diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/tools/external | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/tools/external')
110 files changed, 30618 insertions, 0 deletions
diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationVisitor.java new file mode 100644 index 000000000..835b3e0ca --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationVisitor.java @@ -0,0 +1,88 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A visitor to visit a Java annotation. The methods of this interface must be + * called in the following order: (<tt>visit<tt> | <tt>visitEnum<tt> | + * <tt>visitAnnotation<tt> | <tt>visitArray<tt>)* <tt>visitEnd<tt>. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public interface AnnotationVisitor { + + /** + * Visits a primitive value of the annotation. + * + * @param name the value name. + * @param value the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer}, {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link Type}. + */ + void visit(String name, Object value); + + /** + * Visits an enumeration value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the enumeration class. + * @param value the actual enumeration value. + */ + void visitEnum(String name, String desc, String value); + + /** + * Visits a nested annotation value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the nested annotation class. + * @return a non null visitor to visit the actual nested annotation value. + * <i>The nested annotation value must be fully visited before + * calling other methods on this annotation visitor</i>. + */ + AnnotationVisitor visitAnnotation(String name, String desc); + + /** + * Visits an array value of the annotation. + * + * @param name the value name. + * @return a non null visitor to visit the actual array value elements. The + * 'name' parameters passed to the methods of this visitor are + * ignored. <i>All the array values must be visited before calling + * other methods on this annotation visitor</i>. + */ + AnnotationVisitor visitArray(String name); + + /** + * Visits the end of the annotation. + */ + void visitEnd(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationWriter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationWriter.java new file mode 100644 index 000000000..bf06bc95b --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/AnnotationWriter.java @@ -0,0 +1,311 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An {@link AnnotationVisitor} that generates annotations in bytecode form. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +final class AnnotationWriter implements AnnotationVisitor { + + /** + * The class writer to which this annotation must be added. + */ + private final ClassWriter cw; + + /** + * The number of values in this annotation. + */ + private int size; + + /** + * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation + * writers used for annotation default and annotation arrays use unnamed + * values. + */ + private final boolean named; + + /** + * The annotation values in bytecode form. This byte vector only contains + * the values themselves, i.e. the number of values must be stored as a + * unsigned short just before these bytes. + */ + private final ByteVector bv; + + /** + * The byte vector to be used to store the number of values of this + * annotation. See {@link #bv}. + */ + private final ByteVector parent; + + /** + * Where the number of values of this annotation must be stored in + * {@link #parent}. + */ + private final int offset; + + /** + * Next annotation writer. This field is used to store annotation lists. + */ + AnnotationWriter next; + + /** + * Previous annotation writer. This field is used to store annotation lists. + */ + AnnotationWriter prev; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link AnnotationWriter}. + * + * @param cw the class writer to which this annotation must be added. + * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise. + * @param bv where the annotation values must be stored. + * @param parent where the number of annotation values must be stored. + * @param offset where in <tt>parent</tt> the number of annotation values must + * be stored. + */ + AnnotationWriter( + final ClassWriter cw, + final boolean named, + final ByteVector bv, + final ByteVector parent, + final int offset) + { + this.cw = cw; + this.named = named; + this.bv = bv; + this.parent = parent; + this.offset = offset; + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor interface + // ------------------------------------------------------------------------ + + public void visit(final String name, final Object value) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + if (value instanceof String) { + bv.put12('s', cw.newUTF8((String) value)); + } else if (value instanceof Byte) { + bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); + } else if (value instanceof Boolean) { + int v = ((Boolean) value).booleanValue() ? 1 : 0; + bv.put12('Z', cw.newInteger(v).index); + } else if (value instanceof Character) { + bv.put12('C', cw.newInteger(((Character) value).charValue()).index); + } else if (value instanceof Short) { + bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); + } else if (value instanceof Type) { + bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); + } else if (value instanceof byte[]) { + byte[] v = (byte[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('B', cw.newInteger(v[i]).index); + } + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); + } + } else if (value instanceof short[]) { + short[] v = (short[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('S', cw.newInteger(v[i]).index); + } + } else if (value instanceof char[]) { + char[] v = (char[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('C', cw.newInteger(v[i]).index); + } + } else if (value instanceof int[]) { + int[] v = (int[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('I', cw.newInteger(v[i]).index); + } + } else if (value instanceof long[]) { + long[] v = (long[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('J', cw.newLong(v[i]).index); + } + } else if (value instanceof float[]) { + float[] v = (float[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('F', cw.newFloat(v[i]).index); + } + } else if (value instanceof double[]) { + double[] v = (double[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('D', cw.newDouble(v[i]).index); + } + } else { + Item i = cw.newConstItem(value); + bv.put12(".s.IFJDCS".charAt(i.type), i.index); + } + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag and type, and reserve space for values count + bv.put12('@', cw.newUTF8(desc)).putShort(0); + return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + } + + public AnnotationVisitor visitArray(final String name) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag, and reserve space for array size + bv.put12('[', 0); + return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); + } + + public void visitEnd() { + if (parent != null) { + byte[] data = parent.data; + data[offset] = (byte) (size >>> 8); + data[offset + 1] = (byte) size; + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this annotation writer list. + * + * @return the size of this annotation writer list. + */ + int getSize() { + int size = 0; + AnnotationWriter aw = this; + while (aw != null) { + size += aw.bv.length; + aw = aw.next; + } + return size; + } + + /** + * Puts the annotations of this annotation writer list into the given byte + * vector. + * + * @param out where the annotations must be put. + */ + void put(final ByteVector out) { + int n = 0; + int size = 2; + AnnotationWriter aw = this; + AnnotationWriter last = null; + while (aw != null) { + ++n; + size += aw.bv.length; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putInt(size); + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + + /** + * Puts the given annotation lists into the given byte vector. + * + * @param panns an array of annotation writer lists. + * @param out where the annotations must be put. + */ + static void put(final AnnotationWriter[] panns, final ByteVector out) { + int size = 1 + 2 * panns.length; + for (int i = 0; i < panns.length; ++i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + out.putInt(size).putByte(panns.length); + for (int i = 0; i < panns.length; ++i) { + AnnotationWriter aw = panns[i]; + AnnotationWriter last = null; + int n = 0; + while (aw != null) { + ++n; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Attribute.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Attribute.java new file mode 100644 index 000000000..897a33c79 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Attribute.java @@ -0,0 +1,254 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A non standard class, field, method or code attribute. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class Attribute { + + /** + * The type of this attribute. + */ + public final String type; + + /** + * The raw value of this attribute, used only for unknown attributes. + */ + byte[] value; + + /** + * The next attribute in this attribute list. May be <tt>null</tt>. + */ + Attribute next; + + /** + * Constructs a new empty attribute. + * + * @param type the type of the attribute. + */ + protected Attribute(final String type) { + this.type = type; + } + + /** + * Returns <tt>true</tt> if this type of attribute is unknown. The default + * implementation of this method always returns <tt>true</tt>. + * + * @return <tt>true</tt> if this type of attribute is unknown. + */ + public boolean isUnknown() { + return true; + } + + /** + * Returns <tt>true</tt> if this type of attribute is a code attribute. + * + * @return <tt>true</tt> if this type of attribute is a code attribute. + */ + public boolean isCodeAttribute() { + return false; + } + + /** + * Returns the labels corresponding to this attribute. + * + * @return the labels corresponding to this attribute, or <tt>null</tt> if + * this attribute is not a code attribute that contains labels. + */ + protected Label[] getLabels() { + return null; + } + + /** + * Reads a {@link #type type} attribute. This method must return a <i>new</i> + * {@link Attribute} object, of type {@link #type type}, corresponding to + * the <tt>len</tt> bytes starting at the given offset, in the given class + * reader. + * + * @param cr the class that contains the attribute to be read. + * @param off index of the first byte of the attribute's content in {@link + * ClassReader#b cr.b}. The 6 attribute header bytes, containing the + * type and the length of the attribute, are not taken into account + * here. + * @param len the length of the attribute's content. + * @param buf buffer to be used to call + * {@link ClassReader#readUTF8 readUTF8}, + * {@link ClassReader#readClass(int,char[]) readClass} or + * {@link ClassReader#readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in + * {@link ClassReader#b cr.b}, or -1 if the attribute to be read is + * not a code attribute. The 6 attribute header bytes, containing the + * type and the length of the attribute, are not taken into account + * here. + * @param labels the labels of the method's code, or <tt>null</tt> if the + * attribute to be read is not a code attribute. + * @return a <i>new</i> {@link Attribute} object corresponding to the given + * bytes. + */ + protected Attribute read( + ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + Attribute attr = new Attribute(type); + attr.value = new byte[len]; + System.arraycopy(cr.b, off, attr.value, 0, len); + return attr; + } + + /** + * Returns the byte array form of this attribute. + * + * @param cw the class to which this attribute must be added. This parameter + * can be used to add to the constant pool of this class the items + * that corresponds to this attribute. + * @param code the bytecode of the method corresponding to this code + * attribute, or <tt>null</tt> if this attribute is not a code + * attributes. + * @param len the length of the bytecode of the method corresponding to this + * code attribute, or <tt>null</tt> if this attribute is not a code + * attribute. + * @param maxStack the maximum stack size of the method corresponding to + * this code attribute, or -1 if this attribute is not a code + * attribute. + * @param maxLocals the maximum number of local variables of the method + * corresponding to this code attribute, or -1 if this attribute is + * not a code attribute. + * @return the byte array form of this attribute. + */ + protected ByteVector write( + ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector v = new ByteVector(); + v.data = value; + v.length = value.length; + return v; + } + + /** + * Returns the length of the attribute list that begins with this attribute. + * + * @return the length of the attribute list that begins with this attribute. + */ + final int getCount() { + int count = 0; + Attribute attr = this; + while (attr != null) { + count += 1; + attr = attr.next; + } + return count; + } + + /** + * Returns the size of all the attributes in this attribute list. + * + * @param cw the class writer to be used to convert the attributes into byte + * arrays, with the {@link #write write} method. + * @param code the bytecode of the method corresponding to these code + * attributes, or <tt>null</tt> if these attributes are not code + * attributes. + * @param len the length of the bytecode of the method corresponding to + * these code attributes, or <tt>null</tt> if these attributes are + * not code attributes. + * @param maxStack the maximum stack size of the method corresponding to + * these code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these attributes + * are not code attributes. + * @return the size of all the attributes in this attribute list. This size + * includes the size of the attribute headers. + */ + final int getSize( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals) + { + Attribute attr = this; + int size = 0; + while (attr != null) { + cw.newUTF8(attr.type); + size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; + attr = attr.next; + } + return size; + } + + /** + * Writes all the attributes of this attribute list in the given byte + * vector. + * + * @param cw the class writer to be used to convert the attributes into byte + * arrays, with the {@link #write write} method. + * @param code the bytecode of the method corresponding to these code + * attributes, or <tt>null</tt> if these attributes are not code + * attributes. + * @param len the length of the bytecode of the method corresponding to + * these code attributes, or <tt>null</tt> if these attributes are + * not code attributes. + * @param maxStack the maximum stack size of the method corresponding to + * these code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these attributes + * are not code attributes. + * @param out where the attributes must be written. + */ + final void put( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals, + final ByteVector out) + { + Attribute attr = this; + while (attr != null) { + ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); + out.putShort(cw.newUTF8(attr.type)).putInt(b.length); + out.putByteArray(b.data, 0, b.length); + attr = attr.next; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/ByteVector.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/ByteVector.java new file mode 100644 index 000000000..a1bc32517 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/ByteVector.java @@ -0,0 +1,293 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A dynamically extensible vector of bytes. This class is roughly equivalent to + * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. + * + * @author Eric Bruneton + */ +public class ByteVector { + + /** + * The content of this vector. + */ + byte[] data; + + /** + * Actual number of bytes in this vector. + */ + int length; + + /** + * Constructs a new {@link ByteVector ByteVector} with a default initial + * size. + */ + public ByteVector() { + data = new byte[64]; + } + + /** + * Constructs a new {@link ByteVector ByteVector} with the given initial + * size. + * + * @param initialSize the initial size of the byte vector to be constructed. + */ + public ByteVector(final int initialSize) { + data = new byte[initialSize]; + } + + /** + * Puts a byte into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param b a byte. + * @return this byte vector. + */ + public ByteVector putByte(final int b) { + int length = this.length; + if (length + 1 > data.length) { + enlarge(1); + } + data[length++] = (byte) b; + this.length = length; + return this; + } + + /** + * Puts two bytes into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param b1 a byte. + * @param b2 another byte. + * @return this byte vector. + */ + ByteVector put11(final int b1, final int b2) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) b1; + data[length++] = (byte) b2; + this.length = length; + return this; + } + + /** + * Puts a short into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param s a short. + * @return this byte vector. + */ + public ByteVector putShort(final int s) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts a byte and a short into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param b a byte. + * @param s a short. + * @return this byte vector. + */ + ByteVector put12(final int b, final int s) { + int length = this.length; + if (length + 3 > data.length) { + enlarge(3); + } + byte[] data = this.data; + data[length++] = (byte) b; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts an int into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param i an int. + * @return this byte vector. + */ + public ByteVector putInt(final int i) { + int length = this.length; + if (length + 4 > data.length) { + enlarge(4); + } + byte[] data = this.data; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts a long into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param l a long. + * @return this byte vector. + */ + public ByteVector putLong(final long l) { + int length = this.length; + if (length + 8 > data.length) { + enlarge(8); + } + byte[] data = this.data; + int i = (int) (l >>> 32); + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + i = (int) l; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param s a String. + * @return this byte vector. + */ + public ByteVector putUTF8(final String s) { + int charLength = s.length(); + if (length + 2 + charLength > data.length) { + enlarge(2 + charLength); + } + int len = length; + byte[] data = this.data; + // optimistic algorithm: instead of computing the byte length and then + // serializing the string (which requires two loops), we assume the byte + // length is equal to char length (which is the most frequent case), and + // we start serializing the string right away. During the serialization, + // if we find that this assumption is wrong, we continue with the + // general method. + data[len++] = (byte) (charLength >>> 8); + data[len++] = (byte) (charLength); + for (int i = 0; i < charLength; ++i) { + char c = s.charAt(i); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else { + int byteLength = i; + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + byteLength++; + } else if (c > '\u07FF') { + byteLength += 3; + } else { + byteLength += 2; + } + } + data[length] = (byte) (byteLength >>> 8); + data[length + 1] = (byte) (byteLength); + if (length + 2 + byteLength > data.length) { + length = len; + enlarge(2 + byteLength); + data = this.data; + } + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else if (c > '\u07FF') { + data[len++] = (byte) (0xE0 | c >> 12 & 0xF); + data[len++] = (byte) (0x80 | c >> 6 & 0x3F); + data[len++] = (byte) (0x80 | c & 0x3F); + } else { + data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); + data[len++] = (byte) (0x80 | c & 0x3F); + } + } + break; + } + } + length = len; + return this; + } + + /** + * Puts an array of bytes into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> + * null bytes into this byte vector. + * @param off index of the fist byte of b that must be copied. + * @param len number of bytes of b that must be copied. + * @return this byte vector. + */ + public ByteVector putByteArray(final byte[] b, final int off, final int len) + { + if (length + len > data.length) { + enlarge(len); + } + if (b != null) { + System.arraycopy(b, off, data, length, len); + } + length += len; + return this; + } + + /** + * Enlarge this byte vector so that it can receive n more bytes. + * + * @param size number of additional bytes that this byte vector should be + * able to receive. + */ + private void enlarge(final int size) { + int length1 = 2 * data.length; + int length2 = length + size; + byte[] newData = new byte[length1 > length2 ? length1 : length2]; + System.arraycopy(data, 0, newData, 0, length); + data = newData; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassAdapter.java new file mode 100644 index 000000000..24e34bb99 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassAdapter.java @@ -0,0 +1,121 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An empty {@link ClassVisitor} that delegates to another {@link ClassVisitor}. + * This class can be used as a super class to quickly implement usefull class + * adapter classes, just by overriding the necessary methods. + * + * @author Eric Bruneton + */ +public class ClassAdapter implements ClassVisitor { + + /** + * The {@link ClassVisitor} to which this adapter delegates calls. + */ + protected ClassVisitor cv; + + /** + * Constructs a new {@link ClassAdapter} object. + * + * @param cv the class visitor to which this adapter must delegate calls. + */ + public ClassAdapter(final ClassVisitor cv) { + this.cv = cv; + } + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + cv.visit(version, access, name, signature, superName, interfaces); + } + + public void visitSource(final String source, final String debug) { + cv.visitSource(source, debug); + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + cv.visitOuterClass(owner, name, desc); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + return cv.visitAnnotation(desc, visible); + } + + public void visitAttribute(final Attribute attr) { + cv.visitAttribute(attr); + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + cv.visitInnerClass(name, outerName, innerName, access); + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + return cv.visitField(access, name, desc, signature, value); + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + return cv.visitMethod(access, name, desc, signature, exceptions); + } + + public void visitEnd() { + cv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassReader.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassReader.java new file mode 100644 index 000000000..9d94a42d4 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassReader.java @@ -0,0 +1,1606 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +import java.io.InputStream; +import java.io.IOException; + +/** + * A Java class parser to make a {@link ClassVisitor} visit an existing class. + * This class parses a byte array conforming to the Java class file format and + * calls the appropriate visit methods of a given class visitor for each field, + * method and bytecode instruction encountered. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ClassReader { + + /** + * The class to be parsed. <i>The content of this array must not be + * modified. This field is intended for {@link Attribute} sub classes, and + * is normally not needed by class generators or adapters.</i> + */ + public final byte[] b; + + /** + * The start index of each constant pool item in {@link #b b}, plus one. + * The one byte offset skips the constant pool item tag that indicates its + * type. + */ + private int[] items; + + /** + * The String objects corresponding to the CONSTANT_Utf8 items. This cache + * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, + * which GREATLY improves performances (by a factor 2 to 3). This caching + * strategy could be extended to all constant pool items, but its benefit + * would not be so great for these items (because they are much less + * expensive to parse than CONSTANT_Utf8 items). + */ + private String[] strings; + + /** + * Maximum length of the strings contained in the constant pool of the + * class. + */ + private int maxStringLength; + + /** + * Start index of the class header information (access, name...) in + * {@link #b b}. + */ + public final int header; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + */ + public ClassReader(final byte[] b) { + this(b, 0, b.length); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + * @param off the start offset of the class data. + * @param len the length of the class data. + */ + public ClassReader(final byte[] b, final int off, final int len) { + this.b = b; + // parses the constant pool + items = new int[readUnsignedShort(off + 8)]; + int ll = items.length; + strings = new String[ll]; + int max = 0; + int index = off + 10; + for (int i = 1; i < ll; ++i) { + items[i] = index + 1; + int tag = b[index]; + int size; + switch (tag) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + case ClassWriter.INT: + case ClassWriter.FLOAT: + case ClassWriter.NAME_TYPE: + size = 5; + break; + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + size = 9; + ++i; + break; + case ClassWriter.UTF8: + size = 3 + readUnsignedShort(index + 1); + if (size > max) { + max = size; + } + break; + // case ClassWriter.CLASS: + // case ClassWriter.STR: + default: + size = 3; + break; + } + index += size; + } + maxStringLength = max; + // the class header information starts just after the constant pool + header = index; + } + + /** + * Copies the constant pool data into the given {@link ClassWriter}. Should + * be called before the {@link #accept(ClassVisitor,boolean)} method. + * + * @param classWriter the {@link ClassWriter} to copy constant pool into. + */ + void copyPool(final ClassWriter classWriter) { + char[] buf = new char[maxStringLength]; + int ll = items.length; + Item[] items2 = new Item[ll]; + for (int i = 1; i < ll; i++) { + int index = items[i]; + int tag = b[index - 1]; + Item item = new Item(i); + int nameType; + switch (tag) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + nameType = items[readUnsignedShort(index + 2)]; + item.set(tag, + readClass(index, buf), + readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + + case ClassWriter.INT: + item.set(readInt(index)); + break; + + case ClassWriter.FLOAT: + item.set(Float.intBitsToFloat(readInt(index))); + break; + + case ClassWriter.NAME_TYPE: + item.set(tag, + readUTF8(index, buf), + readUTF8(index + 2, buf), + null); + break; + + case ClassWriter.LONG: + item.set(readLong(index)); + ++i; + break; + + case ClassWriter.DOUBLE: + item.set(Double.longBitsToDouble(readLong(index))); + ++i; + break; + + case ClassWriter.UTF8: { + String s = strings[i]; + if (s == null) { + index = items[i]; + s = strings[i] = readUTF(index + 2, + readUnsignedShort(index), + buf); + } + item.set(tag, s, null, null); + } + break; + + // case ClassWriter.STR: + // case ClassWriter.CLASS: + default: + item.set(tag, readUTF8(index, buf), null, null); + break; + } + + int index2 = item.hashCode % items2.length; + item.next = items2[index2]; + items2[index2] = item; + } + + int off = items[1] - 1; + classWriter.pool.putByteArray(b, off, header - off); + classWriter.items = items2; + classWriter.threshold = (int) (0.75d * ll); + classWriter.index = ll; + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param is an input stream from which to read the class. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream is) throws IOException { + this(readClass(is)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param name the fully qualified name of the class to be read. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String name) throws IOException { + this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + + ".class")); + } + + /** + * Reads the bytecode of a class. + * + * @param is an input stream from which to read the class. + * @return the bytecode read from the given input stream. + * @throws IOException if a problem occurs during reading. + */ + private static byte[] readClass(final InputStream is) throws IOException { + if (is == null) { + throw new IOException("Class not found"); + } + byte[] b = new byte[is.available()]; + int len = 0; + while (true) { + int n = is.read(b, len, b.length - len); + if (n == -1) { + if (len < b.length) { + byte[] c = new byte[len]; + System.arraycopy(b, 0, c, 0, len); + b = c; + } + return b; + } + len += n; + if (len == b.length) { + byte[] c = new byte[b.length + 1000]; + System.arraycopy(b, 0, c, 0, len); + b = c; + } + } + } + + // ------------------------------------------------------------------------ + // Public methods + // ------------------------------------------------------------------------ + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. + * This class is the one specified in the constructor (see + * {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param skipDebug <tt>true</tt> if the debug information of the class + * must not be visited. In this case the + * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and + * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will + * not be called. + */ + public void accept(final ClassVisitor classVisitor, final boolean skipDebug) + { + accept(classVisitor, new Attribute[0], skipDebug); + } + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. + * This class is the one specified in the constructor (see + * {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param attrs prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to the + * type of one the prototypes will be ignored. + * @param skipDebug <tt>true</tt> if the debug information of the class + * must not be visited. In this case the + * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and + * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will + * not be called. + */ + public void accept( + final ClassVisitor classVisitor, + final Attribute[] attrs, + final boolean skipDebug) + { + byte[] b = this.b; // the bytecode array + char[] c = new char[maxStringLength]; // buffer used to read strings + int i, j, k; // loop variables + int u, v, w; // indexes in b + Attribute attr; + + int access; + String name; + String desc; + String attrName; + String signature; + int anns = 0; + int ianns = 0; + Attribute cattrs = null; + + // visits the header + u = header; + access = readUnsignedShort(u); + name = readClass(u + 2, c); + v = items[readUnsignedShort(u + 4)]; + String superClassName = v == 0 ? null : readUTF8(v, c); + String[] implementedItfs = new String[readUnsignedShort(u + 6)]; + w = 0; + u += 8; + for (i = 0; i < implementedItfs.length; ++i) { + implementedItfs[i] = readClass(u, c); + u += 2; + } + + // skips fields and methods + v = u; + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + // reads the class's attributes + signature = null; + String sourceFile = null; + String sourceDebug = null; + String enclosingOwner = null; + String enclosingName = null; + String enclosingDesc = null; + + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + attrName = readUTF8(v, c); + if (attrName.equals("SourceFile")) { + sourceFile = readUTF8(v + 6, c); + } else if (attrName.equals("Deprecated")) { + access |= Opcodes.ACC_DEPRECATED; + } else if (attrName.equals("Synthetic")) { + access |= Opcodes.ACC_SYNTHETIC; + } else if (attrName.equals("Annotation")) { + access |= Opcodes.ACC_ANNOTATION; + } else if (attrName.equals("Enum")) { + access |= Opcodes.ACC_ENUM; + } else if (attrName.equals("InnerClasses")) { + w = v + 6; + } else if (attrName.equals("Signature")) { + signature = readUTF8(v + 6, c); + } else if (attrName.equals("SourceDebugExtension")) { + int len = readInt(v + 2); + sourceDebug = readUTF(v + 6, len, new char[len]); + } else if (attrName.equals("EnclosingMethod")) { + enclosingOwner = readClass(v + 6, c); + int item = readUnsignedShort(v + 8); + if (item != 0) { + enclosingName = readUTF8(items[item], c); + enclosingDesc = readUTF8(items[item] + 2, c); + } + } else if (attrName.equals("RuntimeVisibleAnnotations")) { + anns = v + 6; + } else if (attrName.equals("RuntimeInvisibleAnnotations")) { + ianns = v + 6; + } else { + attr = readAttribute(attrs, + attrName, + v + 6, + readInt(v + 2), + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + v += 6 + readInt(v + 2); + } + // calls the visit method + classVisitor.visit(readInt(4), + access, + name, + signature, + superClassName, + implementedItfs); + + // calls the visitSource method + if (sourceFile != null || sourceDebug != null) { + classVisitor.visitSource(sourceFile, sourceDebug); + } + + // calls the visitOuterClass method + if (enclosingOwner != null) { + classVisitor.visitOuterClass(enclosingOwner, + enclosingName, + enclosingDesc); + } + + // visits the class annotations + for (i = 1; i >= 0; --i) { + v = i == 0 ? ianns : anns; + if (v != 0) { + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + desc = readUTF8(v, c); + v += 2; + v = readAnnotationValues(v, + c, + classVisitor.visitAnnotation(desc, i != 0)); + } + } + } + + // visits the class attributes + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + classVisitor.visitAttribute(cattrs); + cattrs = attr; + } + + // class the visitInnerClass method + if (w != 0) { + i = readUnsignedShort(w); + w += 2; + for (; i > 0; --i) { + classVisitor.visitInnerClass(readUnsignedShort(w) == 0 + ? null + : readClass(w, c), readUnsignedShort(w + 2) == 0 + ? null + : readClass(w + 2, c), readUnsignedShort(w + 4) == 0 + ? null + : readUTF8(w + 4, c), readUnsignedShort(w + 6)); + w += 8; + } + } + + // visits the fields + i = readUnsignedShort(u); + u += 2; + for (; i > 0; --i) { + access = readUnsignedShort(u); + name = readUTF8(u + 2, c); + desc = readUTF8(u + 4, c); + // visits the field's attributes and looks for a ConstantValue + // attribute + int fieldValueItem = 0; + signature = null; + anns = 0; + ianns = 0; + cattrs = null; + + j = readUnsignedShort(u + 6); + u += 8; + for (; j > 0; --j) { + attrName = readUTF8(u, c); + if (attrName.equals("ConstantValue")) { + fieldValueItem = readUnsignedShort(u + 6); + } else if (attrName.equals("Synthetic")) { + access |= Opcodes.ACC_SYNTHETIC; + } else if (attrName.equals("Deprecated")) { + access |= Opcodes.ACC_DEPRECATED; + } else if (attrName.equals("Enum")) { + access |= Opcodes.ACC_ENUM; + } else if (attrName.equals("Signature")) { + signature = readUTF8(u + 6, c); + } else if (attrName.equals("RuntimeVisibleAnnotations")) { + anns = u + 6; + } else if (attrName.equals("RuntimeInvisibleAnnotations")) { + ianns = u + 6; + } else { + attr = readAttribute(attrs, + attrName, + u + 6, + readInt(u + 2), + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + u += 6 + readInt(u + 2); + } + // reads the field's value, if any + Object value = (fieldValueItem == 0 + ? null + : readConst(fieldValueItem, c)); + // visits the field + FieldVisitor fv = classVisitor.visitField(access, + name, + desc, + signature, + value); + // visits the field annotations and attributes + if (fv != null) { + for (j = 1; j >= 0; --j) { + v = j == 0 ? ianns : anns; + if (v != 0) { + k = readUnsignedShort(v); + v += 2; + for (; k > 0; --k) { + desc = readUTF8(v, c); + v += 2; + v = readAnnotationValues(v, + c, + fv.visitAnnotation(desc, j != 0)); + } + } + } + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + fv.visitAttribute(cattrs); + cattrs = attr; + } + fv.visitEnd(); + } + } + + // visits the methods + i = readUnsignedShort(u); + u += 2; + for (; i > 0; --i) { + int u0 = u + 6; + access = readUnsignedShort(u); + name = readUTF8(u + 2, c); + desc = readUTF8(u + 4, c); + signature = null; + anns = 0; + ianns = 0; + int dann = 0; + int mpanns = 0; + int impanns = 0; + cattrs = null; + v = 0; + w = 0; + + // looks for Code and Exceptions attributes + j = readUnsignedShort(u + 6); + u += 8; + for (; j > 0; --j) { + attrName = readUTF8(u, c); + u += 2; + int attrSize = readInt(u); + u += 4; + if (attrName.equals("Code")) { + v = u; + } else if (attrName.equals("Exceptions")) { + w = u; + } else if (attrName.equals("Synthetic")) { + access |= Opcodes.ACC_SYNTHETIC; + } else if (attrName.equals("Varargs")) { + access |= Opcodes.ACC_VARARGS; + } else if (attrName.equals("Bridge")) { + access |= Opcodes.ACC_BRIDGE; + } else if (attrName.equals("Deprecated")) { + access |= Opcodes.ACC_DEPRECATED; + } else if (attrName.equals("Signature")) { + signature = readUTF8(u, c); + } else if (attrName.equals("AnnotationDefault")) { + dann = u; + } else if (attrName.equals("RuntimeVisibleAnnotations")) { + anns = u; + } else if (attrName.equals("RuntimeInvisibleAnnotations")) { + ianns = u; + } else if (attrName.equals("RuntimeVisibleParameterAnnotations")) + { + mpanns = u; + } else if (attrName.equals("RuntimeInvisibleParameterAnnotations")) + { + impanns = u; + } else { + attr = readAttribute(attrs, + attrName, + u, + attrSize, + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + u += attrSize; + } + // reads declared exceptions + String[] exceptions; + if (w == 0) { + exceptions = null; + } else { + exceptions = new String[readUnsignedShort(w)]; + w += 2; + for (j = 0; j < exceptions.length; ++j) { + exceptions[j] = readClass(w, c); + w += 2; + } + } + + // visits the method's code, if any + MethodVisitor mv = classVisitor.visitMethod(access, + name, + desc, + signature, + exceptions); + + if (mv != null) { + /* + * if the returned MethodVisitor is in fact a MethodWriter, it + * means there is no method adapter between the reader and the + * writer. If, in addition, the writer's constant pool was + * copied from this reader (mw.cw.cr == this), and the signature + * and exceptions of the method have not been changed, then it + * is possible to skip all visit events and just copy the + * original code of the method to the writer (the access, name + * and descriptor can have been changed, this is not important + * since they are not copied as is from the reader). + */ + if (mv instanceof MethodWriter) { + MethodWriter mw = (MethodWriter) mv; + if (mw.cw.cr == this) { + if (signature == mw.signature) { + boolean sameExceptions = false; + if (exceptions == null) { + sameExceptions = mw.exceptionCount == 0; + } else { + if (exceptions.length == mw.exceptionCount) { + sameExceptions = true; + for (j = exceptions.length - 1; j >= 0; --j) + { + w -= 2; + if (mw.exceptions[j] != readUnsignedShort(w)) + { + sameExceptions = false; + break; + } + } + } + } + if (sameExceptions) { + /* + * we do not copy directly the code into + * MethodWriter to save a byte array copy + * operation. The real copy will be done in + * ClassWriter.toByteArray(). + */ + mw.classReaderOffset = u0; + mw.classReaderLength = u - u0; + continue; + } + } + } + } + if (dann != 0) { + AnnotationVisitor dv = mv.visitAnnotationDefault(); + readAnnotationValue(dann, c, null, dv); + dv.visitEnd(); + } + for (j = 1; j >= 0; --j) { + w = j == 0 ? ianns : anns; + if (w != 0) { + k = readUnsignedShort(w); + w += 2; + for (; k > 0; --k) { + desc = readUTF8(w, c); + w += 2; + w = readAnnotationValues(w, + c, + mv.visitAnnotation(desc, j != 0)); + } + } + } + if (mpanns != 0) { + readParameterAnnotations(mpanns, c, true, mv); + } + if (impanns != 0) { + readParameterAnnotations(impanns, c, false, mv); + } + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + mv.visitAttribute(cattrs); + cattrs = attr; + } + } + + if (mv != null && v != 0) { + int maxStack = readUnsignedShort(v); + int maxLocals = readUnsignedShort(v + 2); + int codeLength = readInt(v + 4); + v += 8; + + int codeStart = v; + int codeEnd = v + codeLength; + + mv.visitCode(); + + // 1st phase: finds the labels + int label; + Label[] labels = new Label[codeLength + 1]; + while (v < codeEnd) { + int opcode = b[v] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + v += 1; + break; + case ClassWriter.LABEL_INSN: + label = v - codeStart + readShort(v + 1); + if (labels[label] == null) { + labels[label] = new Label(); + } + v += 3; + break; + case ClassWriter.LABELW_INSN: + label = v - codeStart + readInt(v + 1); + if (labels[label] == null) { + labels[label] = new Label(); + } + v += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[v + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + v += 6; + } else { + v += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + w = v - codeStart; + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + v += 4; + if (labels[label] == null) { + labels[label] = new Label(); + } + j = readInt(v); + v += 4; + j = readInt(v) - j + 1; + v += 4; + for (; j > 0; --j) { + label = w + readInt(v); + v += 4; + if (labels[label] == null) { + labels[label] = new Label(); + } + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + w = v - codeStart; + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + v += 4; + if (labels[label] == null) { + labels[label] = new Label(); + } + j = readInt(v); + v += 4; + for (; j > 0; --j) { + v += 4; // skips key + label = w + readInt(v); + v += 4; + if (labels[label] == null) { + labels[label] = new Label(); + } + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + v += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + v += 3; + break; + case ClassWriter.ITFMETH_INSN: + v += 5; + break; + // case MANA_INSN: + default: + v += 4; + break; + } + } + // parses the try catch entries + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + label = readUnsignedShort(v); + Label start = labels[label]; + if (start == null) { + labels[label] = start = new Label(); + } + label = readUnsignedShort(v + 2); + Label end = labels[label]; + if (end == null) { + labels[label] = end = new Label(); + } + label = readUnsignedShort(v + 4); + Label handler = labels[label]; + if (handler == null) { + labels[label] = handler = new Label(); + } + + int type = readUnsignedShort(v + 6); + if (type == 0) { + mv.visitTryCatchBlock(start, end, handler, null); + } else { + mv.visitTryCatchBlock(start, + end, + handler, + readUTF8(items[type], c)); + } + v += 8; + } + // parses the local variable, line number tables, and code + // attributes + int varTable = 0; + int varTypeTable = 0; + cattrs = null; + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + attrName = readUTF8(v, c); + if (attrName.equals("LocalVariableTable")) { + if (!skipDebug) { + varTable = v + 6; + k = readUnsignedShort(v + 6); + w = v + 8; + for (; k > 0; --k) { + label = readUnsignedShort(w); + if (labels[label] == null) { + labels[label] = new Label(); + } + label += readUnsignedShort(w + 2); + if (labels[label] == null) { + labels[label] = new Label(); + } + w += 10; + } + } + } else if (attrName.equals("LocalVariableTypeTable")) { + varTypeTable = v + 6; + } else if (attrName.equals("LineNumberTable")) { + if (!skipDebug) { + k = readUnsignedShort(v + 6); + w = v + 8; + for (; k > 0; --k) { + label = readUnsignedShort(w); + if (labels[label] == null) { + labels[label] = new Label(); + } + labels[label].line = readUnsignedShort(w + 2); + w += 4; + } + } + } else { + for (k = 0; k < attrs.length; ++k) { + if (attrs[k].type.equals(attrName)) { + attr = attrs[k].read(this, + v + 6, + readInt(v + 2), + c, + codeStart - 8, + labels); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + } + } + v += 6 + readInt(v + 2); + } + + // 2nd phase: visits each instruction + v = codeStart; + Label l; + while (v < codeEnd) { + w = v - codeStart; + l = labels[w]; + if (l != null) { + mv.visitLabel(l); + if (!skipDebug && l.line > 0) { + mv.visitLineNumber(l.line, l); + } + } + int opcode = b[v] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + mv.visitInsn(opcode); + v += 1; + break; + case ClassWriter.IMPLVAR_INSN: + if (opcode > Opcodes.ISTORE) { + opcode -= 59; // ISTORE_0 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), + opcode & 0x3); + } else { + opcode -= 26; // ILOAD_0 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), + opcode & 0x3); + } + v += 1; + break; + case ClassWriter.LABEL_INSN: + mv.visitJumpInsn(opcode, labels[w + + readShort(v + 1)]); + v += 3; + break; + case ClassWriter.LABELW_INSN: + mv.visitJumpInsn(opcode - 33, labels[w + + readInt(v + 1)]); + v += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[v + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + mv.visitIincInsn(readUnsignedShort(v + 2), + readShort(v + 4)); + v += 6; + } else { + mv.visitVarInsn(opcode, + readUnsignedShort(v + 2)); + v += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + v += 4; + int min = readInt(v); + v += 4; + int max = readInt(v); + v += 4; + Label[] table = new Label[max - min + 1]; + for (j = 0; j < table.length; ++j) { + table[j] = labels[w + readInt(v)]; + v += 4; + } + mv.visitTableSwitchInsn(min, + max, + labels[label], + table); + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + v += 4; + j = readInt(v); + v += 4; + int[] keys = new int[j]; + Label[] values = new Label[j]; + for (j = 0; j < keys.length; ++j) { + keys[j] = readInt(v); + v += 4; + values[j] = labels[w + readInt(v)]; + v += 4; + } + mv.visitLookupSwitchInsn(labels[label], + keys, + values); + break; + case ClassWriter.VAR_INSN: + mv.visitVarInsn(opcode, b[v + 1] & 0xFF); + v += 2; + break; + case ClassWriter.SBYTE_INSN: + mv.visitIntInsn(opcode, b[v + 1]); + v += 2; + break; + case ClassWriter.SHORT_INSN: + mv.visitIntInsn(opcode, readShort(v + 1)); + v += 3; + break; + case ClassWriter.LDC_INSN: + mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c)); + v += 2; + break; + case ClassWriter.LDCW_INSN: + mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), + c)); + v += 3; + break; + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.ITFMETH_INSN: + int cpIndex = items[readUnsignedShort(v + 1)]; + String iowner = readClass(cpIndex, c); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + if (opcode < Opcodes.INVOKEVIRTUAL) { + mv.visitFieldInsn(opcode, iowner, iname, idesc); + } else { + mv.visitMethodInsn(opcode, iowner, iname, idesc); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + v += 5; + } else { + v += 3; + } + break; + case ClassWriter.TYPE_INSN: + mv.visitTypeInsn(opcode, readClass(v + 1, c)); + v += 3; + break; + case ClassWriter.IINC_INSN: + mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]); + v += 3; + break; + // case MANA_INSN: + default: + mv.visitMultiANewArrayInsn(readClass(v + 1, c), + b[v + 3] & 0xFF); + v += 4; + break; + } + } + l = labels[codeEnd - codeStart]; + if (l != null) { + mv.visitLabel(l); + } + + // visits the local variable tables + if (!skipDebug && varTable != 0) { + int[] typeTable = null; + if (varTypeTable != 0) { + w = varTypeTable; + k = readUnsignedShort(w) * 3; + w += 2; + typeTable = new int[k]; + while (k > 0) { + typeTable[--k] = w + 6; // signature + typeTable[--k] = readUnsignedShort(w + 8); // index + typeTable[--k] = readUnsignedShort(w); // start + w += 10; + } + } + w = varTable; + k = readUnsignedShort(w); + w += 2; + for (; k > 0; --k) { + int start = readUnsignedShort(w); + int length = readUnsignedShort(w + 2); + int index = readUnsignedShort(w + 8); + String vsignature = null; + if (typeTable != null) { + for (int a = 0; a < typeTable.length; a += 3) { + if (typeTable[a] == start + && typeTable[a + 1] == index) + { + vsignature = readUTF8(typeTable[a + 2], c); + break; + } + } + } + mv.visitLocalVariable(readUTF8(w + 4, c), + readUTF8(w + 6, c), + vsignature, + labels[start], + labels[start + length], + index); + w += 10; + } + } + // visits the other attributes + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + mv.visitAttribute(cattrs); + cattrs = attr; + } + // visits the max stack and max locals values + mv.visitMaxs(maxStack, maxLocals); + } + + if (mv != null) { + mv.visitEnd(); + } + } + + // visits the end of the class + classVisitor.visitEnd(); + } + + /** + * Reads parameter annotations and makes the given visitor visit them. + * + * @param v start offset in {@link #b b} of the annotations to be read. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param visible <tt>true</tt> if the annotations to be read are visible + * at runtime. + * @param mv the visitor that must visit the annotations. + */ + private void readParameterAnnotations( + int v, + final char[] buf, + final boolean visible, + final MethodVisitor mv) + { + int n = b[v++] & 0xFF; + for (int i = 0; i < n; ++i) { + int j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + String desc = readUTF8(v, buf); + v += 2; + AnnotationVisitor av = mv.visitParameterAnnotation(i, + desc, + visible); + v = readAnnotationValues(v, buf, av); + } + } + } + + /** + * Reads the values of an annotation and makes the given visitor visit them. + * + * @param v the start offset in {@link #b b} of the values to be read + * (including the unsigned short that gives the number of values). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param av the visitor that must visit the values. + * @return the end offset of the annotations values. + */ + private int readAnnotationValues( + int v, + final char[] buf, + final AnnotationVisitor av) + { + int i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + String name = readUTF8(v, buf); + v += 2; + v = readAnnotationValue(v, buf, name, av); + } + av.visitEnd(); + return v; + } + + /** + * Reads a value of an annotation and makes the given visitor visit it. + * + * @param v the start offset in {@link #b b} of the value to be read (<i>not + * including the value name constant pool index</i>). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param name the name of the value to be read. + * @param av the visitor that must visit the value. + * @return the end offset of the annotation value. + */ + private int readAnnotationValue( + int v, + final char[] buf, + final String name, + final AnnotationVisitor av) + { + int i; + switch (readByte(v++)) { + case 'I': // pointer to CONSTANT_Integer + case 'J': // pointer to CONSTANT_Long + case 'F': // pointer to CONSTANT_Float + case 'D': // pointer to CONSTANT_Double + av.visit(name, readConst(readUnsignedShort(v), buf)); + v += 2; + break; + case 'B': // pointer to CONSTANT_Byte + av.visit(name, + new Byte((byte) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'Z': // pointer to CONSTANT_Boolean + boolean b = readInt(items[readUnsignedShort(v)]) == 0; + av.visit(name, b ? Boolean.FALSE : Boolean.TRUE); + v += 2; + break; + case 'S': // pointer to CONSTANT_Short + av.visit(name, + new Short((short) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'C': // pointer to CONSTANT_Char + av.visit(name, + new Character((char) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 's': // pointer to CONSTANT_Utf8 + av.visit(name, readUTF8(v, buf)); + v += 2; + break; + case 'e': // enum_const_value + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); + v += 4; + break; + case 'c': // class_info + av.visit(name, Type.getType(readUTF8(v, buf))); + v += 2; + break; + case '@': // annotation_value + String desc = readUTF8(v, buf); + v += 2; + v = readAnnotationValues(v, buf, av.visitAnnotation(name, desc)); + break; + case '[': // array_value + int size = readUnsignedShort(v); + v += 2; + if (size == 0) { + av.visitArray(name).visitEnd(); + return v; + } + switch (readByte(v++)) { + case 'B': + byte[] bv = new byte[size]; + for (i = 0; i < size; i++) { + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, bv); + --v; + break; + case 'Z': + boolean[] zv = new boolean[size]; + for (i = 0; i < size; i++) { + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; + v += 3; + } + av.visit(name, zv); + --v; + break; + case 'S': + short[] sv = new short[size]; + for (i = 0; i < size; i++) { + sv[i] = (short) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, sv); + --v; + break; + case 'C': + char[] cv = new char[size]; + for (i = 0; i < size; i++) { + cv[i] = (char) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, cv); + --v; + break; + case 'I': + int[] iv = new int[size]; + for (i = 0; i < size; i++) { + iv[i] = readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, iv); + --v; + break; + case 'J': + long[] lv = new long[size]; + for (i = 0; i < size; i++) { + lv[i] = readLong(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, lv); + --v; + break; + case 'F': + float[] fv = new float[size]; + for (i = 0; i < size; i++) { + fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, fv); + --v; + break; + case 'D': + double[] dv = new double[size]; + for (i = 0; i < size; i++) { + dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, dv); + --v; + break; + default: + v--; + AnnotationVisitor aav = av.visitArray(name); + for (i = size; i > 0; --i) { + v = readAnnotationValue(v, buf, null, aav); + } + aav.visitEnd(); + } + } + return v; + } + + /** + * Reads an attribute in {@link #b b}. + * + * @param attrs prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to the + * type of one the prototypes is ignored (i.e. an empty + * {@link Attribute} instance is returned). + * @param type the type of the attribute. + * @param off index of the first byte of the attribute's content in + * {@link #b b}. The 6 attribute header bytes, containing the type + * and the length of the attribute, are not taken into account here + * (they have already been read). + * @param len the length of the attribute's content. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in + * {@link #b b}, or -1 if the attribute to be read is not a code + * attribute. The 6 attribute header bytes, containing the type and + * the length of the attribute, are not taken into account here. + * @param labels the labels of the method's code, or <tt>null</tt> if the + * attribute to be read is not a code attribute. + * @return the attribute that has been read, or <tt>null</tt> to skip this + * attribute. + */ + private Attribute readAttribute( + final Attribute[] attrs, + final String type, + final int off, + final int len, + final char[] buf, + final int codeOff, + final Label[] labels) + { + for (int i = 0; i < attrs.length; ++i) { + if (attrs[i].type.equals(type)) { + return attrs[i].read(this, off, len, buf, codeOff, labels); + } + } + return new Attribute(type).read(this, off, len, null, -1, null); + } + + // ------------------------------------------------------------------------ + // Utility methods: low level parsing + // ------------------------------------------------------------------------ + + /** + * Returns the start index of the constant pool item in {@link #b b}, plus + * one. <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param item the index a constant pool item. + * @return the start index of the constant pool item in {@link #b b}, plus + * one. + */ + public int getItem(final int item) { + return items[item]; + } + + /** + * Reads a byte value in {@link #b b}. <i>This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readByte(final int index) { + return b[index] & 0xFF; + } + + /** + * Reads an unsigned short value in {@link #b b}. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readUnsignedShort(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in {@link #b b}. <i>This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public short readShort(final int index) { + byte[] b = this.b; + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in {@link #b b}. <i>This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readInt(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); + } + + /** + * Reads a signed long value in {@link #b b}. <i>This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public long readLong(final int index) { + long l1 = readInt(index); + long l0 = readInt(index + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method + * is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters.</i> + * + * @param index the start index of an unsigned short value in {@link #b b}, + * whose value is the index of an UTF8 constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 item. + */ + public String readUTF8(int index, final char[] buf) { + int item = readUnsignedShort(index); + String s = strings[item]; + if (s != null) { + return s; + } + index = items[item]; + return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); + } + + /** + * Reads UTF8 string in {@link #b b}. + * + * @param index start offset of the UTF8 string to be read. + * @param utfLen length of the UTF8 string to be read. + * @param buf buffer to be used to read the string. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUTF(int index, int utfLen, char[] buf) { + int endIndex = index + utfLen; + byte[] b = this.b; + int strLen = 0; + int c, d, e; + while (index < endIndex) { + c = b[index++] & 0xFF; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxxxxxx + buf[strLen++] = (char) c; + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + d = b[index++]; + buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F)); + break; + default: + // 1110 xxxx 10xx xxxx 10xx xxxx + d = b[index++]; + e = b[index++]; + buf[strLen++] = (char) (((c & 0x0F) << 12) + | ((d & 0x3F) << 6) | (e & 0x3F)); + break; + } + } + return new String(buf, 0, strLen); + } + + /** + * Reads a class constant pool item in {@link #b b}. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> + * + * @param index the start index of an unsigned short value in {@link #b b}, + * whose value is the index of a class constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified class item. + */ + public String readClass(final int index, final char[] buf) { + // computes the start index of the CONSTANT_Class item in b + // and reads the CONSTANT_Utf8 item designated by + // the first two bytes of this CONSTANT_Class item + return readUTF8(items[readUnsignedShort(index)], buf); + } + + /** + * Reads a numeric or string constant pool item in {@link #b b}. <i>This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters.</i> + * + * @param item the index of a constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String} or {@link Type} corresponding to + * the given constant pool item. + */ + public Object readConst(final int item, final char[] buf) { + int index = items[item]; + switch (b[index - 1]) { + case ClassWriter.INT: + return new Integer(readInt(index)); + case ClassWriter.FLOAT: + return new Float(Float.intBitsToFloat(readInt(index))); + case ClassWriter.LONG: + return new Long(readLong(index)); + case ClassWriter.DOUBLE: + return new Double(Double.longBitsToDouble(readLong(index))); + case ClassWriter.CLASS: + String s = readUTF8(index, buf); + return Type.getType(s.charAt(0) == '[' ? s : "L" + s + ";"); + // case ClassWriter.STR: + default: + return readUTF8(index, buf); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassVisitor.java new file mode 100644 index 000000000..edeb58765 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassVisitor.java @@ -0,0 +1,195 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A visitor to visit a Java class. The methods of this interface must be called + * in the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ + * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | + * <tt>visitAttribute</tt> )* (<tt>visitInnerClass</tt> | + * <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>. + * + * @author Eric Bruneton + */ +public interface ClassVisitor { + + /** + * Visits the header of the class. + * + * @param version the class version. + * @param access the class's access flags (see {@link Opcodes}). This + * parameter also indicates if the class is deprecated. + * @param name the internal name of the class (see + * {@link Type#getInternalName() getInternalName}). + * @param signature the signature of this class. May be <tt>null</tt> if + * the class is not a generic one, and does not extend or implement + * generic classes or interfaces. + * @param superName the internal of name of the super class (see + * {@link Type#getInternalName() getInternalName}). For interfaces, + * the super class is {@link Object}. May be <tt>null</tt>, but + * only for the {@link Object} class. + * @param interfaces the internal names of the class's interfaces (see + * {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. + */ + void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces); + + /** + * Visits the source of the class. + * + * @param source the name of the source file from which the class was + * compiled. May be <tt>null</tt>. + * @param debug additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * <tt>null</tt>. + */ + void visitSource(String source, String debug); + + /** + * Visits the enclosing class of the class. This method must be called only + * if the class has an enclosing class. + * + * @param owner internal name of the enclosing class of the class. + * @param name the name of the method that contains the class, or + * <tt>null</tt> if the class is not enclosed in a method of its + * enclosing class. + * @param desc the descriptor of the method that contains the class, or + * <tt>null</tt> if the class is not enclosed in a method of its + * enclosing class. + */ + void visitOuterClass(String owner, String name, String desc); + + /** + * Visits an annotation of the class. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a non null visitor to visit the annotation values. + */ + AnnotationVisitor visitAnnotation(String desc, boolean visible); + + /** + * Visits a non standard attribute of the class. + * + * @param attr an attribute. + */ + void visitAttribute(Attribute attr); + + /** + * Visits information about an inner class. This inner class is not + * necessarily a member of the class being visited. + * + * @param name the internal name of an inner class (see + * {@link Type#getInternalName() getInternalName}). + * @param outerName the internal name of the class to which the inner class + * belongs (see {@link 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. + */ + void visitInnerClass( + String name, + String outerName, + String innerName, + int access); + + /** + * Visits a field of the class. + * + * @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 Type Type}). + * @param signature the field's signature. May be <tt>null</tt> if the + * field's type does not use generic types. + * @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} (for <tt>int</tt>, + * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields + * respectively). <i>This parameter is only used for static fields</i>. + * Its value is ignored for non static fields, which must be + * initialized through bytecode instructions in constructors or + * methods. + * @return a visitor to visit field annotations and attributes, or + * <tt>null</tt> if this class visitor is not interested in + * visiting these annotations and attributes. + */ + FieldVisitor visitField( + int access, + String name, + String desc, + String signature, + Object value); + + /** + * Visits a method of the class. This method <i>must</i> return a new + * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is + * called, i.e., it should not return a previously returned visitor. + * + * @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 Type}). + * @param signature the method's signature. May be <tt>null</tt> if the + * method parameters, return type and exceptions do not use generic + * types. + * @param exceptions the internal names of the method's exception classes + * (see {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. + * @return an object to visit the byte code of the method, or <tt>null</tt> + * if this class visitor is not interested in visiting the code of + * this method. + */ + MethodVisitor visitMethod( + int access, + String name, + String desc, + String signature, + String[] exceptions); + + /** + * Visits the end of the class. This method, which is the last one to be + * called, is used to inform the visitor that all the fields and methods of + * the class have been visited. + */ + void visitEnd(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassWriter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassWriter.java new file mode 100644 index 000000000..81eeeb7d6 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/ClassWriter.java @@ -0,0 +1,1162 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A {@link ClassVisitor} that generates classes in bytecode form. More + * precisely this visitor generates a byte array conforming to the Java class + * file format. It can be used alone, to generate a Java class "from scratch", + * or with one or more {@link ClassReader ClassReader} and adapter class visitor + * to generate a modified class from one or more existing Java classes. + * + * @author Eric Bruneton + */ +public class ClassWriter implements ClassVisitor { + + /** + * The type of instructions without any argument. + */ + final static int NOARG_INSN = 0; + + /** + * The type of instructions with an signed byte argument. + */ + final static int SBYTE_INSN = 1; + + /** + * The type of instructions with an signed short argument. + */ + final static int SHORT_INSN = 2; + + /** + * The type of instructions with a local variable index argument. + */ + final static int VAR_INSN = 3; + + /** + * The type of instructions with an implicit local variable index argument. + */ + final static int IMPLVAR_INSN = 4; + + /** + * The type of instructions with a type descriptor argument. + */ + final static int TYPE_INSN = 5; + + /** + * The type of field and method invocations instructions. + */ + final static int FIELDORMETH_INSN = 6; + + /** + * The type of the INVOKEINTERFACE instruction. + */ + final static int ITFMETH_INSN = 7; + + /** + * The type of instructions with a 2 bytes bytecode offset label. + */ + final static int LABEL_INSN = 8; + + /** + * The type of instructions with a 4 bytes bytecode offset label. + */ + final static int LABELW_INSN = 9; + + /** + * The type of the LDC instruction. + */ + final static int LDC_INSN = 10; + + /** + * The type of the LDC_W and LDC2_W instructions. + */ + final static int LDCW_INSN = 11; + + /** + * The type of the IINC instruction. + */ + final static int IINC_INSN = 12; + + /** + * The type of the TABLESWITCH instruction. + */ + final static int TABL_INSN = 13; + + /** + * The type of the LOOKUPSWITCH instruction. + */ + final static int LOOK_INSN = 14; + + /** + * The type of the MULTIANEWARRAY instruction. + */ + final static int MANA_INSN = 15; + + /** + * The type of the WIDE instruction. + */ + final static int WIDE_INSN = 16; + + /** + * The instruction types of all JVM opcodes. + */ + static byte[] TYPE; + + /** + * The type of CONSTANT_Class constant pool items. + */ + final static int CLASS = 7; + + /** + * The type of CONSTANT_Fieldref constant pool items. + */ + final static int FIELD = 9; + + /** + * The type of CONSTANT_Methodref constant pool items. + */ + final static int METH = 10; + + /** + * The type of CONSTANT_InterfaceMethodref constant pool items. + */ + final static int IMETH = 11; + + /** + * The type of CONSTANT_String constant pool items. + */ + final static int STR = 8; + + /** + * The type of CONSTANT_Integer constant pool items. + */ + final static int INT = 3; + + /** + * The type of CONSTANT_Float constant pool items. + */ + final static int FLOAT = 4; + + /** + * The type of CONSTANT_Long constant pool items. + */ + final static int LONG = 5; + + /** + * The type of CONSTANT_Double constant pool items. + */ + final static int DOUBLE = 6; + + /** + * The type of CONSTANT_NameAndType constant pool items. + */ + final static int NAME_TYPE = 12; + + /** + * The type of CONSTANT_Utf8 constant pool items. + */ + final static int UTF8 = 1; + + /** + * The class reader from which this class writer was constructed, if any. + */ + ClassReader cr; + + /** + * Minor and major version numbers of the class to be generated. + */ + int version; + + /** + * Index of the next item to be added in the constant pool. + */ + int index; + + /** + * The constant pool of this class. + */ + ByteVector pool; + + /** + * The constant pool's hash table data. + */ + Item[] items; + + /** + * The threshold of the constant pool's hash table. + */ + int threshold; + + /** + * A reusable key used to look for items in the hash {@link #items items}. + */ + Item key; + + /** + * A reusable key used to look for items in the hash {@link #items items}. + */ + Item key2; + + /** + * A reusable key used to look for items in the hash {@link #items items}. + */ + Item key3; + + /** + * The access flags of this class. + */ + private int access; + + /** + * The constant pool item that contains the internal name of this class. + */ + private int name; + + /** + * The constant pool item that contains the signature of this class. + */ + private int signature; + + /** + * The constant pool item that contains the internal name of the super class + * of this class. + */ + private int superName; + + /** + * Number of interfaces implemented or extended by this class or interface. + */ + private int interfaceCount; + + /** + * The interfaces implemented or extended by this class or interface. More + * precisely, this array contains the indexes of the constant pool items + * that contain the internal names of these interfaces. + */ + private int[] interfaces; + + /** + * The index of the constant pool item that contains the name of the source + * file from which this class was compiled. + */ + private int sourceFile; + + /** + * The SourceDebug attribute of this class. + */ + private ByteVector sourceDebug; + + /** + * The constant pool item that contains the name of the enclosing class of + * this class. + */ + private int enclosingMethodOwner; + + /** + * The constant pool item that contains the name and descriptor of the + * enclosing method of this class. + */ + private int enclosingMethod; + + /** + * The runtime visible annotations of this class. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this class. + */ + private AnnotationWriter ianns; + + /** + * The non standard attributes of this class. + */ + private Attribute attrs; + + /** + * The number of entries in the InnerClasses attribute. + */ + private int innerClassesCount; + + /** + * The InnerClasses attribute. + */ + private ByteVector innerClasses; + + /** + * The fields of this class. These fields are stored in a linked list of + * {@link FieldWriter} objects, linked to each other by their + * {@link FieldWriter#next} field. This field stores the first element of + * this list. + */ + FieldWriter firstField; + + /** + * The fields of this class. These fields are stored in a linked list of + * {@link FieldWriter} objects, linked to each other by their + * {@link FieldWriter#next} field. This field stores the last element of + * this list. + */ + FieldWriter lastField; + + /** + * The methods of this class. These methods are stored in a linked list of + * {@link MethodWriter} objects, linked to each other by their + * {@link MethodWriter#next} field. This field stores the first element of + * this list. + */ + MethodWriter firstMethod; + + /** + * The methods of this class. These methods are stored in a linked list of + * {@link MethodWriter} objects, linked to each other by their + * {@link MethodWriter#next} field. This field stores the last element of + * this list. + */ + MethodWriter lastMethod; + + /** + * <tt>true</tt> if the maximum stack size and number of local variables + * must be automatically computed. + */ + private boolean computeMaxs; + + // ------------------------------------------------------------------------ + // Static initializer + // ------------------------------------------------------------------------ + + /** + * Computes the instruction types of JVM opcodes. + */ + static { + int i; + byte[] b = new byte[220]; + String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA" + + "AAAAGGGGGGGHAFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII"; + for (i = 0; i < b.length; ++i) { + b[i] = (byte) (s.charAt(i) - 'A'); + } + TYPE = b; + + // code to generate the above string + // + // // SBYTE_INSN instructions + // b[Constants.NEWARRAY] = SBYTE_INSN; + // b[Constants.BIPUSH] = SBYTE_INSN; + // + // // SHORT_INSN instructions + // b[Constants.SIPUSH] = SHORT_INSN; + // + // // (IMPL)VAR_INSN instructions + // b[Constants.RET] = VAR_INSN; + // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 + // b[i] = IMPLVAR_INSN; + // } + // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 + // b[i] = IMPLVAR_INSN; + // } + // + // // TYPE_INSN instructions + // b[Constants.NEW] = TYPE_INSN; + // b[Constants.ANEWARRAY] = TYPE_INSN; + // b[Constants.CHECKCAST] = TYPE_INSN; + // b[Constants.INSTANCEOF] = TYPE_INSN; + // + // // (Set)FIELDORMETH_INSN instructions + // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { + // b[i] = FIELDORMETH_INSN; + // } + // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; + // + // // LABEL(W)_INSN instructions + // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { + // b[i] = LABEL_INSN; + // } + // b[Constants.IFNULL] = LABEL_INSN; + // b[Constants.IFNONNULL] = LABEL_INSN; + // b[200] = LABELW_INSN; // GOTO_W + // b[201] = LABELW_INSN; // JSR_W + // // temporary opcodes used internally by ASM - see Label and + // MethodWriter + // for (i = 202; i < 220; ++i) { + // b[i] = LABEL_INSN; + // } + // + // // LDC(_W) instructions + // b[Constants.LDC] = LDC_INSN; + // b[19] = LDCW_INSN; // LDC_W + // b[20] = LDCW_INSN; // LDC2_W + // + // // special instructions + // b[Constants.IINC] = IINC_INSN; + // b[Constants.TABLESWITCH] = TABL_INSN; + // b[Constants.LOOKUPSWITCH] = LOOK_INSN; + // b[Constants.MULTIANEWARRAY] = MANA_INSN; + // b[196] = WIDE_INSN; // WIDE + // + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('A' + b[i])); + // } + // System.err.println(); + } + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassWriter ClassWriter} object. + * + * @param computeMaxs <tt>true</tt> if the maximum stack size and the + * maximum number of local variables must be automatically computed. + * If this flag is <tt>true</tt>, then the arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method of the + * {@link MethodVisitor} returned by the + * {@link #visitMethod visitMethod} method will be ignored, and + * computed automatically from the signature and the bytecode of each + * method. + */ + public ClassWriter(final boolean computeMaxs) { + this(computeMaxs, false); + } + + /** + * Constructs a new {@link ClassWriter} object. + * + * @param computeMaxs <tt>true</tt> if the maximum stack size and the + * maximum number of local variables must be automatically computed. + * If this flag is <tt>true</tt>, then the arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method of the + * {@link MethodVisitor} returned by the + * {@link #visitMethod visitMethod} method will be ignored, and + * computed automatically from the signature and the bytecode of each + * method. + * @param skipUnknownAttributes <b>Deprecated</b>. The value of this + * parameter is ignored. + */ + public ClassWriter( + final boolean computeMaxs, + final boolean skipUnknownAttributes) + { + index = 1; + pool = new ByteVector(); + items = new Item[256]; + threshold = (int) (0.75d * items.length); + key = new Item(); + key2 = new Item(); + key3 = new Item(); + this.computeMaxs = computeMaxs; + } + + /** + * Constructs a new {@link ClassWriter} object and enables optimizations for + * "mostly add" bytecode transformations. These optimizations are the + * following: + * + * <ul> <li>The constant pool from the original class is copied as is in + * the new class, which saves time. New constant pool entries will be added + * at the end if necessary, but unused constant pool entries <i>won't be + * removed</i>.</li> <li>Methods that are not transformed are copied as + * is in the new class, directly from the original class bytecode (i.e. + * without emitting visit events for all the method instructions), which + * saves a <i>lot</i> of time. Untransformed methods are detected by the + * fact that the {@link ClassReader} receives {@link MethodVisitor} objects + * that come from a {@link ClassWriter} (and not from a custom + * {@link ClassAdapter} or any other {@link ClassVisitor} instance).</li> + * </ul> + * + * @param classReader the {@link ClassReader} used to read the original + * class. It will be used to copy the entire constant pool from the + * original class and also to copy other fragments of original + * bytecode where applicable. + * @param computeMaxs <tt>true</tt> if the maximum stack size and the + * maximum number of local variables must be automatically computed. + * If this flag is <tt>true</tt>, then the arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method of the + * {@link MethodVisitor} returned by the + * {@link #visitMethod visitMethod} method will be ignored, and + * computed automatically from the signature and the bytecode of each + * method. + */ + public ClassWriter( + final ClassReader classReader, + final boolean computeMaxs) + { + this(computeMaxs, false); + classReader.copyPool(this); + this.cr = classReader; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + this.version = version; + this.access = access; + this.name = newClass(name); + if (signature != null) { + this.signature = newUTF8(signature); + } + this.superName = superName == null ? 0 : newClass(superName); + if (interfaces != null && interfaces.length > 0) { + interfaceCount = interfaces.length; + this.interfaces = new int[interfaceCount]; + for (int i = 0; i < interfaceCount; ++i) { + this.interfaces[i] = newClass(interfaces[i]); + } + } + } + + public void visitSource(final String file, final String debug) { + if (file != null) { + sourceFile = newUTF8(file); + } + if (debug != null) { + sourceDebug = new ByteVector().putUTF8(debug); + } + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + enclosingMethodOwner = newClass(owner); + if (name != null && desc != null) { + enclosingMethod = newNameType(name, desc); + } + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + public void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + if (innerClasses == null) { + innerClasses = new ByteVector(); + } + ++innerClassesCount; + innerClasses.putShort(name == null ? 0 : newClass(name)); + innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); + innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); + innerClasses.putShort(access); + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + return new FieldWriter(this, access, name, desc, signature, value); + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + return new MethodWriter(this, + access, + name, + desc, + signature, + exceptions, + computeMaxs); + } + + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Other public methods + // ------------------------------------------------------------------------ + + /** + * Returns the bytecode of the class that was build with this class writer. + * + * @return the bytecode of the class that was build with this class writer. + */ + public byte[] toByteArray() { + // computes the real size of the bytecode of this class + int size = 24 + 2 * interfaceCount; + int nbFields = 0; + FieldWriter fb = firstField; + while (fb != null) { + ++nbFields; + size += fb.getSize(); + fb = fb.next; + } + int nbMethods = 0; + MethodWriter mb = firstMethod; + while (mb != null) { + ++nbMethods; + size += mb.getSize(); + mb = mb.next; + } + int attributeCount = 0; + if (signature != 0) { + ++attributeCount; + size += 8; + newUTF8("Signature"); + } + if (sourceFile != 0) { + ++attributeCount; + size += 8; + newUTF8("SourceFile"); + } + if (sourceDebug != null) { + ++attributeCount; + size += sourceDebug.length + 4; + newUTF8("SourceDebugExtension"); + } + if (enclosingMethodOwner != 0) { + ++attributeCount; + size += 10; + newUTF8("EnclosingMethod"); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + size += 6; + newUTF8("Deprecated"); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (version & 0xffff) < Opcodes.V1_5) + { + ++attributeCount; + size += 6; + newUTF8("Synthetic"); + } + if (version == Opcodes.V1_4) { + if ((access & Opcodes.ACC_ANNOTATION) != 0) { + ++attributeCount; + size += 6; + newUTF8("Annotation"); + } + if ((access & Opcodes.ACC_ENUM) != 0) { + ++attributeCount; + size += 6; + newUTF8("Enum"); + } + } + if (innerClasses != null) { + ++attributeCount; + size += 8 + innerClasses.length; + newUTF8("InnerClasses"); + } + if (anns != null) { + ++attributeCount; + size += 8 + anns.getSize(); + newUTF8("RuntimeVisibleAnnotations"); + } + if (ianns != null) { + ++attributeCount; + size += 8 + ianns.getSize(); + newUTF8("RuntimeInvisibleAnnotations"); + } + if (attrs != null) { + attributeCount += attrs.getCount(); + size += attrs.getSize(this, null, 0, -1, -1); + } + size += pool.length; + // allocates a byte vector of this size, in order to avoid unnecessary + // arraycopy operations in the ByteVector.enlarge() method + ByteVector out = new ByteVector(size); + out.putInt(0xCAFEBABE).putInt(version); + out.putShort(index).putByteArray(pool.data, 0, pool.length); + out.putShort(access).putShort(name).putShort(superName); + out.putShort(interfaceCount); + for (int i = 0; i < interfaceCount; ++i) { + out.putShort(interfaces[i]); + } + out.putShort(nbFields); + fb = firstField; + while (fb != null) { + fb.put(out); + fb = fb.next; + } + out.putShort(nbMethods); + mb = firstMethod; + while (mb != null) { + mb.put(out); + mb = mb.next; + } + out.putShort(attributeCount); + if (signature != 0) { + out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); + } + if (sourceFile != 0) { + out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); + } + if (sourceDebug != null) { + int len = sourceDebug.length - 2; + out.putShort(newUTF8("SourceDebugExtension")).putInt(len); + out.putByteArray(sourceDebug.data, 2, len); + } + if (enclosingMethodOwner != 0) { + out.putShort(newUTF8("EnclosingMethod")).putInt(4); + out.putShort(enclosingMethodOwner).putShort(enclosingMethod); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(newUTF8("Deprecated")).putInt(0); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (version & 0xffff) < Opcodes.V1_5) + { + out.putShort(newUTF8("Synthetic")).putInt(0); + } + if (version == Opcodes.V1_4) { + if ((access & Opcodes.ACC_ANNOTATION) != 0) { + out.putShort(newUTF8("Annotation")).putInt(0); + } + if ((access & Opcodes.ACC_ENUM) != 0) { + out.putShort(newUTF8("Enum")).putInt(0); + } + } + if (innerClasses != null) { + out.putShort(newUTF8("InnerClasses")); + out.putInt(innerClasses.length + 2).putShort(innerClassesCount); + out.putByteArray(innerClasses.data, 0, innerClasses.length); + } + if (anns != null) { + out.putShort(newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (attrs != null) { + attrs.put(this, null, 0, -1, -1, out); + } + return out.data; + } + + // ------------------------------------------------------------------------ + // Utility methods: constant pool management + // ------------------------------------------------------------------------ + + /** + * Adds a number or string constant to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * + * @param cst the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double}, a {@link String} or a + * {@link Type}. + * @return a new or already existing constant item with the given value. + */ + Item newConstItem(final Object cst) { + if (cst instanceof Integer) { + int val = ((Integer) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Byte) { + int val = ((Byte) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Character) { + int val = ((Character) cst).charValue(); + return newInteger(val); + } else if (cst instanceof Short) { + int val = ((Short) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Boolean) { + int val = ((Boolean) cst).booleanValue() ? 1 : 0; + return newInteger(val); + } else if (cst instanceof Float) { + float val = ((Float) cst).floatValue(); + return newFloat(val); + } else if (cst instanceof Long) { + long val = ((Long) cst).longValue(); + return newLong(val); + } else if (cst instanceof Double) { + double val = ((Double) cst).doubleValue(); + return newDouble(val); + } else if (cst instanceof String) { + return newString((String) cst); + } else if (cst instanceof Type) { + Type t = (Type) cst; + return newClassItem(t.getSort() == Type.OBJECT + ? t.getInternalName() + : t.getDescriptor()); + } else { + throw new IllegalArgumentException("value " + cst); + } + } + + /** + * Adds a number or string constant to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param cst the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double} or a {@link String}. + * @return the index of a new or already existing constant item with the + * given value. + */ + public int newConst(final Object cst) { + return newConstItem(cst).index; + } + + /** + * Adds an UTF8 string to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. <i>This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters.</i> + * + * @param value the String value. + * @return the index of a new or already existing UTF8 item. + */ + public int newUTF8(final String value) { + key.set(UTF8, value, null, null); + Item result = get(key); + if (result == null) { + pool.putByte(UTF8).putUTF8(value); + result = new Item(index++, key); + put(result); + } + return result.index; + } + + /** + * Adds a class reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param value the internal name of the class. + * @return the index of a new or already existing class reference item. + */ + public int newClass(final String value) { + return newClassItem(value).index; + } + + /** + * Adds a class reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param value the internal name of the class. + * @return a new or already existing class reference item. + */ + private Item newClassItem(final String value) { + key2.set(CLASS, value, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(CLASS, newUTF8(value)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a field reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. + * @return the index of a new or already existing field reference item. + */ + public int newField(final String owner, final String name, final String desc) + { + key3.set(FIELD, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(FIELD, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result.index; + } + + /** + * Adds a method reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @return a new or already existing method reference item. + */ + Item newMethodItem( + final String owner, + final String name, + final String desc, + final boolean itf) + { + int type = itf ? IMETH : METH; + key3.set(type, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(type, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds a method reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @return the index of a new or already existing method reference item. + */ + public int newMethod( + final String owner, + final String name, + final String desc, + final boolean itf) + { + return newMethodItem(owner, name, desc, itf).index; + } + + /** + * Adds an integer to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. + * + * @param value the int value. + * @return a new or already existing int item. + */ + Item newInteger(final int value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(INT).putInt(value); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a float to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the float value. + * @return a new or already existing float item. + */ + Item newFloat(final float value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(FLOAT).putInt(Float.floatToIntBits(value)); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a long to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the long value. + * @return a new or already existing long item. + */ + Item newLong(final long value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(LONG).putLong(value); + result = new Item(index, key); + put(result); + index += 2; + } + return result; + } + + /** + * Adds a double to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the double value. + * @return a new or already existing double item. + */ + Item newDouble(final double value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(DOUBLE).putLong(Double.doubleToLongBits(value)); + result = new Item(index, key); + put(result); + index += 2; + } + return result; + } + + /** + * Adds a string to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the String value. + * @return a new or already existing string item. + */ + private Item newString(final String value) { + key2.set(STR, value, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(STR, newUTF8(value)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a name and type to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. <i>This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters.</i> + * + * @param name a name. + * @param desc a type descriptor. + * @return the index of a new or already existing name and type item. + */ + public int newNameType(final String name, final String desc) { + key2.set(NAME_TYPE, name, desc, null); + Item result = get(key2); + if (result == null) { + put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); + result = new Item(index++, key2); + put(result); + } + return result.index; + } + + /** + * Returns the constant pool's hash table item which is equal to the given + * item. + * + * @param key a constant pool item. + * @return the constant pool's hash table item which is equal to the given + * item, or <tt>null</tt> if there is no such item. + */ + private Item get(final Item key) { + Item i = items[key.hashCode % items.length]; + while (i != null && !key.isEqualTo(i)) { + i = i.next; + } + return i; + } + + /** + * Puts the given item in the constant pool's hash table. The hash table + * <i>must</i> not already contains this item. + * + * @param i the item to be added to the constant pool's hash table. + */ + private void put(final Item i) { + if (index > threshold) { + int ll = items.length; + int nl = ll * 2 + 1; + Item[] newItems = new Item[nl]; + for (int l = ll - 1; l >= 0; --l) { + Item j = items[l]; + while (j != null) { + int index = j.hashCode % newItems.length; + Item k = j.next; + j.next = newItems[index]; + newItems[index] = j; + j = k; + } + } + items = newItems; + threshold = (int) (nl * 0.75); + } + int index = i.hashCode % items.length; + i.next = items[index]; + items[index] = i; + } + + /** + * Puts one byte and two shorts into the constant pool. + * + * @param b a byte. + * @param s1 a short. + * @param s2 another short. + */ + private void put122(final int b, final int s1, final int s2) { + pool.put12(b, s1).putShort(s2); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Edge.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Edge.java new file mode 100644 index 000000000..5bada4e9a --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Edge.java @@ -0,0 +1,57 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An edge in the control flow graph of a method body. See {@link Label Label}. + * + * @author Eric Bruneton + */ +class Edge { + + /** + * The (relative) stack size in the basic block from which this edge + * originates. This size is equal to the stack size at the "jump" + * instruction to which this edge corresponds, relatively to the stack size + * at the beginning of the originating basic block. + */ + int stackSize; + + /** + * The successor block of the basic block from which this edge originates. + */ + Label successor; + + /** + * The next edge in the list of successors of the originating basic block. + * See {@link Label#successors successors}. + */ + Edge next; +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldVisitor.java new file mode 100644 index 000000000..a05cb5a3c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldVisitor.java @@ -0,0 +1,63 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A visitor to visit a Java field. The methods of this interface must be called + * in the following order: ( <tt>visitAnnotation</tt> | + * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>. + * + * @author Eric Bruneton + */ +public interface FieldVisitor { + + /** + * Visits an annotation of the field. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a non null visitor to visit the annotation values. + */ + AnnotationVisitor visitAnnotation(String desc, boolean visible); + + /** + * Visits a non standard attribute of the field. + * + * @param attr an attribute. + */ + void visitAttribute(Attribute attr); + + /** + * Visits the end of the field. This method, which is the last one to be + * called, is used to inform the visitor that all the annotations and + * attributes of the field have been visited. + */ + void visitEnd(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldWriter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldWriter.java new file mode 100644 index 000000000..0adbea91a --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/FieldWriter.java @@ -0,0 +1,276 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An {@link FieldVisitor} that generates Java fields in bytecode form. + * + * @author Eric Bruneton + */ +final class FieldWriter implements FieldVisitor { + + /** + * Next field writer (see {@link ClassWriter#firstField firstField}). + */ + FieldWriter next; + + /** + * The class writer to which this field must be added. + */ + private ClassWriter cw; + + /** + * Access flags of this field. + */ + private int access; + + /** + * The index of the constant pool item that contains the name of this + * method. + */ + private int name; + + /** + * The index of the constant pool item that contains the descriptor of this + * field. + */ + private int desc; + + /** + * The index of the constant pool item that contains the signature of this + * field. + */ + private int signature; + + /** + * The index of the constant pool item that contains the constant value of + * this field. + */ + private int value; + + /** + * The runtime visible annotations of this field. May be <tt>null</tt>. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this field. May be <tt>null</tt>. + */ + private AnnotationWriter ianns; + + /** + * The non standard attributes of this field. May be <tt>null</tt>. + */ + private Attribute attrs; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link FieldWriter}. + * + * @param cw the class writer to which this field must be added. + * @param access the field's access flags (see {@link Opcodes}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type}). + * @param signature the field's signature. May be <tt>null</tt>. + * @param value the field's constant value. May be <tt>null</tt>. + */ + protected FieldWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + if (cw.firstField == null) { + cw.firstField = this; + } else { + cw.lastField.next = this; + } + cw.lastField = this; + this.cw = cw; + this.access = access; + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + if (signature != null) { + this.signature = cw.newUTF8(signature); + } + if (value != null) { + this.value = cw.newConstItem(value).index; + } + } + + // ------------------------------------------------------------------------ + // Implementation of the FieldVisitor interface + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + public void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this field. + * + * @return the size of this field. + */ + int getSize() { + int size = 8; + if (value != 0) { + cw.newUTF8("ConstantValue"); + size += 8; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + cw.newUTF8("Synthetic"); + size += 6; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) { + cw.newUTF8("Enum"); + size += 6; + } + if (signature != 0) { + cw.newUTF8("Signature"); + size += 8; + } + if (anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the content of this field into the given byte vector. + * + * @param out where the content of this field must be put. + */ + void put(final ByteVector out) { + out.putShort(access).putShort(name).putShort(desc); + int attributeCount = 0; + if (value != 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + ++attributeCount; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) { + ++attributeCount; + } + if (signature != 0) { + ++attributeCount; + } + if (anns != null) { + ++attributeCount; + } + if (ianns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (value != 0) { + out.putShort(cw.newUTF8("ConstantValue")); + out.putInt(2).putShort(value); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) { + out.putShort(cw.newUTF8("Enum")).putInt(0); + } + if (signature != 0) { + out.putShort(cw.newUTF8("Signature")); + out.putInt(2).putShort(signature); + } + if (anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Handler.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Handler.java new file mode 100644 index 000000000..a1211ae2d --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Handler.java @@ -0,0 +1,70 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * Information about an exception handler block. + * + * @author Eric Bruneton + */ +class Handler { + + /** + * Beginning of the exception handler's scope (inclusive). + */ + Label start; + + /** + * End of the exception handler's scope (exclusive). + */ + Label end; + + /** + * Beginning of the exception handler's code. + */ + Label handler; + + /** + * Internal name of the type of exceptions handled by this handler, or + * <tt>null</tt> to catch any exceptions. + */ + String desc; + + /** + * Constant pool index of the internal name of the type of exceptions + * handled by this handler, or 0 to catch any exceptions. + */ + int type; + + /** + * Next exception handler block info. + */ + Handler next; +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Item.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Item.java new file mode 100644 index 000000000..fc67b0194 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Item.java @@ -0,0 +1,252 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A constant pool item. Constant pool items can be created with the 'newXXX' + * methods in the {@link ClassWriter} class. + * + * @author Eric Bruneton + */ +final class Item { + + /** + * Index of this item in the constant pool. + */ + int index; + + /** + * Type of this constant pool item. A single class is used to represent all + * constant pool item types, in order to minimize the bytecode size of this + * package. The value of this field is one of {@link ClassWriter#INT}, + * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, + * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, + * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, + * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, + * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}. + */ + int type; + + /** + * Value of this item, for an integer item. + */ + int intVal; + + /** + * Value of this item, for a long item. + */ + long longVal; + + /** + * Value of this item, for a float item. + */ + float floatVal; + + /** + * Value of this item, for a double item. + */ + double doubleVal; + + /** + * First part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal1; + + /** + * Second part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal2; + + /** + * Third part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal3; + + /** + * The hash code value of this constant pool item. + */ + int hashCode; + + /** + * Link to another constant pool item, used for collision lists in the + * constant pool's hash table. + */ + Item next; + + /** + * Constructs an uninitialized {@link Item}. + */ + Item() { + } + + Item(int index) { + this.index = index; + } + + /** + * Constructs a copy of the given item. + * + * @param index index of the item to be constructed. + * @param i the item that must be copied into the item to be constructed. + */ + Item(final int index, final Item i) { + this.index = index; + type = i.type; + intVal = i.intVal; + longVal = i.longVal; + floatVal = i.floatVal; + doubleVal = i.doubleVal; + strVal1 = i.strVal1; + strVal2 = i.strVal2; + strVal3 = i.strVal3; + hashCode = i.hashCode; + } + + /** + * Sets this item to an integer item. + * + * @param intVal the value of this item. + */ + void set(final int intVal) { + this.type = ClassWriter.INT; + this.intVal = intVal; + this.hashCode = 0x7FFFFFFF & (type + intVal); + } + + /** + * Sets this item to a long item. + * + * @param longVal the value of this item. + */ + void set(final long longVal) { + this.type = ClassWriter.LONG; + this.longVal = longVal; + this.hashCode = 0x7FFFFFFF & (type + (int) longVal); + } + + /** + * Sets this item to a float item. + * + * @param floatVal the value of this item. + */ + void set(final float floatVal) { + this.type = ClassWriter.FLOAT; + this.floatVal = floatVal; + this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); + } + + /** + * Sets this item to a double item. + * + * @param doubleVal the value of this item. + */ + void set(final double doubleVal) { + this.type = ClassWriter.DOUBLE; + this.doubleVal = doubleVal; + this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); + } + + /** + * Sets this item to an item that do not hold a primitive value. + * + * @param type the type of this item. + * @param strVal1 first part of the value of this item. + * @param strVal2 second part of the value of this item. + * @param strVal3 third part of the value of this item. + */ + void set( + final int type, + final String strVal1, + final String strVal2, + final String strVal3) + { + this.type = type; + this.strVal1 = strVal1; + this.strVal2 = strVal2; + this.strVal3 = strVal3; + switch (type) { + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); + return; + case ClassWriter.NAME_TYPE: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode()); + return; + // ClassWriter.FIELD: + // ClassWriter.METH: + // ClassWriter.IMETH: + default: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode() * strVal3.hashCode()); + } + } + + /** + * Indicates if the given item is equal to this one. + * + * @param i the item to be compared to this one. + * @return <tt>true</tt> if the given item if equal to this one, + * <tt>false</tt> otherwise. + */ + boolean isEqualTo(final Item i) { + if (i.type == type) { + switch (type) { + case ClassWriter.INT: + return i.intVal == intVal; + case ClassWriter.LONG: + return i.longVal == longVal; + case ClassWriter.FLOAT: + return i.floatVal == floatVal; + case ClassWriter.DOUBLE: + return i.doubleVal == doubleVal; + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + return i.strVal1.equals(strVal1); + case ClassWriter.NAME_TYPE: + return i.strVal1.equals(strVal1) + && i.strVal2.equals(strVal2); + // ClassWriter.FIELD: + // ClassWriter.METH: + // ClassWriter.IMETH: + default: + return i.strVal1.equals(strVal1) + && i.strVal2.equals(strVal2) + && i.strVal3.equals(strVal3); + } + } + return false; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Label.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Label.java new file mode 100644 index 000000000..3998e5a86 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Label.java @@ -0,0 +1,299 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A label represents a position in the bytecode of a method. Labels are used + * for jump, goto, and switch instructions, and for try catch blocks. + * + * @author Eric Bruneton + */ +public class Label { + + /** + * The line number corresponding to this label, if known. + */ + int line; + + /** + * Indicates if the position of this label is known. + */ + boolean resolved; + + /** + * The position of this label in the code, if known. + */ + int position; + + /** + * If the label position has been updated, after instruction resizing. + */ + boolean resized; + + /** + * Number of forward references to this label, times two. + */ + private int referenceCount; + + /** + * Informations about forward references. Each forward reference is + * described by two consecutive integers in this array: the first one is the + * position of the first byte of the bytecode instruction that contains the + * forward reference, while the second is the position of the first byte of + * the forward reference itself. In fact the sign of the first integer + * indicates if this reference uses 2 or 4 bytes, and its absolute value + * gives the position of the bytecode instruction. + */ + private int[] srcAndRefPositions; + + /* + * Fields for the control flow graph analysis algorithm (used to compute the + * maximum stack size). A control flow graph contains one node per "basic + * block", and one edge per "jump" from one basic block to another. Each + * node (i.e., each basic block) is represented by the Label object that + * corresponds to the first instruction of this basic block. Each node also + * stores the list of it successors in the graph, as a linked list of Edge + * objects. + */ + + /** + * The stack size at the beginning of this basic block. This size is + * initially unknown. It is computed by the control flow analysis algorithm + * (see {@link MethodWriter#visitMaxs visitMaxs}). + */ + int beginStackSize; + + /** + * The (relative) maximum stack size corresponding to this basic block. This + * size is relative to the stack size at the beginning of the basic block, + * i.e., the true maximum stack size is equal to {@link #beginStackSize + * beginStackSize} + {@link #maxStackSize maxStackSize}. + */ + int maxStackSize; + + /** + * The successors of this node in the control flow graph. These successors + * are stored in a linked list of {@link Edge Edge} objects, linked to each + * other by their {@link Edge#next} field. + */ + Edge successors; + + /** + * The next basic block in the basic block stack. See + * {@link MethodWriter#visitMaxs visitMaxs}. + */ + Label next; + + /** + * <tt>true</tt> if this basic block has been pushed in the basic block + * stack. See {@link MethodWriter#visitMaxs visitMaxs}. + */ + boolean pushed; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new label. + */ + public Label() { + } + + // ------------------------------------------------------------------------ + // Methods to compute offsets and to manage forward references + // ------------------------------------------------------------------------ + + /** + * Returns the offset corresponding to this label. This offset is computed + * from the start of the method's bytecode. <i>This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> + * + * @return the offset corresponding to this label. + * @throws IllegalStateException if this label is not resolved yet. + */ + public int getOffset() { + if (!resolved) { + throw new IllegalStateException("Label offset position has not been resolved yet"); + } + return position; + } + + /** + * Puts a reference to this label in the bytecode of a method. If the + * position of the label is known, the offset is computed and written + * directly. Otherwise, a null offset is written and a new forward reference + * is declared for this label. + * + * @param owner the code writer that calls this method. + * @param out the bytecode of the method. + * @param source the position of first byte of the bytecode instruction that + * contains this label. + * @param wideOffset <tt>true</tt> if the reference must be stored in 4 + * bytes, or <tt>false</tt> if it must be stored with 2 bytes. + * @throws IllegalArgumentException if this label has not been created by + * the given code writer. + */ + void put( + final MethodWriter owner, + final ByteVector out, + final int source, + final boolean wideOffset) + { + if (resolved) { + if (wideOffset) { + out.putInt(position - source); + } else { + out.putShort(position - source); + } + } else { + if (wideOffset) { + addReference(-1 - source, out.length); + out.putInt(-1); + } else { + addReference(source, out.length); + out.putShort(-1); + } + } + } + + /** + * Adds a forward reference to this label. This method must be called only + * for a true forward reference, i.e. only if this label is not resolved + * yet. For backward references, the offset of the reference can be, and + * must be, computed and stored directly. + * + * @param sourcePosition the position of the referencing instruction. This + * position will be used to compute the offset of this forward + * reference. + * @param referencePosition the position where the offset for this forward + * reference must be stored. + */ + private void addReference( + final int sourcePosition, + final int referencePosition) + { + if (srcAndRefPositions == null) { + srcAndRefPositions = new int[6]; + } + if (referenceCount >= srcAndRefPositions.length) { + int[] a = new int[srcAndRefPositions.length + 6]; + System.arraycopy(srcAndRefPositions, + 0, + a, + 0, + srcAndRefPositions.length); + srcAndRefPositions = a; + } + srcAndRefPositions[referenceCount++] = sourcePosition; + srcAndRefPositions[referenceCount++] = referencePosition; + } + + /** + * Resolves all forward references to this label. This method must be called + * when this label is added to the bytecode of the method, i.e. when its + * position becomes known. This method fills in the blanks that where left + * in the bytecode by each forward reference previously added to this label. + * + * @param owner the code writer that calls this method. + * @param position the position of this label in the bytecode. + * @param data the bytecode of the method. + * @return <tt>true</tt> if a blank that was left for this label was to + * small to store the offset. In such a case the corresponding jump + * instruction is replaced with a pseudo instruction (using unused + * opcodes) using an unsigned two bytes offset. These pseudo + * instructions will need to be replaced with true instructions with + * wider offsets (4 bytes instead of 2). This is done in + * {@link MethodWriter#resizeInstructions}. + * @throws IllegalArgumentException if this label has already been resolved, + * or if it has not been created by the given code writer. + */ + boolean resolve( + final MethodWriter owner, + final int position, + final byte[] data) + { + boolean needUpdate = false; + this.resolved = true; + this.position = position; + int i = 0; + while (i < referenceCount) { + int source = srcAndRefPositions[i++]; + int reference = srcAndRefPositions[i++]; + int offset; + if (source >= 0) { + offset = position - source; + if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { + /* + * changes the opcode of the jump instruction, in order to + * be able to find it later (see resizeInstructions in + * MethodWriter). These temporary opcodes are similar to + * jump instruction opcodes, except that the 2 bytes offset + * is unsigned (and can therefore represent values from 0 to + * 65535, which is sufficient since the size of a method is + * limited to 65535 bytes). + */ + int opcode = data[reference - 1] & 0xFF; + if (opcode <= Opcodes.JSR) { + // changes IFEQ ... JSR to opcodes 202 to 217 + data[reference - 1] = (byte) (opcode + 49); + } else { + // changes IFNULL and IFNONNULL to opcodes 218 and 219 + data[reference - 1] = (byte) (opcode + 20); + } + needUpdate = true; + } + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } else { + offset = position + source + 1; + data[reference++] = (byte) (offset >>> 24); + data[reference++] = (byte) (offset >>> 16); + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } + } + return needUpdate; + } + + // ------------------------------------------------------------------------ + // Overriden Object methods + // ------------------------------------------------------------------------ + + /** + * Returns a string representation of this label. + * + * @return a string representation of this label. + */ + public String toString() { + return "L" + System.identityHashCode(this); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodAdapter.java new file mode 100644 index 000000000..a038ac713 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodAdapter.java @@ -0,0 +1,185 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An empty {@link MethodVisitor} that delegates to another + * {@link MethodVisitor}. This class can be used as a super class to quickly + * implement usefull method adapter classes, just by overriding the necessary + * methods. + * + * @author Eric Bruneton + */ +public class MethodAdapter implements MethodVisitor { + + /** + * The {@link MethodVisitor} to which this adapter delegates calls. + */ + protected MethodVisitor mv; + + /** + * Constructs a new {@link MethodAdapter} object. + * + * @param mv the code visitor to which this adapter must delegate calls. + */ + public MethodAdapter(final MethodVisitor mv) { + this.mv = mv; + } + + public AnnotationVisitor visitAnnotationDefault() { + return mv.visitAnnotationDefault(); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + return mv.visitAnnotation(desc, visible); + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + return mv.visitParameterAnnotation(parameter, desc, visible); + } + + public void visitAttribute(final Attribute attr) { + mv.visitAttribute(attr); + } + + public void visitCode() { + mv.visitCode(); + } + + public void visitInsn(final int opcode) { + mv.visitInsn(opcode); + } + + public void visitIntInsn(final int opcode, final int operand) { + mv.visitIntInsn(opcode, operand); + } + + public void visitVarInsn(final int opcode, final int var) { + mv.visitVarInsn(opcode, var); + } + + public void visitTypeInsn(final int opcode, final String desc) { + mv.visitTypeInsn(opcode, desc); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitFieldInsn(opcode, owner, name, desc); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitMethodInsn(opcode, owner, name, desc); + } + + public void visitJumpInsn(final int opcode, final Label label) { + mv.visitJumpInsn(opcode, label); + } + + public void visitLabel(final Label label) { + mv.visitLabel(label); + } + + public void visitLdcInsn(final Object cst) { + mv.visitLdcInsn(cst); + } + + public void visitIincInsn(final int var, final int increment) { + mv.visitIincInsn(var, increment); + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label labels[]) + { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int keys[], + final Label labels[]) + { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + mv.visitMultiANewArrayInsn(desc, dims); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + mv.visitTryCatchBlock(start, end, handler, type); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + + public void visitLineNumber(final int line, final Label start) { + mv.visitLineNumber(line, start); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + mv.visitMaxs(maxStack, maxLocals); + } + + public void visitEnd() { + mv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodVisitor.java new file mode 100644 index 000000000..d56b3bd1c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodVisitor.java @@ -0,0 +1,334 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A visitor to visit a Java method. The methods of this interface must be + * called in the following order: [ <tt>visitAnnotationDefault</tt> ] ( + * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> | + * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visit</tt><i>X</i>Insn</tt> | + * <tt>visitLabel</tt> | <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> | + * <tt>visitLineNumber</tt>)* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In + * addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> + * methods must be called in the sequential order of the bytecode instructions + * of the visited code, and the <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> + * methods must be called <i>after</i> the labels passed as arguments have been + * visited. + * + * @author Eric Bruneton + */ +public interface MethodVisitor { + + // ------------------------------------------------------------------------- + // Annotations and non standard attributes + // ------------------------------------------------------------------------- + + /** + * Visits the default value of this annotation interface method. + * + * @return a non null visitor to the visit the actual default value of this + * annotation interface method. The 'name' parameters passed to the + * methods of this annotation visitor are ignored. Moreover, exacly + * one visit method must be called on this annotation visitor, + * followed by visitEnd. + */ + AnnotationVisitor visitAnnotationDefault(); + + /** + * Visits an annotation of this method. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a non null visitor to visit the annotation values. + */ + AnnotationVisitor visitAnnotation(String desc, boolean visible); + + /** + * Visits an annotation of a parameter this method. + * + * @param parameter the parameter index. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a non null visitor to visit the annotation values. + */ + AnnotationVisitor visitParameterAnnotation( + int parameter, + String desc, + boolean visible); + + /** + * Visits a non standard attribute of this method. + * + * @param attr an attribute. + */ + void visitAttribute(Attribute attr); + + /** + * Starts the visit of the method's code, if any (i.e. non abstract method). + */ + void visitCode(); + + // ------------------------------------------------------------------------- + // Normal instructions + // ------------------------------------------------------------------------- + + /** + * Visits a zero operand instruction. + * + * @param opcode the opcode of the instruction to be visited. This opcode is + * either 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. + */ + void visitInsn(int opcode); + + /** + * Visits an instruction with a single int operand. + * + * @param opcode the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand the operand of the instruction to be visited.<br> + * When opcode is BIPUSH, operand value should be between + * Byte.MIN_VALUE and Byte.MAX_VALUE.<br> + * When opcode is SIPUSH, operand value should be between + * Short.MIN_VALUE and Short.MAX_VALUE.<br> + * When opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. + */ + void visitIntInsn(int opcode, int operand); + + /** + * Visits a local variable instruction. A local variable instruction is an + * instruction that loads or stores the value of a local variable. + * + * @param opcode the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, + * LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var the operand of the instruction to be visited. This operand is + * the index of a local variable. + */ + void visitVarInsn(int opcode, int var); + + /** + * Visits a type instruction. A type instruction is an instruction that + * takes a type descriptor as parameter. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param desc the operand of the instruction to be visited. This operand is + * must be a fully qualified class name in internal form, or the type + * descriptor of an array type (see {@link Type Type}). + */ + void visitTypeInsn(int opcode, String desc); + + /** + * Visits a field instruction. A field instruction is an instruction that + * loads or stores the value of a field of an object. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner the internal name of the field's owner class (see {@link + * Type#getInternalName() getInternalName}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type Type}). + */ + void visitFieldInsn(int opcode, String owner, String name, String desc); + + /** + * Visits a method instruction. A method instruction is an instruction that + * invokes a method. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner the internal name of the method's owner class (see {@link + * Type#getInternalName() getInternalName}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + */ + void visitMethodInsn(int opcode, String owner, String name, String desc); + + /** + * Visits a jump instruction. A jump instruction is an instruction that may + * jump to another instruction. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either 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 visited. This operand + * is a label that designates the instruction to which the jump + * instruction may jump. + */ + void visitJumpInsn(int opcode, Label label); + + /** + * Visits a label. A label designates the instruction that will be visited + * just after it. + * + * @param label a {@link Label Label} object. + */ + void visitLabel(Label label); + + // ------------------------------------------------------------------------- + // Special instructions + // ------------------------------------------------------------------------- + + /** + * Visits a LDC instruction. + * + * @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} a {@link String} (or a {@link Type} for + * <tt>.class</tt> constants, for classes whose version is 49.0 or + * more). + */ + void visitLdcInsn(Object cst); + + /** + * Visits an IINC instruction. + * + * @param var index of the local variable to be incremented. + * @param increment amount to increment the local variable by. + */ + void visitIincInsn(int var, int increment); + + /** + * Visits a TABLESWITCH instruction. + * + * @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. + */ + void visitTableSwitchInsn(int min, int max, Label dflt, Label labels[]); + + /** + * Visits a LOOKUPSWITCH instruction. + * + * @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. + */ + void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]); + + /** + * Visits a MULTIANEWARRAY instruction. + * + * @param desc an array type descriptor (see {@link Type Type}). + * @param dims number of dimensions of the array to allocate. + */ + void visitMultiANewArrayInsn(String desc, int dims); + + // ------------------------------------------------------------------------- + // Exceptions table entries, debug information, + // max stack size and max locals + // ------------------------------------------------------------------------- + + /** + * Visits a try catch block. + * + * @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). + */ + void visitTryCatchBlock(Label start, Label end, Label handler, String type); + + /** + * Visits a local variable declaration. + * + * @param name the name of a local variable. + * @param desc the type descriptor of this local variable. + * @param signature the type signature of this local variable. May be + * <tt>null</tt> if the local variable type does not use generic + * types. + * @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. + * @throws IllegalArgumentException if one of the labels has not already + * been visited by this visitor (by the + * {@link #visitLabel visitLabel} method). + */ + void visitLocalVariable( + String name, + String desc, + String signature, + Label start, + Label end, + int index); + + /** + * Visits a line number declaration. + * + * @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. + * @throws IllegalArgumentException if <tt>start</tt> has not already been + * visited by this visitor (by the {@link #visitLabel visitLabel} + * method). + */ + void visitLineNumber(int line, Label start); + + /** + * Visits the maximum stack size and the maximum number of local variables + * of the method. + * + * @param maxStack maximum stack size of the method. + * @param maxLocals maximum number of local variables for the method. + */ + void visitMaxs(int maxStack, int maxLocals); + + /** + * Visits the end of the method. This method, which is the last one to be + * called, is used to inform the visitor that all the annotations and + * attributes of the method have been visited. + */ + void visitEnd(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodWriter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodWriter.java new file mode 100644 index 000000000..5b841d5fc --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/MethodWriter.java @@ -0,0 +1,2022 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A {@link MethodVisitor} that generates methods in bytecode form. Each visit + * method of this class appends the bytecode corresponding to the visited + * instruction to a byte vector, in the order these methods are called. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +class MethodWriter implements MethodVisitor { + + /** + * Next method writer (see {@link ClassWriter#firstMethod firstMethod}). + */ + MethodWriter next; + + /** + * The class writer to which this method must be added. + */ + ClassWriter cw; + + /** + * Access flags of this method. + */ + private int access; + + /** + * The index of the constant pool item that contains the name of this + * method. + */ + private int name; + + /** + * The index of the constant pool item that contains the descriptor of this + * method. + */ + private int desc; + + /** + * The descriptor of this method. + */ + private String descriptor; + + /** + * If not zero, indicates that the code of this method must be copied from + * the ClassReader associated to this writer in <code>cw.cr</code>. More + * precisely, this field gives the index of the first byte to copied from + * <code>cw.cr.b</code>. + */ + int classReaderOffset; + + /** + * If not zero, indicates that the code of this method must be copied from + * the ClassReader associated to this writer in <code>cw.cr</code>. More + * precisely, this field gives the number of bytes to copied from + * <code>cw.cr.b</code>. + */ + int classReaderLength; + + /** + * The signature of this method. + */ + String signature; + + /** + * Number of exceptions that can be thrown by this method. + */ + int exceptionCount; + + /** + * The exceptions that can be thrown by this method. More precisely, this + * array contains the indexes of the constant pool items that contain the + * internal names of these exception classes. + */ + int[] exceptions; + + /** + * The annotation default attribute of this method. May be <tt>null</tt>. + */ + private ByteVector annd; + + /** + * The runtime visible annotations of this method. May be <tt>null</tt>. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this method. May be <tt>null</tt>. + */ + private AnnotationWriter ianns; + + /** + * The runtime visible parameter annotations of this method. May be + * <tt>null</tt>. + */ + private AnnotationWriter[] panns; + + /** + * The runtime invisible parameter annotations of this method. May be + * <tt>null</tt>. + */ + private AnnotationWriter[] ipanns; + + /** + * The non standard attributes of the method. + */ + private Attribute attrs; + + /** + * The bytecode of this method. + */ + private ByteVector code = new ByteVector(); + + /** + * Maximum stack size of this method. + */ + private int maxStack; + + /** + * Maximum number of local variables for this method. + */ + private int maxLocals; + + /** + * Number of entries in the catch table of this method. + */ + private int catchCount; + + /** + * The catch table of this method. + */ + private Handler catchTable; + + /** + * The last element in the catchTable handler list. + */ + private Handler lastHandler; + + /** + * Number of entries in the LocalVariableTable attribute. + */ + private int localVarCount; + + /** + * The LocalVariableTable attribute. + */ + private ByteVector localVar; + + /** + * Number of entries in the LocalVariableTypeTable attribute. + */ + private int localVarTypeCount; + + /** + * The LocalVariableTypeTable attribute. + */ + private ByteVector localVarType; + + /** + * Number of entries in the LineNumberTable attribute. + */ + private int lineNumberCount; + + /** + * The LineNumberTable attribute. + */ + private ByteVector lineNumber; + + /** + * The non standard attributes of the method's code. + */ + private Attribute cattrs; + + /** + * Indicates if some jump instructions are too small and need to be resized. + */ + private boolean resize; + + /* + * Fields for the control flow graph analysis algorithm (used to compute the + * maximum stack size). A control flow graph contains one node per "basic + * block", and one edge per "jump" from one basic block to another. Each + * node (i.e., each basic block) is represented by the Label object that + * corresponds to the first instruction of this basic block. Each node also + * stores the list of its successors in the graph, as a linked list of Edge + * objects. + */ + + /** + * <tt>true</tt> if the maximum stack size and number of local variables + * must be automatically computed. + */ + private final boolean computeMaxs; + + /** + * The (relative) stack size after the last visited instruction. This size + * is relative to the beginning of the current basic block, i.e., the true + * stack size after the last visited instruction is equal to the {@link + * Label#beginStackSize beginStackSize} of the current basic block plus + * <tt>stackSize</tt>. + */ + private int stackSize; + + /** + * The (relative) maximum stack size after the last visited instruction. + * This size is relative to the beginning of the current basic block, i.e., + * the true maximum stack size after the last visited instruction is equal + * to the {@link Label#beginStackSize beginStackSize} of the current basic + * block plus <tt>stackSize</tt>. + */ + private int maxStackSize; + + /** + * The current basic block. This block is the basic block to which the next + * instruction to be visited must be added. + */ + private Label currentBlock; + + /** + * The basic block stack used by the control flow analysis algorithm. This + * stack is represented by a linked list of {@link Label Label} objects, + * linked to each other by their {@link Label#next} field. This stack must + * not be confused with the JVM stack used to execute the JVM instructions! + */ + private Label blockStack; + + /** + * The stack size variation corresponding to each JVM instruction. This + * stack variation is equal to the size of the values produced by an + * instruction, minus the size of the values consumed by this instruction. + */ + private final static int[] SIZE; + + // ------------------------------------------------------------------------ + // Static initializer + // ------------------------------------------------------------------------ + + /** + * Computes the stack size variation corresponding to each JVM instruction. + */ + static { + int i; + int[] b = new int[202]; + String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" + + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" + + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" + + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; + for (i = 0; i < b.length; ++i) { + b[i] = s.charAt(i) - 'E'; + } + SIZE = b; + + // code to generate the above string + // + // int NA = 0; // not applicable (unused opcode or variable size opcode) + // + // b = new int[] { + // 0, //NOP, // visitInsn + // 1, //ACONST_NULL, // - + // 1, //ICONST_M1, // - + // 1, //ICONST_0, // - + // 1, //ICONST_1, // - + // 1, //ICONST_2, // - + // 1, //ICONST_3, // - + // 1, //ICONST_4, // - + // 1, //ICONST_5, // - + // 2, //LCONST_0, // - + // 2, //LCONST_1, // - + // 1, //FCONST_0, // - + // 1, //FCONST_1, // - + // 1, //FCONST_2, // - + // 2, //DCONST_0, // - + // 2, //DCONST_1, // - + // 1, //BIPUSH, // visitIntInsn + // 1, //SIPUSH, // - + // 1, //LDC, // visitLdcInsn + // NA, //LDC_W, // - + // NA, //LDC2_W, // - + // 1, //ILOAD, // visitVarInsn + // 2, //LLOAD, // - + // 1, //FLOAD, // - + // 2, //DLOAD, // - + // 1, //ALOAD, // - + // NA, //ILOAD_0, // - + // NA, //ILOAD_1, // - + // NA, //ILOAD_2, // - + // NA, //ILOAD_3, // - + // NA, //LLOAD_0, // - + // NA, //LLOAD_1, // - + // NA, //LLOAD_2, // - + // NA, //LLOAD_3, // - + // NA, //FLOAD_0, // - + // NA, //FLOAD_1, // - + // NA, //FLOAD_2, // - + // NA, //FLOAD_3, // - + // NA, //DLOAD_0, // - + // NA, //DLOAD_1, // - + // NA, //DLOAD_2, // - + // NA, //DLOAD_3, // - + // NA, //ALOAD_0, // - + // NA, //ALOAD_1, // - + // NA, //ALOAD_2, // - + // NA, //ALOAD_3, // - + // -1, //IALOAD, // visitInsn + // 0, //LALOAD, // - + // -1, //FALOAD, // - + // 0, //DALOAD, // - + // -1, //AALOAD, // - + // -1, //BALOAD, // - + // -1, //CALOAD, // - + // -1, //SALOAD, // - + // -1, //ISTORE, // visitVarInsn + // -2, //LSTORE, // - + // -1, //FSTORE, // - + // -2, //DSTORE, // - + // -1, //ASTORE, // - + // NA, //ISTORE_0, // - + // NA, //ISTORE_1, // - + // NA, //ISTORE_2, // - + // NA, //ISTORE_3, // - + // NA, //LSTORE_0, // - + // NA, //LSTORE_1, // - + // NA, //LSTORE_2, // - + // NA, //LSTORE_3, // - + // NA, //FSTORE_0, // - + // NA, //FSTORE_1, // - + // NA, //FSTORE_2, // - + // NA, //FSTORE_3, // - + // NA, //DSTORE_0, // - + // NA, //DSTORE_1, // - + // NA, //DSTORE_2, // - + // NA, //DSTORE_3, // - + // NA, //ASTORE_0, // - + // NA, //ASTORE_1, // - + // NA, //ASTORE_2, // - + // NA, //ASTORE_3, // - + // -3, //IASTORE, // visitInsn + // -4, //LASTORE, // - + // -3, //FASTORE, // - + // -4, //DASTORE, // - + // -3, //AASTORE, // - + // -3, //BASTORE, // - + // -3, //CASTORE, // - + // -3, //SASTORE, // - + // -1, //POP, // - + // -2, //POP2, // - + // 1, //DUP, // - + // 1, //DUP_X1, // - + // 1, //DUP_X2, // - + // 2, //DUP2, // - + // 2, //DUP2_X1, // - + // 2, //DUP2_X2, // - + // 0, //SWAP, // - + // -1, //IADD, // - + // -2, //LADD, // - + // -1, //FADD, // - + // -2, //DADD, // - + // -1, //ISUB, // - + // -2, //LSUB, // - + // -1, //FSUB, // - + // -2, //DSUB, // - + // -1, //IMUL, // - + // -2, //LMUL, // - + // -1, //FMUL, // - + // -2, //DMUL, // - + // -1, //IDIV, // - + // -2, //LDIV, // - + // -1, //FDIV, // - + // -2, //DDIV, // - + // -1, //IREM, // - + // -2, //LREM, // - + // -1, //FREM, // - + // -2, //DREM, // - + // 0, //INEG, // - + // 0, //LNEG, // - + // 0, //FNEG, // - + // 0, //DNEG, // - + // -1, //ISHL, // - + // -1, //LSHL, // - + // -1, //ISHR, // - + // -1, //LSHR, // - + // -1, //IUSHR, // - + // -1, //LUSHR, // - + // -1, //IAND, // - + // -2, //LAND, // - + // -1, //IOR, // - + // -2, //LOR, // - + // -1, //IXOR, // - + // -2, //LXOR, // - + // 0, //IINC, // visitIincInsn + // 1, //I2L, // visitInsn + // 0, //I2F, // - + // 1, //I2D, // - + // -1, //L2I, // - + // -1, //L2F, // - + // 0, //L2D, // - + // 0, //F2I, // - + // 1, //F2L, // - + // 1, //F2D, // - + // -1, //D2I, // - + // 0, //D2L, // - + // -1, //D2F, // - + // 0, //I2B, // - + // 0, //I2C, // - + // 0, //I2S, // - + // -3, //LCMP, // - + // -1, //FCMPL, // - + // -1, //FCMPG, // - + // -3, //DCMPL, // - + // -3, //DCMPG, // - + // -1, //IFEQ, // visitJumpInsn + // -1, //IFNE, // - + // -1, //IFLT, // - + // -1, //IFGE, // - + // -1, //IFGT, // - + // -1, //IFLE, // - + // -2, //IF_ICMPEQ, // - + // -2, //IF_ICMPNE, // - + // -2, //IF_ICMPLT, // - + // -2, //IF_ICMPGE, // - + // -2, //IF_ICMPGT, // - + // -2, //IF_ICMPLE, // - + // -2, //IF_ACMPEQ, // - + // -2, //IF_ACMPNE, // - + // 0, //GOTO, // - + // 1, //JSR, // - + // 0, //RET, // visitVarInsn + // -1, //TABLESWITCH, // visiTableSwitchInsn + // -1, //LOOKUPSWITCH, // visitLookupSwitch + // -1, //IRETURN, // visitInsn + // -2, //LRETURN, // - + // -1, //FRETURN, // - + // -2, //DRETURN, // - + // -1, //ARETURN, // - + // 0, //RETURN, // - + // NA, //GETSTATIC, // visitFieldInsn + // NA, //PUTSTATIC, // - + // NA, //GETFIELD, // - + // NA, //PUTFIELD, // - + // NA, //INVOKEVIRTUAL, // visitMethodInsn + // NA, //INVOKESPECIAL, // - + // NA, //INVOKESTATIC, // - + // NA, //INVOKEINTERFACE, // - + // NA, //UNUSED, // NOT VISITED + // 1, //NEW, // visitTypeInsn + // 0, //NEWARRAY, // visitIntInsn + // 0, //ANEWARRAY, // visitTypeInsn + // 0, //ARRAYLENGTH, // visitInsn + // NA, //ATHROW, // - + // 0, //CHECKCAST, // visitTypeInsn + // 0, //INSTANCEOF, // - + // -1, //MONITORENTER, // visitInsn + // -1, //MONITOREXIT, // - + // NA, //WIDE, // NOT VISITED + // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn + // -1, //IFNULL, // visitJumpInsn + // -1, //IFNONNULL, // - + // NA, //GOTO_W, // - + // NA, //JSR_W, // - + // }; + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('E' + b[i])); + // } + // System.err.println(); + } + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link MethodWriter}. + * + * @param cw the class writer in which the method must be added. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type}). + * @param signature the method's signature. May be <tt>null</tt>. + * @param exceptions the internal names of the method's exceptions. May be + * <tt>null</tt>. + * @param computeMaxs <tt>true</tt> if the maximum stack size and number + * of local variables must be automatically computed. + */ + MethodWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions, + final boolean computeMaxs) + { + if (cw.firstMethod == null) { + cw.firstMethod = this; + } else { + cw.lastMethod.next = this; + } + cw.lastMethod = this; + this.cw = cw; + this.access = access; + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + this.descriptor = desc; + this.signature = signature; + if (exceptions != null && exceptions.length > 0) { + exceptionCount = exceptions.length; + this.exceptions = new int[exceptionCount]; + for (int i = 0; i < exceptionCount; ++i) { + this.exceptions[i] = cw.newClass(exceptions[i]); + } + } + this.computeMaxs = computeMaxs; + if (computeMaxs) { + // updates maxLocals + int size = getArgumentsAndReturnSizes(desc) >> 2; + if ((access & Opcodes.ACC_STATIC) != 0) { + --size; + } + maxLocals = size; + // pushes the first block onto the stack of blocks to be visited + currentBlock = new Label(); + currentBlock.pushed = true; + blockStack = currentBlock; + } + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor interface + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotationDefault() { + annd = new ByteVector(); + return new AnnotationWriter(cw, false, annd, null, 0); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + if (panns == null) { + panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = panns[parameter]; + panns[parameter] = aw; + } else { + if (ipanns == null) { + ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = ipanns[parameter]; + ipanns[parameter] = aw; + } + return aw; + } + + public void visitAttribute(final Attribute attr) { + if (attr.isCodeAttribute()) { + attr.next = cattrs; + cattrs = attr; + } else { + attr.next = attrs; + attrs = attr; + } + } + + public void visitCode() { + } + + public void visitInsn(final int opcode) { + if (computeMaxs) { + // updates current and max stack sizes + int size = stackSize + SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + // if opcode == ATHROW or xRETURN, ends current block (no successor) + if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) + || opcode == Opcodes.ATHROW) + { + if (currentBlock != null) { + currentBlock.maxStackSize = maxStackSize; + currentBlock = null; + } + } + } + // adds the instruction to the bytecode of the method + code.putByte(opcode); + } + + public void visitIntInsn(final int opcode, final int operand) { + if (computeMaxs && opcode != Opcodes.NEWARRAY) { + // updates current and max stack sizes only if opcode == NEWARRAY + // (stack size variation = 0 for BIPUSH or SIPUSH) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // adds the instruction to the bytecode of the method + if (opcode == Opcodes.SIPUSH) { + code.put12(opcode, operand); + } else { // BIPUSH or NEWARRAY + code.put11(opcode, operand); + } + } + + public void visitVarInsn(final int opcode, final int var) { + if (computeMaxs) { + // updates current and max stack sizes + if (opcode == Opcodes.RET) { + // no stack change, but end of current block (no successor) + if (currentBlock != null) { + currentBlock.maxStackSize = maxStackSize; + currentBlock = null; + } + } else { // xLOAD or xSTORE + int size = stackSize + SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // updates max locals + int n; + if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD + || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) + { + n = var + 2; + } else { + n = var + 1; + } + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if (var < 4 && opcode != Opcodes.RET) { + int opt; + if (opcode < Opcodes.ISTORE) { + /* ILOAD_0 */ + opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; + } else { + /* ISTORE_0 */ + opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; + } + code.putByte(opt); + } else if (var >= 256) { + code.putByte(196 /* WIDE */).put12(opcode, var); + } else { + code.put11(opcode, var); + } + } + + public void visitTypeInsn(final int opcode, final String desc) { + if (computeMaxs && opcode == Opcodes.NEW) { + // updates current and max stack sizes only if opcode == NEW + // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // adds the instruction to the bytecode of the method + code.put12(opcode, cw.newClass(desc)); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + if (computeMaxs) { + int size; + // computes the stack size variation + char c = desc.charAt(0); + switch (opcode) { + case Opcodes.GETSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); + break; + // case Constants.PUTFIELD: + default: + size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); + break; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // adds the instruction to the bytecode of the method + code.put12(opcode, cw.newField(owner, name, desc)); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + Item i = cw.newMethodItem(owner, name, desc, itf); + int argSize = i.intVal; + if (computeMaxs) { + /* + * computes the stack size variation. In order not to recompute + * several times this variation for the same Item, we use the intVal + * field of this item to store this variation, once it has been + * computed. More precisely this intVal field stores the sizes of + * the arguments and of the return value corresponding to desc. + */ + if (argSize == 0) { + // the above sizes have not been computed yet, so we compute + // them... + argSize = getArgumentsAndReturnSizes(desc); + // ... and we save them in order not to recompute them in the + // future + i.intVal = argSize; + } + int size; + if (opcode == Opcodes.INVOKESTATIC) { + size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; + } else { + size = stackSize - (argSize >> 2) + (argSize & 0x03); + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // adds the instruction to the bytecode of the method + if (itf) { + if (!computeMaxs) { + if (argSize == 0) { + argSize = getArgumentsAndReturnSizes(desc); + i.intVal = argSize; + } + } + code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); + } else { + code.put12(opcode, i.index); + } + } + + public void visitJumpInsn(final int opcode, final Label label) { + if (computeMaxs) { + if (opcode == Opcodes.GOTO) { + // no stack change, but end of current block (with one new + // successor) + if (currentBlock != null) { + currentBlock.maxStackSize = maxStackSize; + addSuccessor(stackSize, label); + currentBlock = null; + } + } else if (opcode == Opcodes.JSR) { + if (currentBlock != null) { + addSuccessor(stackSize + 1, label); + } + } else { + // updates current stack size (max stack size unchanged because + // stack size variation always negative in this case) + stackSize += SIZE[opcode]; + if (currentBlock != null) { + addSuccessor(stackSize, label); + } + } + } + // adds the instruction to the bytecode of the method + if (label.resolved && label.position - code.length < Short.MIN_VALUE) { + /* + * case of a backward jump with an offset < -32768. In this case we + * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx + * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the + * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'> + * designates the instruction just after the GOTO_W. + */ + if (opcode == Opcodes.GOTO) { + code.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + code.putByte(201); // JSR_W + } else { + code.putByte(opcode <= 166 + ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1); + code.putShort(8); // jump offset + code.putByte(200); // GOTO_W + } + label.put(this, code, code.length - 1, true); + } else { + /* + * case of a backward jump with an offset >= -32768, or of a forward + * jump with, of course, an unknown offset. In these cases we store + * the offset in 2 bytes (which will be increased in + * resizeInstructions, if needed). + */ + code.putByte(opcode); + label.put(this, code, code.length - 1, false); + } + } + + public void visitLabel(final Label label) { + if (computeMaxs) { + if (currentBlock != null) { + // ends current block (with one new successor) + currentBlock.maxStackSize = maxStackSize; + addSuccessor(stackSize, label); + } + // begins a new current block, + // resets the relative current and max stack sizes + currentBlock = label; + stackSize = 0; + maxStackSize = 0; + } + // resolves previous forward references to label, if any + resize |= label.resolve(this, code.length, code.data); + } + + public void visitLdcInsn(final Object cst) { + Item i = cw.newConstItem(cst); + if (computeMaxs) { + int size; + // computes the stack size variation + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { + size = stackSize + 2; + } else { + size = stackSize + 1; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // adds the instruction to the bytecode of the method + int index = i.index; + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { + code.put12(20 /* LDC2_W */, index); + } else if (index >= 256) { + code.put12(19 /* LDC_W */, index); + } else { + code.put11(Opcodes.LDC, index); + } + } + + public void visitIincInsn(final int var, final int increment) { + if (computeMaxs) { + // updates max locals only (no stack change) + int n = var + 1; + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if ((var > 255) || (increment > 127) || (increment < -128)) { + code.putByte(196 /* WIDE */) + .put12(Opcodes.IINC, var) + .putShort(increment); + } else { + code.putByte(Opcodes.IINC).put11(var, increment); + } + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label labels[]) + { + if (computeMaxs) { + // updates current stack size (max stack size unchanged) + --stackSize; + // ends current block (with many new successors) + if (currentBlock != null) { + currentBlock.maxStackSize = maxStackSize; + addSuccessor(stackSize, dflt); + for (int i = 0; i < labels.length; ++i) { + addSuccessor(stackSize, labels[i]); + } + currentBlock = null; + } + } + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.TABLESWITCH); + while (code.length % 4 != 0) { + code.putByte(0); + } + dflt.put(this, code, source, true); + code.putInt(min).putInt(max); + for (int i = 0; i < labels.length; ++i) { + labels[i].put(this, code, source, true); + } + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int keys[], + final Label labels[]) + { + if (computeMaxs) { + // updates current stack size (max stack size unchanged) + --stackSize; + // ends current block (with many new successors) + if (currentBlock != null) { + currentBlock.maxStackSize = maxStackSize; + addSuccessor(stackSize, dflt); + for (int i = 0; i < labels.length; ++i) { + addSuccessor(stackSize, labels[i]); + } + currentBlock = null; + } + } + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.LOOKUPSWITCH); + while (code.length % 4 != 0) { + code.putByte(0); + } + dflt.put(this, code, source, true); + code.putInt(labels.length); + for (int i = 0; i < labels.length; ++i) { + code.putInt(keys[i]); + labels[i].put(this, code, source, true); + } + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + if (computeMaxs) { + // updates current stack size (max stack size unchanged because + // stack size variation always negative or null) + stackSize += 1 - dims; + } + // adds the instruction to the bytecode of the method + code.put12(Opcodes.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + if (computeMaxs) { + // pushes handler block onto the stack of blocks to be visited + if (!handler.pushed) { + handler.beginStackSize = 1; + handler.pushed = true; + handler.next = blockStack; + blockStack = handler; + } + } + ++catchCount; + Handler h = new Handler(); + h.start = start; + h.end = end; + h.handler = handler; + h.desc = type; + h.type = type != null ? cw.newClass(type) : 0; + if (lastHandler == null) { + catchTable = h; + } else { + lastHandler.next = h; + } + lastHandler = h; + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + if (signature != null) { + if (localVarType == null) { + localVarType = new ByteVector(); + } + ++localVarTypeCount; + localVarType.putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(signature)) + .putShort(index); + } + if (localVar == null) { + localVar = new ByteVector(); + } + ++localVarCount; + localVar.putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(desc)) + .putShort(index); + + if(computeMaxs) { + // updates max locals + char c = desc.charAt(0); + int n = index + ( c=='L' || c=='D' ? 2 : 1); + if (n > maxLocals) { + maxLocals = n; + } + } + } + + public void visitLineNumber(final int line, final Label start) { + if (lineNumber == null) { + lineNumber = new ByteVector(); + } + ++lineNumberCount; + lineNumber.putShort(start.position); + lineNumber.putShort(line); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + if (computeMaxs) { + // true (non relative) max stack size + int max = 0; + /* + * control flow analysis algorithm: while the block stack is not + * empty, pop a block from this stack, update the max stack size, + * compute the true (non relative) begin stack size of the + * successors of this block, and push these successors onto the + * stack (unless they have already been pushed onto the stack). + * Note: by hypothesis, the {@link Label#beginStackSize} of the + * blocks in the block stack are the true (non relative) beginning + * stack sizes of these blocks. + */ + Label stack = blockStack; + while (stack != null) { + // pops a block from the stack + Label l = stack; + stack = stack.next; + // computes the true (non relative) max stack size of this block + int start = l.beginStackSize; + int blockMax = start + l.maxStackSize; + // updates the global max stack size + if (blockMax > max) { + max = blockMax; + } + // analyses the successors of the block + Edge b = l.successors; + while (b != null) { + l = b.successor; + // if this successor has not already been pushed onto the + // stack... + if (!l.pushed) { + // computes the true beginning stack size of this + // successor block + l.beginStackSize = start + b.stackSize; + // pushes this successor onto the stack + l.pushed = true; + l.next = stack; + stack = l; + } + b = b.next; + } + } + this.maxStack = max; + } else { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + } + + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Utility methods: control flow analysis algorithm + // ------------------------------------------------------------------------ + + /** + * Computes the size of the arguments and of the return value of a method. + * + * @param desc the descriptor of a method. + * @return the size of the arguments of the method (plus one for the + * implicit this argument), argSize, and the size of its return + * value, retSize, packed into a single int i = + * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal + * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). + */ + private static int getArgumentsAndReturnSizes(final String desc) { + int n = 1; + int c = 1; + while (true) { + char car = desc.charAt(c++); + if (car == ')') { + car = desc.charAt(c); + return n << 2 + | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); + } else if (car == 'L') { + while (desc.charAt(c++) != ';') { + } + n += 1; + } else if (car == '[') { + while ((car = desc.charAt(c)) == '[') { + ++c; + } + if (car == 'D' || car == 'J') { + n -= 1; + } + } else if (car == 'D' || car == 'J') { + n += 2; + } else { + n += 1; + } + } + } + + /** + * Adds a successor to the {@link #currentBlock currentBlock} block. + * + * @param stackSize the current (relative) stack size in the current block. + * @param successor the successor block to be added to the current block. + */ + private void addSuccessor(final int stackSize, final Label successor) { + Edge b = new Edge(); + // initializes the previous Edge object... + b.stackSize = stackSize; + b.successor = successor; + // ...and adds it to the successor list of the currentBlock block + b.next = currentBlock.successors; + currentBlock.successors = b; + } + + // ------------------------------------------------------------------------ + // Utility methods: dump bytecode array + // ------------------------------------------------------------------------ + + /** + * Returns the size of the bytecode of this method. + * + * @return the size of the bytecode of this method. + */ + final int getSize() { + if (classReaderOffset != 0) { + return 6 + classReaderLength; + } + if (resize) { + // replaces the temporary jump opcodes introduced by Label.resolve. + resizeInstructions(new int[0], new int[0], 0); + } + int size = 8; + if (code.length > 0) { + cw.newUTF8("Code"); + size += 18 + code.length + 8 * catchCount; + if (localVar != null) { + cw.newUTF8("LocalVariableTable"); + size += 8 + localVar.length; + } + if (localVarType != null) { + cw.newUTF8("LocalVariableTypeTable"); + size += 8 + localVarType.length; + } + if (lineNumber != null) { + cw.newUTF8("LineNumberTable"); + size += 8 + lineNumber.length; + } + if (cattrs != null) { + size += cattrs.getSize(cw, + code.data, + code.length, + maxStack, + maxLocals); + } + } + if (exceptionCount > 0) { + cw.newUTF8("Exceptions"); + size += 8 + 2 * exceptionCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + cw.newUTF8("Synthetic"); + size += 6; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (cw.version == Opcodes.V1_4) { + if ((access & Opcodes.ACC_VARARGS) != 0) { + cw.newUTF8("Varargs"); + size += 6; + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + cw.newUTF8("Bridge"); + size += 6; + } + } + if (signature != null) { + cw.newUTF8("Signature"); + cw.newUTF8(signature); + size += 8; + } + if (annd != null) { + cw.newUTF8("AnnotationDefault"); + size += 6 + annd.length; + } + if (anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (panns != null) { + cw.newUTF8("RuntimeVisibleParameterAnnotations"); + size += 7 + 2 * panns.length; + for (int i = panns.length - 1; i >= 0; --i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + } + if (ipanns != null) { + cw.newUTF8("RuntimeInvisibleParameterAnnotations"); + size += 7 + 2 * ipanns.length; + for (int i = ipanns.length - 1; i >= 0; --i) { + size += ipanns[i] == null ? 0 : ipanns[i].getSize(); + } + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the bytecode of this method in the given byte vector. + * + * @param out the byte vector into which the bytecode of this method must be + * copied. + */ + final void put(final ByteVector out) { + out.putShort(access).putShort(name).putShort(desc); + if (classReaderOffset != 0) { + out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); + return; + } + int attributeCount = 0; + if (code.length > 0) { + ++attributeCount; + } + if (exceptionCount > 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + ++attributeCount; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (cw.version == Opcodes.V1_4) { + if ((access & Opcodes.ACC_VARARGS) != 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + ++attributeCount; + } + } + if (signature != null) { + ++attributeCount; + } + if (annd != null) { + ++attributeCount; + } + if (anns != null) { + ++attributeCount; + } + if (ianns != null) { + ++attributeCount; + } + if (panns != null) { + ++attributeCount; + } + if (ipanns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (code.length > 0) { + int size = 12 + code.length + 8 * catchCount; + if (localVar != null) { + size += 8 + localVar.length; + } + if (localVarType != null) { + size += 8 + localVarType.length; + } + if (lineNumber != null) { + size += 8 + lineNumber.length; + } + if (cattrs != null) { + size += cattrs.getSize(cw, + code.data, + code.length, + maxStack, + maxLocals); + } + out.putShort(cw.newUTF8("Code")).putInt(size); + out.putShort(maxStack).putShort(maxLocals); + out.putInt(code.length).putByteArray(code.data, 0, code.length); + out.putShort(catchCount); + if (catchCount > 0) { + Handler h = catchTable; + while (h != null) { + out.putShort(h.start.position) + .putShort(h.end.position) + .putShort(h.handler.position) + .putShort(h.type); + h = h.next; + } + } + attributeCount = 0; + if (localVar != null) { + ++attributeCount; + } + if (localVarType != null) { + ++attributeCount; + } + if (lineNumber != null) { + ++attributeCount; + } + if (cattrs != null) { + attributeCount += cattrs.getCount(); + } + out.putShort(attributeCount); + if (localVar != null) { + out.putShort(cw.newUTF8("LocalVariableTable")); + out.putInt(localVar.length + 2).putShort(localVarCount); + out.putByteArray(localVar.data, 0, localVar.length); + } + if (localVarType != null) { + out.putShort(cw.newUTF8("LocalVariableTypeTable")); + out.putInt(localVarType.length + 2).putShort(localVarTypeCount); + out.putByteArray(localVarType.data, 0, localVarType.length); + } + if (lineNumber != null) { + out.putShort(cw.newUTF8("LineNumberTable")); + out.putInt(lineNumber.length + 2).putShort(lineNumberCount); + out.putByteArray(lineNumber.data, 0, lineNumber.length); + } + if (cattrs != null) { + cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); + } + } + if (exceptionCount > 0) { + out.putShort(cw.newUTF8("Exceptions")) + .putInt(2 * exceptionCount + 2); + out.putShort(exceptionCount); + for (int i = 0; i < exceptionCount; ++i) { + out.putShort(exceptions[i]); + } + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && (cw.version & 0xffff) < Opcodes.V1_5) + { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (cw.version == Opcodes.V1_4) { + if ((access & Opcodes.ACC_VARARGS) != 0) { + out.putShort(cw.newUTF8("Varargs")).putInt(0); + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + out.putShort(cw.newUTF8("Bridge")).putInt(0); + } + } + if (signature != null) { + out.putShort(cw.newUTF8("Signature")) + .putInt(2) + .putShort(cw.newUTF8(signature)); + } + if (annd != null) { + out.putShort(cw.newUTF8("AnnotationDefault")); + out.putInt(annd.length); + out.putByteArray(annd.data, 0, annd.length); + } + if (anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (panns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); + AnnotationWriter.put(panns, out); + } + if (ipanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); + AnnotationWriter.put(ipanns, out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } + + // ------------------------------------------------------------------------ + // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) + // ------------------------------------------------------------------------ + + /** + * Resizes the designated instructions, while keeping jump offsets and + * instruction addresses consistent. This may require to resize other + * existing instructions, or even to introduce new instructions: for + * example, increasing the size of an instruction by 2 at the middle of a + * method can increases the offset of an IFEQ instruction from 32766 to + * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W + * 32765. This, in turn, may require to increase the size of another jump + * instruction, and so on... All these operations are handled automatically + * by this method. <p> <i>This method must be called after all the method + * that is being built has been visited</i>. In particular, the + * {@link Label Label} objects used to construct the method are no longer + * valid after this method has been called. + * + * @param indexes current positions of the instructions to be resized. Each + * instruction must be designated by the index of its <i>last</i> + * byte, plus one (or, in other words, by the index of the <i>first</i> + * byte of the <i>next</i> instruction). + * @param sizes the number of bytes to be <i>added</i> to the above + * instructions. More precisely, for each i < <tt>len</tt>, + * <tt>sizes</tt>[i] bytes will be added at the end of the + * instruction designated by <tt>indexes</tt>[i] or, if + * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| + * bytes of the instruction will be removed (the instruction size + * <i>must not</i> become negative or null). The gaps introduced by + * this method must be filled in "manually" in {@link #code code} + * method. + * @param len the number of instruction to be resized. Must be smaller than + * or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length. + * @return the <tt>indexes</tt> array, which now contains the new + * positions of the resized instructions (designated as above). + */ + private int[] resizeInstructions( + final int[] indexes, + final int[] sizes, + final int len) + { + byte[] b = code.data; // bytecode of the method + int u, v, label; // indexes in b + int i, j; // loop indexes + + /* + * 1st step: As explained above, resizing an instruction may require to + * resize another one, which may require to resize yet another one, and + * so on. The first step of the algorithm consists in finding all the + * instructions that need to be resized, without modifying the code. + * This is done by the following "fix point" algorithm: + * + * Parse the code to find the jump instructions whose offset will need + * more than 2 bytes to be stored (the future offset is computed from + * the current offset and from the number of bytes that will be inserted + * or removed between the source and target instructions). For each such + * instruction, adds an entry in (a copy of) the indexes and sizes + * arrays (if this has not already been done in a previous iteration!). + * + * If at least one entry has been added during the previous step, go + * back to the beginning, otherwise stop. + * + * In fact the real algorithm is complicated by the fact that the size + * of TABLESWITCH and LOOKUPSWITCH instructions depends on their + * position in the bytecode (because of padding). In order to ensure the + * convergence of the algorithm, the number of bytes to be added or + * removed from these instructions is over estimated during the previous + * loop, and computed exactly only after the loop is finished (this + * requires another pass to parse the bytecode of the method). + */ + int[] allIndexes = new int[len]; // copy of indexes + int[] allSizes = new int[len]; // copy of sizes + boolean[] resize; // instructions to be resized + int newOffset; // future offset of a jump instruction + + System.arraycopy(indexes, 0, allIndexes, 0, len); + System.arraycopy(sizes, 0, allSizes, 0, len); + resize = new boolean[code.length]; + + // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done + int state = 3; + do { + if (state == 3) { + state = 2; + } + u = 0; + while (u < b.length) { + int opcode = b[u] & 0xFF; // opcode of current instruction + int insert = 0; // bytes to be added after this instruction + + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // converts temporary opcodes 202 to 217, 218 and + // 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (newOffset < Short.MIN_VALUE + || newOffset > Short.MAX_VALUE) + { + if (!resize[u]) { + if (opcode == Opcodes.GOTO + || opcode == Opcodes.JSR) + { + // two additional bytes will be required to + // replace this GOTO or JSR instruction with + // a GOTO_W or a JSR_W + insert = 2; + } else { + // five additional bytes will be required to + // replace this IFxxx <l> instruction with + // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx + // is the "opposite" opcode of IFxxx (i.e., + // IFNE for IFEQ) and where <l'> designates + // the instruction just after the GOTO_W. + insert = 5; + } + resize[u] = true; + } + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + u += 5; + break; + case ClassWriter.TABL_INSN: + if (state == 1) { + // true number of bytes to be added (or removed) + // from this instruction = (future number of padding + // bytes - current number of padding byte) - + // previously over estimated variation = + // = ((3 - newOffset%4) - (3 - u%4)) - u%4 + // = (-newOffset%4 + u%4) - u%4 + // = -(newOffset & 3) + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // over estimation of the number of bytes to be + // added to this instruction = 3 - current number + // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 + insert = u & 3; + resize[u] = true; + } + // skips instruction + u = u + 4 - (u & 3); + u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; + break; + case ClassWriter.LOOK_INSN: + if (state == 1) { + // like TABL_INSN + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // like TABL_INSN + insert = u & 3; + resize[u] = true; + } + // skips instruction + u = u + 4 - (u & 3); + u += 8 * readInt(b, u + 4) + 8; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + u += 5; + break; + // case ClassWriter.MANA_INSN: + default: + u += 4; + break; + } + if (insert != 0) { + // adds a new (u, insert) entry in the allIndexes and + // allSizes arrays + int[] newIndexes = new int[allIndexes.length + 1]; + int[] newSizes = new int[allSizes.length + 1]; + System.arraycopy(allIndexes, + 0, + newIndexes, + 0, + allIndexes.length); + System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); + newIndexes[allIndexes.length] = u; + newSizes[allSizes.length] = insert; + allIndexes = newIndexes; + allSizes = newSizes; + if (insert > 0) { + state = 3; + } + } + } + if (state < 3) { + --state; + } + } while (state != 0); + + // 2nd step: + // copies the bytecode of the method into a new bytevector, updates the + // offsets, and inserts (or removes) bytes as requested. + + ByteVector newCode = new ByteVector(code.length); + + u = 0; + while (u < code.length) { + for (i = allIndexes.length - 1; i >= 0; --i) { + if (allIndexes[i] == u) { + if (i < len) { + if (sizes[i] > 0) { + newCode.putByteArray(null, 0, sizes[i]); + } else { + newCode.length += sizes[i]; + } + indexes[i] = newCode.length; + } + } + } + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + newCode.putByte(opcode); + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // changes temporary opcodes 202 to 217 (inclusive), 218 + // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (resize[u]) { + // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx + // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where <l'> designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO) { + newCode.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + newCode.putByte(201); // JSR_W + } else { + newCode.putByte(opcode <= 166 + ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1); + newCode.putShort(8); // jump offset + newCode.putByte(200); // GOTO_W + // newOffset now computed from start of GOTO_W + newOffset -= 3; + } + newCode.putInt(newOffset); + } else { + newCode.putByte(opcode); + newCode.putShort(newOffset); + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + label = u + readInt(b, u + 1); + newOffset = getNewOffset(allIndexes, allSizes, u, label); + newCode.putByte(opcode); + newCode.putInt(newOffset); + u += 5; + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.TABLESWITCH); + while (newCode.length % 4 != 0) { + newCode.putByte(0); + } + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + j = readInt(b, u) - j + 1; + u += 4; + newCode.putInt(readInt(b, u - 4)); + for (; j > 0; --j) { + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.LOOKUPSWITCH); + while (newCode.length % 4 != 0) { + newCode.putByte(0); + } + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + for (; j > 0; --j) { + newCode.putInt(readInt(b, u)); + u += 4; + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + newCode.putByteArray(b, u, 6); + u += 6; + } else { + newCode.putByteArray(b, u, 4); + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + newCode.putByteArray(b, u, 2); + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + newCode.putByteArray(b, u, 3); + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + newCode.putByteArray(b, u, 5); + u += 5; + break; + // case MANA_INSN: + default: + newCode.putByteArray(b, u, 4); + u += 4; + break; + } + } + + // updates the exception handler block labels + Handler h = catchTable; + while (h != null) { + getNewOffset(allIndexes, allSizes, h.start); + getNewOffset(allIndexes, allSizes, h.end); + getNewOffset(allIndexes, allSizes, h.handler); + h = h.next; + } + for (i = 0; i < 2; ++i) { + ByteVector bv = i == 0 ? localVar : localVarType; + if (bv != null) { + b = bv.data; + u = 0; + while (u < bv.length) { + label = readUnsignedShort(b, u); + newOffset = getNewOffset(allIndexes, allSizes, 0, label); + writeShort(b, u, newOffset); + label += readUnsignedShort(b, u + 2); + newOffset = getNewOffset(allIndexes, allSizes, 0, label) + - newOffset; + writeShort(b, u + 2, newOffset); + u += 10; + } + } + } + if (lineNumber != null) { + b = lineNumber.data; + u = 0; + while (u < lineNumber.length) { + writeShort(b, u, getNewOffset(allIndexes, + allSizes, + 0, + readUnsignedShort(b, u))); + u += 4; + } + } + // updates the labels of the other attributes + while (cattrs != null) { + Label[] labels = cattrs.getLabels(); + if (labels != null) { + for (i = labels.length - 1; i >= 0; --i) { + if (!labels[i].resized) { + labels[i].position = getNewOffset(allIndexes, + allSizes, + 0, + labels[i].position); + labels[i].resized = true; + } + } + } + } + + // replaces old bytecodes with new ones + code = newCode; + + // returns the positions of the resized instructions + return indexes; + } + + /** + * Reads an unsigned short value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static int readUnsignedShort(final byte[] b, final int index) { + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static short readShort(final byte[] b, final int index) { + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static int readInt(final byte[] b, final int index) { + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); + } + + /** + * Writes a short value in the given byte array. + * + * @param b a byte array. + * @param index where the first byte of the short value must be written. + * @param s the value to be written in the given byte array. + */ + static void writeShort(final byte[] b, final int index, final int s) { + b[index] = (byte) (s >>> 8); + b[index + 1] = (byte) s; + } + + /** + * Computes the future value of a bytecode offset. <p> Note: it is possible + * to have several entries for the same instruction in the <tt>indexes</tt> + * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b') + * are equivalent to a single entry (index=a,size=b+b'). + * + * @param indexes current positions of the instructions to be resized. Each + * instruction must be designated by the index of its <i>last</i> + * byte, plus one (or, in other words, by the index of the <i>first</i> + * byte of the <i>next</i> instruction). + * @param sizes the number of bytes to be <i>added</i> to the above + * instructions. More precisely, for each i < <tt>len</tt>, + * <tt>sizes</tt>[i] bytes will be added at the end of the + * instruction designated by <tt>indexes</tt>[i] or, if + * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| + * bytes of the instruction will be removed (the instruction size + * <i>must not</i> become negative or null). + * @param begin index of the first byte of the source instruction. + * @param end index of the first byte of the target instruction. + * @return the future value of the given bytecode offset. + */ + static int getNewOffset( + final int[] indexes, + final int[] sizes, + final int begin, + final int end) + { + int offset = end - begin; + for (int i = 0; i < indexes.length; ++i) { + if (begin < indexes[i] && indexes[i] <= end) { + // forward jump + offset += sizes[i]; + } else if (end < indexes[i] && indexes[i] <= begin) { + // backward jump + offset -= sizes[i]; + } + } + return offset; + } + + /** + * Updates the offset of the given label. + * + * @param indexes current positions of the instructions to be resized. Each + * instruction must be designated by the index of its <i>last</i> + * byte, plus one (or, in other words, by the index of the <i>first</i> + * byte of the <i>next</i> instruction). + * @param sizes the number of bytes to be <i>added</i> to the above + * instructions. More precisely, for each i < <tt>len</tt>, + * <tt>sizes</tt>[i] bytes will be added at the end of the + * instruction designated by <tt>indexes</tt>[i] or, if + * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| + * bytes of the instruction will be removed (the instruction size + * <i>must not</i> become negative or null). + * @param label the label whose offset must be updated. + */ + static void getNewOffset( + final int[] indexes, + final int[] sizes, + final Label label) + { + if (!label.resized) { + label.position = getNewOffset(indexes, sizes, 0, label.position); + label.resized = true; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Opcodes.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Opcodes.java new file mode 100644 index 000000000..2728d96b5 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Opcodes.java @@ -0,0 +1,295 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * Defines the JVM opcodes, access flags and array type codes. This interface + * does not define all the JVM opcodes because some opcodes are automatically + * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced + * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n + * opcodes are therefore not defined in this interface. Likewise for LDC, + * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and + * JSR_W. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public interface Opcodes { + + // versions + + int V1_1 = 3 << 16 | 45; + int V1_2 = 0 << 16 | 46; + int V1_3 = 0 << 16 | 47; + int V1_4 = 0 << 16 | 48; + int V1_5 = 0 << 16 | 49; + int V1_6 = 0 << 16 | 50; + + // access flags + + int ACC_PUBLIC = 0x0001; // class, field, method + int ACC_PRIVATE = 0x0002; // class, field, method + int ACC_PROTECTED = 0x0004; // class, field, method + int ACC_STATIC = 0x0008; // field, method + int ACC_FINAL = 0x0010; // class, field, method + int ACC_SUPER = 0x0020; // class + int ACC_SYNCHRONIZED = 0x0020; // method + int ACC_VOLATILE = 0x0040; // field + int ACC_BRIDGE = 0x0040; // method + int ACC_VARARGS = 0x0080; // method + int ACC_TRANSIENT = 0x0080; // field + int ACC_NATIVE = 0x0100; // method + int ACC_INTERFACE = 0x0200; // class + int ACC_ABSTRACT = 0x0400; // class, method + int ACC_STRICT = 0x0800; // method + int ACC_SYNTHETIC = 0x1000; // class, field, method + int ACC_ANNOTATION = 0x2000; // class + int ACC_ENUM = 0x4000; // class(?) field inner + + // ASM specific pseudo access flags + + int ACC_DEPRECATED = 131072; // class, field, method + + // types for NEWARRAY + + int T_BOOLEAN = 4; + int T_CHAR = 5; + int T_FLOAT = 6; + int T_DOUBLE = 7; + int T_BYTE = 8; + int T_SHORT = 9; + int T_INT = 10; + int T_LONG = 11; + + // opcodes // visit method (- = idem) + + int NOP = 0; // visitInsn + int ACONST_NULL = 1; // - + int ICONST_M1 = 2; // - + int ICONST_0 = 3; // - + int ICONST_1 = 4; // - + int ICONST_2 = 5; // - + int ICONST_3 = 6; // - + int ICONST_4 = 7; // - + int ICONST_5 = 8; // - + int LCONST_0 = 9; // - + int LCONST_1 = 10; // - + int FCONST_0 = 11; // - + int FCONST_1 = 12; // - + int FCONST_2 = 13; // - + int DCONST_0 = 14; // - + int DCONST_1 = 15; // - + int BIPUSH = 16; // visitIntInsn + int SIPUSH = 17; // - + int LDC = 18; // visitLdcInsn + // int LDC_W = 19; // - + // int LDC2_W = 20; // - + int ILOAD = 21; // visitVarInsn + int LLOAD = 22; // - + int FLOAD = 23; // - + int DLOAD = 24; // - + int ALOAD = 25; // - + // int ILOAD_0 = 26; // - + // int ILOAD_1 = 27; // - + // int ILOAD_2 = 28; // - + // int ILOAD_3 = 29; // - + // int LLOAD_0 = 30; // - + // int LLOAD_1 = 31; // - + // int LLOAD_2 = 32; // - + // int LLOAD_3 = 33; // - + // int FLOAD_0 = 34; // - + // int FLOAD_1 = 35; // - + // int FLOAD_2 = 36; // - + // int FLOAD_3 = 37; // - + // int DLOAD_0 = 38; // - + // int DLOAD_1 = 39; // - + // int DLOAD_2 = 40; // - + // int DLOAD_3 = 41; // - + // int ALOAD_0 = 42; // - + // int ALOAD_1 = 43; // - + // int ALOAD_2 = 44; // - + // int ALOAD_3 = 45; // - + int IALOAD = 46; // visitInsn + int LALOAD = 47; // - + int FALOAD = 48; // - + int DALOAD = 49; // - + int AALOAD = 50; // - + int BALOAD = 51; // - + int CALOAD = 52; // - + int SALOAD = 53; // - + int ISTORE = 54; // visitVarInsn + int LSTORE = 55; // - + int FSTORE = 56; // - + int DSTORE = 57; // - + int ASTORE = 58; // - + // int ISTORE_0 = 59; // - + // int ISTORE_1 = 60; // - + // int ISTORE_2 = 61; // - + // int ISTORE_3 = 62; // - + // int LSTORE_0 = 63; // - + // int LSTORE_1 = 64; // - + // int LSTORE_2 = 65; // - + // int LSTORE_3 = 66; // - + // int FSTORE_0 = 67; // - + // int FSTORE_1 = 68; // - + // int FSTORE_2 = 69; // - + // int FSTORE_3 = 70; // - + // int DSTORE_0 = 71; // - + // int DSTORE_1 = 72; // - + // int DSTORE_2 = 73; // - + // int DSTORE_3 = 74; // - + // int ASTORE_0 = 75; // - + // int ASTORE_1 = 76; // - + // int ASTORE_2 = 77; // - + // int ASTORE_3 = 78; // - + int IASTORE = 79; // visitInsn + int LASTORE = 80; // - + int FASTORE = 81; // - + int DASTORE = 82; // - + int AASTORE = 83; // - + int BASTORE = 84; // - + int CASTORE = 85; // - + int SASTORE = 86; // - + int POP = 87; // - + int POP2 = 88; // - + int DUP = 89; // - + int DUP_X1 = 90; // - + int DUP_X2 = 91; // - + int DUP2 = 92; // - + int DUP2_X1 = 93; // - + int DUP2_X2 = 94; // - + int SWAP = 95; // - + int IADD = 96; // - + int LADD = 97; // - + int FADD = 98; // - + int DADD = 99; // - + int ISUB = 100; // - + int LSUB = 101; // - + int FSUB = 102; // - + int DSUB = 103; // - + int IMUL = 104; // - + int LMUL = 105; // - + int FMUL = 106; // - + int DMUL = 107; // - + int IDIV = 108; // - + int LDIV = 109; // - + int FDIV = 110; // - + int DDIV = 111; // - + int IREM = 112; // - + int LREM = 113; // - + int FREM = 114; // - + int DREM = 115; // - + int INEG = 116; // - + int LNEG = 117; // - + int FNEG = 118; // - + int DNEG = 119; // - + int ISHL = 120; // - + int LSHL = 121; // - + int ISHR = 122; // - + int LSHR = 123; // - + int IUSHR = 124; // - + int LUSHR = 125; // - + int IAND = 126; // - + int LAND = 127; // - + int IOR = 128; // - + int LOR = 129; // - + int IXOR = 130; // - + int LXOR = 131; // - + int IINC = 132; // visitIincInsn + int I2L = 133; // visitInsn + int I2F = 134; // - + int I2D = 135; // - + int L2I = 136; // - + int L2F = 137; // - + int L2D = 138; // - + int F2I = 139; // - + int F2L = 140; // - + int F2D = 141; // - + int D2I = 142; // - + int D2L = 143; // - + int D2F = 144; // - + int I2B = 145; // - + int I2C = 146; // - + int I2S = 147; // - + int LCMP = 148; // - + int FCMPL = 149; // - + int FCMPG = 150; // - + int DCMPL = 151; // - + int DCMPG = 152; // - + int IFEQ = 153; // visitJumpInsn + int IFNE = 154; // - + int IFLT = 155; // - + int IFGE = 156; // - + int IFGT = 157; // - + int IFLE = 158; // - + int IF_ICMPEQ = 159; // - + int IF_ICMPNE = 160; // - + int IF_ICMPLT = 161; // - + int IF_ICMPGE = 162; // - + int IF_ICMPGT = 163; // - + int IF_ICMPLE = 164; // - + int IF_ACMPEQ = 165; // - + int IF_ACMPNE = 166; // - + int GOTO = 167; // - + int JSR = 168; // - + int RET = 169; // visitVarInsn + int TABLESWITCH = 170; // visiTableSwitchInsn + int LOOKUPSWITCH = 171; // visitLookupSwitch + int IRETURN = 172; // visitInsn + int LRETURN = 173; // - + int FRETURN = 174; // - + int DRETURN = 175; // - + int ARETURN = 176; // - + int RETURN = 177; // - + int GETSTATIC = 178; // visitFieldInsn + int PUTSTATIC = 179; // - + int GETFIELD = 180; // - + int PUTFIELD = 181; // - + int INVOKEVIRTUAL = 182; // visitMethodInsn + int INVOKESPECIAL = 183; // - + int INVOKESTATIC = 184; // - + int INVOKEINTERFACE = 185; // - + // int UNUSED = 186; // NOT VISITED + int NEW = 187; // visitTypeInsn + int NEWARRAY = 188; // visitIntInsn + int ANEWARRAY = 189; // visitTypeInsn + int ARRAYLENGTH = 190; // visitInsn + int ATHROW = 191; // - + int CHECKCAST = 192; // visitTypeInsn + int INSTANCEOF = 193; // - + int MONITORENTER = 194; // visitInsn + int MONITOREXIT = 195; // - + // int WIDE = 196; // NOT VISITED + int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn + int IFNULL = 198; // visitJumpInsn + int IFNONNULL = 199; // - + // int GOTO_W = 200; // - + // int JSR_W = 201; // - +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/Type.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/Type.java new file mode 100644 index 000000000..ae314e8cd --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/Type.java @@ -0,0 +1,760 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +import java.lang.reflect.Method; + +/** + * A Java type. This class can be used to make it easier to manipulate type and + * method descriptors. + * + * @author Eric Bruneton + * @author Chris Nokleberg + */ +public class Type { + + /** + * The sort of the <tt>void</tt> type. See {@link #getSort getSort}. + */ + public final static int VOID = 0; + + /** + * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. + */ + public final static int BOOLEAN = 1; + + /** + * The sort of the <tt>char</tt> type. See {@link #getSort getSort}. + */ + public final static int CHAR = 2; + + /** + * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. + */ + public final static int BYTE = 3; + + /** + * The sort of the <tt>short</tt> type. See {@link #getSort getSort}. + */ + public final static int SHORT = 4; + + /** + * The sort of the <tt>int</tt> type. See {@link #getSort getSort}. + */ + public final static int INT = 5; + + /** + * The sort of the <tt>float</tt> type. See {@link #getSort getSort}. + */ + public final static int FLOAT = 6; + + /** + * The sort of the <tt>long</tt> type. See {@link #getSort getSort}. + */ + public final static int LONG = 7; + + /** + * The sort of the <tt>double</tt> type. See {@link #getSort getSort}. + */ + public final static int DOUBLE = 8; + + /** + * The sort of array reference types. See {@link #getSort getSort}. + */ + public final static int ARRAY = 9; + + /** + * The sort of object reference type. See {@link #getSort getSort}. + */ + public final static int OBJECT = 10; + + /** + * The <tt>void</tt> type. + */ + public final static Type VOID_TYPE = new Type(VOID); + + /** + * The <tt>boolean</tt> type. + */ + public final static Type BOOLEAN_TYPE = new Type(BOOLEAN); + + /** + * The <tt>char</tt> type. + */ + public final static Type CHAR_TYPE = new Type(CHAR); + + /** + * The <tt>byte</tt> type. + */ + public final static Type BYTE_TYPE = new Type(BYTE); + + /** + * The <tt>short</tt> type. + */ + public final static Type SHORT_TYPE = new Type(SHORT); + + /** + * The <tt>int</tt> type. + */ + public final static Type INT_TYPE = new Type(INT); + + /** + * The <tt>float</tt> type. + */ + public final static Type FLOAT_TYPE = new Type(FLOAT); + + /** + * The <tt>long</tt> type. + */ + public final static Type LONG_TYPE = new Type(LONG); + + /** + * The <tt>double</tt> type. + */ + public final static Type DOUBLE_TYPE = new Type(DOUBLE); + + // ------------------------------------------------------------------------ + // Fields + // ------------------------------------------------------------------------ + + /** + * The sort of this Java type. + */ + private final int sort; + + /** + * A buffer containing the descriptor of this Java type. This field is only + * used for reference types. + */ + private char[] buf; + + /** + * The offset of the descriptor of this Java type in {@link #buf buf}. This + * field is only used for reference types. + */ + private int off; + + /** + * The length of the descriptor of this Java type. + */ + private int len; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a primitive type. + * + * @param sort the sort of the primitive type to be constructed. + */ + private Type(final int sort) { + this.sort = sort; + this.len = 1; + } + + /** + * Constructs a reference type. + * + * @param sort the sort of the reference type to be constructed. + * @param buf a buffer containing the descriptor of the previous type. + * @param off the offset of this descriptor in the previous buffer. + * @param len the length of this descriptor. + */ + private Type(final int sort, final char[] buf, final int off, final int len) + { + this.sort = sort; + this.buf = buf; + this.off = off; + this.len = len; + } + + /** + * Returns the Java type corresponding to the given type descriptor. + * + * @param typeDescriptor a type descriptor. + * @return the Java type corresponding to the given type descriptor. + */ + public static Type getType(final String typeDescriptor) { + return getType(typeDescriptor.toCharArray(), 0); + } + + /** + * Returns the Java type corresponding to the given class. + * + * @param c a class. + * @return the Java type corresponding to the given class. + */ + public static Type getType(final Class c) { + if (c.isPrimitive()) { + if (c == Integer.TYPE) { + return INT_TYPE; + } else if (c == Void.TYPE) { + return VOID_TYPE; + } else if (c == Boolean.TYPE) { + return BOOLEAN_TYPE; + } else if (c == Byte.TYPE) { + return BYTE_TYPE; + } else if (c == Character.TYPE) { + return CHAR_TYPE; + } else if (c == Short.TYPE) { + return SHORT_TYPE; + } else if (c == Double.TYPE) { + return DOUBLE_TYPE; + } else if (c == Float.TYPE) { + return FLOAT_TYPE; + } else /* if (c == Long.TYPE) */{ + return LONG_TYPE; + } + } else { + return getType(getDescriptor(c)); + } + } + + /** + * Returns the Java types corresponding to the argument types of the given + * method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java types corresponding to the argument types of the given + * method descriptor. + */ + public static Type[] getArgumentTypes(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + int off = 1; + int size = 0; + while (true) { + char car = buf[off++]; + if (car == ')') { + break; + } else if (car == 'L') { + while (buf[off++] != ';') { + } + ++size; + } else if (car != '[') { + ++size; + } + } + Type[] args = new Type[size]; + off = 1; + size = 0; + while (buf[off] != ')') { + args[size] = getType(buf, off); + off += args[size].len; + size += 1; + } + return args; + } + + /** + * Returns the Java types corresponding to the argument types of the given + * method. + * + * @param method a method. + * @return the Java types corresponding to the argument types of the given + * method. + */ + public static Type[] getArgumentTypes(final Method method) { + Class[] classes = method.getParameterTypes(); + Type[] types = new Type[classes.length]; + for (int i = classes.length - 1; i >= 0; --i) { + types[i] = getType(classes[i]); + } + return types; + } + + /** + * Returns the Java type corresponding to the return type of the given + * method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java type corresponding to the return type of the given + * method descriptor. + */ + public static Type getReturnType(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + return getType(buf, methodDescriptor.indexOf(')') + 1); + } + + /** + * Returns the Java type corresponding to the return type of the given + * method. + * + * @param method a method. + * @return the Java type corresponding to the return type of the given + * method. + */ + public static Type getReturnType(final Method method) { + return getType(method.getReturnType()); + } + + /** + * Returns the Java type corresponding to the given type descriptor. + * + * @param buf a buffer containing a type descriptor. + * @param off the offset of this descriptor in the previous buffer. + * @return the Java type corresponding to the given type descriptor. + */ + private static Type getType(final char[] buf, final int off) { + int len; + switch (buf[off]) { + case 'V': + return VOID_TYPE; + case 'Z': + return BOOLEAN_TYPE; + case 'C': + return CHAR_TYPE; + case 'B': + return BYTE_TYPE; + case 'S': + return SHORT_TYPE; + case 'I': + return INT_TYPE; + case 'F': + return FLOAT_TYPE; + case 'J': + return LONG_TYPE; + case 'D': + return DOUBLE_TYPE; + case '[': + len = 1; + while (buf[off + len] == '[') { + ++len; + } + if (buf[off + len] == 'L') { + ++len; + while (buf[off + len] != ';') { + ++len; + } + } + return new Type(ARRAY, buf, off, len + 1); + // case 'L': + default: + len = 1; + while (buf[off + len] != ';') { + ++len; + } + return new Type(OBJECT, buf, off, len + 1); + } + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the sort of this Java type. + * + * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, + * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT}, + * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, + * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or + * {@link #OBJECT OBJECT}. + */ + public int getSort() { + return sort; + } + + /** + * Returns the number of dimensions of this array type. This method should + * only be used for an array type. + * + * @return the number of dimensions of this array type. + */ + public int getDimensions() { + int i = 1; + while (buf[off + i] == '[') { + ++i; + } + return i; + } + + /** + * Returns the type of the elements of this array type. This method should + * only be used for an array type. + * + * @return Returns the type of the elements of this array type. + */ + public Type getElementType() { + return getType(buf, off + getDimensions()); + } + + /** + * Returns the name of the class corresponding to this type. + * + * @return the fully qualified name of the class corresponding to this type. + */ + public String getClassName() { + switch (sort) { + case VOID: + return "void"; + case BOOLEAN: + return "boolean"; + case CHAR: + return "char"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case INT: + return "int"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case DOUBLE: + return "double"; + case ARRAY: + StringBuffer b = new StringBuffer(getElementType().getClassName()); + for (int i = getDimensions(); i > 0; --i) { + b.append("[]"); + } + return b.toString(); + // case OBJECT: + default: + return new String(buf, off + 1, len - 2).replace('/', '.'); + } + } + + /** + * Returns the internal name of the class corresponding to this object type. + * The internal name of a class is its fully qualified name, where '.' are + * replaced by '/'. This method should only be used for an object type. + * + * @return the internal name of the class corresponding to this object type. + */ + public String getInternalName() { + return new String(buf, off + 1, len - 2); + } + + // ------------------------------------------------------------------------ + // Conversion to type descriptors + // ------------------------------------------------------------------------ + + /** + * Returns the descriptor corresponding to this Java type. + * + * @return the descriptor corresponding to this Java type. + */ + public String getDescriptor() { + StringBuffer buf = new StringBuffer(); + getDescriptor(buf); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given argument and return + * types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the descriptor corresponding to the given argument and return + * types. + */ + public static String getMethodDescriptor( + final Type returnType, + final Type[] argumentTypes) + { + StringBuffer buf = new StringBuffer(); + buf.append('('); + for (int i = 0; i < argumentTypes.length; ++i) { + argumentTypes[i].getDescriptor(buf); + } + buf.append(')'); + returnType.getDescriptor(buf); + return buf.toString(); + } + + /** + * Appends the descriptor corresponding to this Java type to the given + * string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + */ + private void getDescriptor(final StringBuffer buf) { + switch (sort) { + case VOID: + buf.append('V'); + return; + case BOOLEAN: + buf.append('Z'); + return; + case CHAR: + buf.append('C'); + return; + case BYTE: + buf.append('B'); + return; + case SHORT: + buf.append('S'); + return; + case INT: + buf.append('I'); + return; + case FLOAT: + buf.append('F'); + return; + case LONG: + buf.append('J'); + return; + case DOUBLE: + buf.append('D'); + return; + // case ARRAY: + // case OBJECT: + default: + buf.append(this.buf, off, len); + } + } + + // ------------------------------------------------------------------------ + // Direct conversion from classes to type descriptors, + // without intermediate Type objects + // ------------------------------------------------------------------------ + + /** + * Returns the internal name of the given class. The internal name of a + * class is its fully qualified name, where '.' are replaced by '/'. + * + * @param c an object class. + * @return the internal name of the given class. + */ + public static String getInternalName(final Class c) { + return c.getName().replace('.', '/'); + } + + /** + * Returns the descriptor corresponding to the given Java type. + * + * @param c an object class, a primitive class or an array class. + * @return the descriptor corresponding to the given class. + */ + public static String getDescriptor(final Class c) { + StringBuffer buf = new StringBuffer(); + getDescriptor(buf, c); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given method. + * + * @param m a {@link Method Method} object. + * @return the descriptor of the given method. + */ + public static String getMethodDescriptor(final Method m) { + Class[] parameters = m.getParameterTypes(); + StringBuffer buf = new StringBuffer(); + buf.append('('); + for (int i = 0; i < parameters.length; ++i) { + getDescriptor(buf, parameters[i]); + } + buf.append(')'); + getDescriptor(buf, m.getReturnType()); + return buf.toString(); + } + + /** + * Appends the descriptor of the given class to the given string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + * @param c the class whose descriptor must be computed. + */ + private static void getDescriptor(final StringBuffer buf, final Class c) { + Class d = c; + while (true) { + if (d.isPrimitive()) { + char car; + if (d == Integer.TYPE) { + car = 'I'; + } else if (d == Void.TYPE) { + car = 'V'; + } else if (d == Boolean.TYPE) { + car = 'Z'; + } else if (d == Byte.TYPE) { + car = 'B'; + } else if (d == Character.TYPE) { + car = 'C'; + } else if (d == Short.TYPE) { + car = 'S'; + } else if (d == Double.TYPE) { + car = 'D'; + } else if (d == Float.TYPE) { + car = 'F'; + } else /* if (d == Long.TYPE) */{ + car = 'J'; + } + buf.append(car); + return; + } else if (d.isArray()) { + buf.append('['); + d = d.getComponentType(); + } else { + buf.append('L'); + String name = d.getName(); + int len = name.length(); + for (int i = 0; i < len; ++i) { + char car = name.charAt(i); + buf.append(car == '.' ? '/' : car); + } + buf.append(';'); + return; + } + } + } + + // ------------------------------------------------------------------------ + // Corresponding size and opcodes + // ------------------------------------------------------------------------ + + /** + * Returns the size of values of this type. + * + * @return the size of values of this type, i.e., 2 for <tt>long</tt> and + * <tt>double</tt>, and 1 otherwise. + */ + public int getSize() { + return (sort == LONG || sort == DOUBLE ? 2 : 1); + } + + /** + * Returns a JVM instruction opcode adapted to this Java type. + * + * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, + * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, + * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. + * @return an opcode that is similar to the given opcode, but adapted to + * this Java type. For example, if this type is <tt>float</tt> and + * <tt>opcode</tt> is IRETURN, this method returns FRETURN. + */ + public int getOpcode(final int opcode) { + if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { + switch (sort) { + case BOOLEAN: + case BYTE: + return opcode + 5; + case CHAR: + return opcode + 6; + case SHORT: + return opcode + 7; + case INT: + return opcode; + case FLOAT: + return opcode + 2; + case LONG: + return opcode + 1; + case DOUBLE: + return opcode + 3; + // case ARRAY: + // case OBJECT: + default: + return opcode + 4; + } + } else { + switch (sort) { + case VOID: + return opcode + 5; + case BOOLEAN: + case CHAR: + case BYTE: + case SHORT: + case INT: + return opcode; + case FLOAT: + return opcode + 2; + case LONG: + return opcode + 1; + case DOUBLE: + return opcode + 3; + // case ARRAY: + // case OBJECT: + default: + return opcode + 4; + } + } + } + + // ------------------------------------------------------------------------ + // Equals, hashCode and toString + // ------------------------------------------------------------------------ + + /** + * Tests if the given object is equal to this type. + * + * @param o the object to be compared to this type. + * @return <tt>true</tt> if the given object is equal to this type. + */ + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || !(o instanceof Type)) { + return false; + } + Type t = (Type) o; + if (sort != t.sort) { + return false; + } + if (sort == Type.OBJECT || sort == Type.ARRAY) { + if (len != t.len) { + return false; + } + for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { + if (buf[i] != t.buf[j]) { + return false; + } + } + } + return true; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value for this type. + */ + public int hashCode() { + int hc = 13 * sort; + if (sort == Type.OBJECT || sort == Type.ARRAY) { + for (int i = off, end = i + len; i < end; i++) { + hc = 17 * (hc + buf[i]); + } + } + return hc; + } + + /** + * Returns a string representation of this type. + * + * @return the descriptor of this type. + */ + public String toString() { + return getDescriptor(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapAttribute.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapAttribute.java new file mode 100644 index 000000000..f35947485 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapAttribute.java @@ -0,0 +1,378 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.attrs; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ByteVector; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; + +/** + * StackMapAttribute is used by CDLC preverifier. Definition is given in + * appendix "CLDC Byte Code Typechecker Specification" from CDLC 1.1 + * specification. <p> <i>Note that this implementation does not calculate + * StackMapFrame structures from the method bytecode. If method code is changed + * or generated from scratch, then developer is responsible to prepare a correct + * StackMapFrame structures.</i> <p> The format of the stack map in the class + * file is given below. In the following, <ul> <li>if the length of the + * method's byte code1 is 65535 or less, then <tt>uoffset</tt> represents the + * type u2; otherwise <tt>uoffset</tt> represents the type u4.</li> <li>If + * the maximum number of local variables for the method is 65535 or less, then + * <tt>ulocalvar</tt> represents the type u2; otherwise <tt>ulocalvar</tt> + * represents the type u4.</li> <li>If the maximum size of the operand stack + * is 65535 or less, then <tt>ustack</tt> represents the type u2; otherwise + * ustack represents the type u4.</li> </ul> + * + * <pre> + * stack_map { // attribute StackMap + * u2 attribute_name_index; + * u4 attribute_length + * uoffset number_of_entries; + * stack_map_frame entries[number_of_entries]; + * } + * </pre> + * + * Each stack map frame has the following format: + * + * <pre> + * stack_map_frame { + * uoffset offset; + * ulocalvar number_of_locals; + * verification_type_info locals[number_of_locals]; + * ustack number_of_stack_items; + * verification_type_info stack[number_of_stack_items]; + * } + * </pre> + * + * The <tt>verification_type_info</tt> structure consists of a one-byte tag + * followed by zero or more bytes, giving more information about the tag. Each + * <tt>verification_type_info</tt> structure specifies the verification type + * of one or two locations. + * + * <pre> + * union verification_type_info { + * Top_variable_info; + * Integer_variable_info; + * Float_variable_info; + * Long_variable_info; + * Double_variable_info; + * Null_variable_info; + * UninitializedThis_variable_info; + * Object_variable_info; + * Uninitialized_variable_info; + * } + * + * Top_variable_info { + * u1 tag = ITEM_Top; // 0 + * } + * + * Integer_variable_info { + * u1 tag = ITEM_Integer; // 1 + * } + * + * Float_variable_info { + * u1 tag = ITEM_Float; // 2 + * } + * + * Long_variable_info { + * u1 tag = ITEM_Long; // 4 + * } + * + * Double_variable_info { + * u1 tag = ITEM_Double; // 3 + * } + * + * Null_variable_info { + * u1 tag = ITEM_Null; // 5 + * } + * + * UninitializedThis_variable_info { + * u1 tag = ITEM_UninitializedThis; // 6 + * } + * + * Object_variable_info { + * u1 tag = ITEM_Object; // 7 + * u2 cpool_index; + * } + * + * Uninitialized_variable_info { + * u1 tag = ITEM_Uninitialized // 8 + * uoffset offset; + * } + * </pre> + * + * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected + * Limited Device Configuration 1.1</a> + * + * @author Eugene Kuleshov + */ +public class StackMapAttribute extends Attribute { + + static final int MAX_SIZE = 65535; + + /** + * A List of <code>StackMapFrame</code> instances. + */ + public List frames = new ArrayList(); + + public StackMapAttribute() { + super("StackMap"); + } + + public StackMapAttribute(List frames) { + this(); + this.frames = frames; + } + + public List getFrames() { + return frames; + } + + public StackMapFrame getFrame(Label label) { + for (int i = 0; i < frames.size(); i++) { + StackMapFrame frame = (StackMapFrame) frames.get(i); + if (frame.label == label) { + return frame; + } + } + return null; + } + + public boolean isUnknown() { + return false; + } + + public boolean isCodeAttribute() { + return true; + } + + protected Attribute read( + ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + StackMapAttribute attr = new StackMapAttribute(); + // note that this is not the size of Code attribute + boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SIZE; + boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SIZE; + boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SIZE; + + int size = 0; + if (isExtCodeSize) { + size = cr.readInt(off); + off += 4; + } else { + size = cr.readUnsignedShort(off); + off += 2; + } + for (int i = 0; i < size; i++) { + int offset; + if (isExtCodeSize) { + offset = cr.readInt(off); + off += 4; + } else { + offset = cr.readUnsignedShort(off); + off += 2; + } + + Label label = getLabel(offset, labels); + List locals = new ArrayList(); + List stack = new ArrayList(); + + off = readTypeInfo(cr, + off, + locals, + labels, + buf, + isExtLocals, + isExtCodeSize); + off = readTypeInfo(cr, + off, + stack, + labels, + buf, + isExtStack, + isExtCodeSize); + + attr.frames.add(new StackMapFrame(label, locals, stack)); + } + return attr; + } + + private int readTypeInfo( + ClassReader cr, + int off, + List info, + Label[] labels, + char[] buf, + boolean isExt, + boolean isExtCode) + { + int n = 0; + if (isExt) { + n = cr.readInt(off); + off += 4; + } else { + n = cr.readUnsignedShort(off); + off += 2; + } + for (int j = 0; j < n; j++) { + int itemType = cr.readByte(off++); + StackMapType typeInfo = StackMapType.getTypeInfo(itemType); + info.add(typeInfo); + switch (itemType) { + case StackMapType.ITEM_Object: // + typeInfo.setObject(cr.readClass(off, buf)); + off += 2; + break; + case StackMapType.ITEM_Uninitialized: // + int offset; + if (isExtCode) { + offset = cr.readInt(off); + off += 4; + } else { + offset = cr.readUnsignedShort(off); + off += 2; + } + typeInfo.setLabel(getLabel(offset, labels)); + break; + } + } + return off; + } + + private void writeTypeInfo(ByteVector bv, ClassWriter cw, List info, int max) + { + if (max > StackMapAttribute.MAX_SIZE) { + bv.putInt(info.size()); + } else { + bv.putShort(info.size()); + } + for (int j = 0; j < info.size(); j++) { + StackMapType typeInfo = (StackMapType) info.get(j); + bv.putByte(typeInfo.getType()); + switch (typeInfo.getType()) { + case StackMapType.ITEM_Object: // + bv.putShort(cw.newClass(typeInfo.getObject())); + break; + + case StackMapType.ITEM_Uninitialized: // + bv.putShort(typeInfo.getLabel().getOffset()); + break; + + } + } + } + + private Label getLabel(int offset, Label[] labels) { + Label l = labels[offset]; + if (l != null) { + return l; + } + return labels[offset] = new Label(); + } + + protected ByteVector write( + ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector bv = new ByteVector(); + if (code != null && code.length > MAX_SIZE) { // TODO verify value + bv.putInt(frames.size()); + } else { + bv.putShort(frames.size()); + } + for (int i = 0; i < frames.size(); i++) { + writeFrame((StackMapFrame) frames.get(i), + cw, + maxStack, + maxLocals, + bv); + } + return bv; + } + + protected Label[] getLabels() { + HashSet labels = new HashSet(); + for (int i = 0; i < frames.size(); i++) { + getFrameLabels((StackMapFrame) frames.get(i), labels); + } + return (Label[]) labels.toArray(new Label[labels.size()]); + } + + private void writeFrame( + StackMapFrame frame, + ClassWriter cw, + int maxStack, + int maxLocals, + ByteVector bv) + { + bv.putShort(frame.label.getOffset()); + writeTypeInfo(bv, cw, frame.locals, maxLocals); + writeTypeInfo(bv, cw, frame.stack, maxStack); + } + + private void getFrameLabels(StackMapFrame frame, Set labels) { + labels.add(frame.label); + getTypeInfoLabels(labels, frame.locals); + getTypeInfoLabels(labels, frame.stack); + } + + private void getTypeInfoLabels(Set labels, List info) { + for (Iterator it = info.iterator(); it.hasNext();) { + StackMapType typeInfo = (StackMapType) it.next(); + if (typeInfo.getType() == StackMapType.ITEM_Uninitialized) { + labels.add(typeInfo.getLabel()); + } + } + } + + public String toString() { + StringBuffer sb = new StringBuffer("StackMap["); + for (int i = 0; i < frames.size(); i++) { + sb.append('\n').append('[').append(frames.get(i)).append(']'); + } + sb.append("\n]"); + return sb.toString(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapFrame.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapFrame.java new file mode 100644 index 000000000..d91d8e707 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapFrame.java @@ -0,0 +1,82 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.attrs; + +import java.util.List; + +import org.objectweb.asm.Label; + +/** + * Holds the state of the stack and local variables for a single execution + * branch. + * + * <i>Note that Long and Double types are represented by two entries in locals + * and stack. Second entry should be always of type Top.</i> + * + * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected + * Limited Device Configuration 1.1</a> + * + * @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM" + * + * @author Eugene Kuleshov + */ +public class StackMapFrame { + + /** + * A <code>Label</code> for frame offset within method bytecode. + */ + public Label label; + + /** + * A List of <code>StackMapType</code> instances that represent locals for + * this frame. + */ + public List locals; + + /** + * A List of <code>StackMapType</code> instances that represent stack for + * this frame. + */ + public List stack; + + public StackMapFrame(Label label, List locals, List stack) { + this.label = label; + this.locals = locals; + this.stack = stack; + } + + public String toString() { + StringBuffer sb = new StringBuffer("Frame:L"); + sb.append(System.identityHashCode(label)); + sb.append(" locals").append(locals); + sb.append(" stack").append(stack); + return sb.toString(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapTableAttribute.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapTableAttribute.java new file mode 100644 index 000000000..032adf62b --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapTableAttribute.java @@ -0,0 +1,927 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.attrs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ByteVector; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * The stack map attribute is used during the process of verification by + * typechecking (§4.11.1). <br> <br> A stack map attribute consists of zero or + * more stack map frames. Each stack map frame specifies (either explicitly or + * implicitly) a bytecode offset, the verification types (§4.11.1) for the local + * variables, and the verification types for the operand stack. <br> <br> The + * type checker deals with and manipulates the expected types of a method's + * local variables and operand stack. Throughout this section, a location refers + * to either a single local variable or to a single operand stack entry. <br> + * <br> We will use the terms stack frame map and type state interchangeably to + * describe a mapping from locations in the operand stack and local variables of + * a method to verification types. We will usually use the term stack frame map + * when such a mapping is provided in the class file, and the term type state + * when the mapping is inferred by the type checker. <br> <br> If a method's + * Code attribute does not have a StackMapTable attribute, it has an implicit + * stack map attribute. This implicit stack map attribute is equivalent to a + * StackMapTable attribute with number_of_entries equal to zero. A method's Code + * attribute may have at most one StackMapTable attribute, otherwise a + * java.lang.ClassFormatError is thrown. <br> <br> The format of the stack map + * in the class file is given below. In the following, if the length of the + * method's byte code is 65535 or less, then uoffset represents the type u2; + * otherwise uoffset represents the type u4. If the maximum number of local + * variables for the method is 65535 or less, then <code>ulocalvar</code> + * represents the type u2; otherwise ulocalvar represents the type u4. If the + * maximum size of the operand stack is 65535 or less, then <code>ustack</code> + * represents the type u2; otherwise ustack represents the type u4. + * + * <pre> + * stack_map { // attribute StackMapTable + * u2 attribute_name_index; + * u4 attribute_length + * uoffset number_of_entries; + * stack_map_frame entries[number_of_entries]; + * } + * </pre> + * + * Each stack_map_frame structure specifies the type state at a particular byte + * code offset. Each frame type specifies (explicitly or implicitly) a value, + * offset_delta, that is used to calulate the actual byte code offset at which + * it applies. The byte code offset at which the frame applies is given by + * adding <code>1 + offset_delta</code> to the <code>offset</code> of the + * previous frame, unless the previous frame is the initial frame of the method, + * in which case the byte code offset is <code>offset_delta</code>. <br> <br> + * <i>Note that the length of the byte codes is not the same as the length of + * the Code attribute. The byte codes are embedded in the Code attribute, along + * with other information.</i> <br> <br> By using an offset delta rather than + * the actual byte code offset we ensure, by definition, that stack map frames + * are in the correctly sorted order. Furthermore, by consistently using the + * formula <code>offset_delta + 1</code> for all explicit frames, we guarantee + * the absence of duplicates. <br> <br> All frame types, even full_frame, rely + * on the previous frame for some of their semantics. This raises the question + * of what is the very first frame? The initial frame is implicit, and computed + * from the method descriptor. See the Prolog code for methodInitialStacFrame. + * <br> <br> The stack_map_frame structure consists of a one-byte tag followed + * by zero or more bytes, giving more information, depending upon the tag. <br> + * <br> A stack map frame may belong to one of several frame types + * + * <pre> + * union stack_map_frame { + * same_frame; + * same_locals_1_stack_item_frame; + * chop_frame; + * same_frame_extended; + * append_frame; + * full_frame; + * } + * </pre> + * + * The frame type same_frame is represented by tags in the range [0-63]. If the + * frame type is same_frame, it means the frame has exactly the same locals as + * the previous stack map frame and that the number of stack items is zero. The + * offset_delta value for the frame is the value of the tag field, frame_type. + * The form of such a frame is then: + * + * <pre> + * same_frame { + * u1 frame_type = SAME; // 0-63 + * } + * </pre> + * + * The frame type same_locals_1_stack_item_frame is represented by tags in the + * range [64, 127]. If the frame_type is same_locals_1_stack_item_frame, it + * means the frame has exactly the same locals as the previous stack map frame + * and that the number of stack items is 1. The offset_delta value for the frame + * is the value (frame_type - 64). There is a verification_type_info following + * the frame_type for the one stack item. The form of such a frame is then: + * + * <pre> + * same_locals_1_stack_item_frame { + * u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 + * verification_type_info stack[1]; + * } + * </pre> + * + * Tags in the range [128-247] are reserved for future use. <br> <br> The frame + * type chop_frame is represented by tags in the range [248-250]. If the + * frame_type is chop_frame, it means that the current locals are the same as + * the locals in the previous frame, except that the k last locals are absent. + * The value of k is given by the formula 251-frame_type. <br> <br> The form of + * such a frame is then: + * + * <pre> + * chop_frame { + * u1 frame_type=CHOP; // 248-250 + * uoffset offset_delta; + * } + * </pre> + * + * The frame type same_frame_extended is represented by the tag value 251. If + * the frame type is same_frame_extended, it means the frame has exactly the + * same locals as the previous stack map frame and that the number of stack + * items is zero. The form of such a frame is then: + * + * <pre> + * same_frame_extended { + * u1 frame_type = SAME_FRAME_EXTENDED; // 251 + * uoffset offset_delta; + * } + * </pre> + * + * The frame type append_frame is represented by tags in the range [252-254]. If + * the frame_type is append_frame, it means that the current locals are the same + * as the locals in the previous frame, except that k additional locals are + * defined. The value of k is given by the formula frame_type-251. <br> <br> The + * form of such a frame is then: + * + * <pre> + * append_frame { + * u1 frame_type =APPEND; // 252-254 + * uoffset offset_delta; + * verification_type_info locals[frame_type -251]; + * } + * </pre> + * + * The 0th entry in locals represents the type of the first additional local + * variable. If locals[M] represents local variable N, then locals[M+1] + * represents local variable N+1 if locals[M] is one of Top_variable_info, + * Integer_variable_info, Float_variable_info, Null_variable_info, + * UninitializedThis_variable_info, Object_variable_info, or + * Uninitialized_variable_info, otherwise locals[M+1] represents local variable + * N+2. It is an error if, for any index i, locals[i] represents a local + * variable whose index is greater than the maximum number of local variables + * for the method. <br> <br> The frame type full_frame is represented by the tag + * value 255. The form of such a frame is then: + * + * <pre> + * full_frame { + * u1 frame_type = FULL_FRAME; // 255 + * uoffset offset_delta; + * ulocalvar number_of_locals; + * verification_type_info locals[number_of_locals]; + * ustack number_of_stack_items; + * verification_type_info stack[number_of_stack_items]; + * } + * </pre> + * + * The 0th entry in locals represents the type of local variable 0. If locals[M] + * represents local variable N, then locals[M+1] represents local variable N+1 + * if locals[M] is one of Top_variable_info, Integer_variable_info, + * Float_variable_info, Null_variable_info, UninitializedThis_variable_info, + * Object_variable_info, or Uninitialized_variable_info, otherwise locals[M+1] + * represents local variable N+2. It is an error if, for any index i, locals[i] + * represents a local variable whose index is greater than the maximum number of + * local variables for the method. <br> <br> The 0th entry in stack represents + * the type of the bottom of the stack, and subsequent entries represent types + * of stack elements closer to the top of the operand stack. We shall refer to + * the bottom element of the stack as stack element 0, and to subsequent + * elements as stack element 1, 2 etc. If stack[M] represents stack element N, + * then stack[M+1] represents stack element N+1 if stack[M] is one of + * Top_variable_info, Integer_variable_info, Float_variable_info, + * Null_variable_info, UninitializedThis_variable_info, Object_variable_info, or + * Uninitialized_variable_info, otherwise stack[M+1] represents stack element + * N+2. It is an error if, for any index i, stack[i] represents a stack entry + * whose index is greater than the maximum operand stack size for the method. + * <br> <br> We say that an instruction in the byte code has a corresponding + * stack map frame if the offset in the offset field of the stack map frame is + * the same as the offset of the instruction in the byte codes. <br> <br> The + * verification_type_info structure consists of a one-byte tag followed by zero + * or more bytes, giving more information about the tag. Each + * verification_type_info structure specifies the verification type of one or + * two locations. + * + * <pre> + * union verification_type_info { + * Top_variable_info; + * Integer_variable_info; + * Float_variable_info; + * Long_variable_info; + * Double_variable_info; + * Null_variable_info; + * UninitializedThis_variable_info; + * Object_variable_info; + * Uninitialized_variable_info; + * } + * </pre> + * + * The Top_variable_info type indicates that the local variable has the + * verification type top (T.) + * + * <pre> + * Top_variable_info { + * u1 tag = ITEM_Top; // 0 + * } + * </pre> + * + * The Integer_variable_info type indicates that the location contains the + * verification type int. + * + * <pre> + * Integer_variable_info { + * u1 tag = ITEM_Integer; // 1 + * } + * </pre> + * + * The Float_variable_info type indicates that the location contains the + * verification type float. + * + * <pre> + * Float_variable_info { + * u1 tag = ITEM_Float; // 2 + * } + * </pre> + * + * The Long_variable_info type indicates that the location contains the + * verification type long. If the location is a local variable, then: + * + * <ul> <li>It must not be the local variable with the highest index.</li> + * <li>The next higher numbered local variable contains the verification type + * T.</li> </ul> + * + * If the location is an operand stack entry, then: + * + * <ul> <li>The current location must not be the topmost location of the + * operand stack.</li> <li>the next location closer to the top of the operand + * stack contains the verification type T.</li> </ul> + * + * This structure gives the contents of two locations in the operand stack or in + * the local variables. + * + * <pre> + * Long_variable_info { + * u1 tag = ITEM_Long; // 4 + * } + * </pre> + * + * The Double_variable_info type indicates that the location contains the + * verification type double. If the location is a local variable, then: + * + * <ul> <li>It must not be the local variable with the highest index.</li> + * <li>The next higher numbered local variable contains the verification type + * T. <li> </ul> + * + * If the location is an operand stack entry, then: + * + * <ul> <li>The current location must not be the topmost location of the + * operand stack.</li> <li>the next location closer to the top of the operand + * stack contains the verification type T.</li> </ul> + * + * This structure gives the contents of two locations in in the operand stack or + * in the local variables. + * + * <pre> + * Double_variable_info { + * u1 tag = ITEM_Double; // 3 + * } + * </pre> + * + * The Null_variable_info type indicates that location contains the verification + * type null. + * + * <pre> + * Null_variable_info { + * u1 tag = ITEM_Null; // 5 + * } + * </pre> + * + * The UninitializedThis_variable_info type indicates that the location contains + * the verification type uninitializedThis. + * + * <pre> + * UninitializedThis_variable_info { + * u1 tag = ITEM_UninitializedThis; // 6 + * } + * </pre> + * + * The Object_variable_info type indicates that the location contains an + * instance of the class referenced by the constant pool entry. + * + * <pre> + * Object_variable_info { + * u1 tag = ITEM_Object; // 7 + * u2 cpool_index; + * } + * </pre> + * + * The Uninitialized_variable_info indicates that the location contains the + * verification type uninitialized(offset). The offset item indicates the offset + * of the new instruction that created the object being stored in the location. + * + * <pre> + * Uninitialized_variable_info { + * u1 tag = ITEM_Uninitialized // 8 + * uoffset offset; + * } + * </pre> + * + * @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM" + * + * @author Eugene Kuleshov + */ +public class StackMapTableAttribute extends Attribute { + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is zero. + */ + public static final int SAME_FRAME = 0; // to 63 (0-3f) + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is 1 + */ + public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 + + // (40-7f) + + /** + * Reserved for future use + */ + public static final int RESERVED = 128; + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is 1. Offset is bigger then 63; + */ + public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 + + /** + * Frame where current locals are the same as the locals in the previous + * frame, except that the k last locals are absent. The value of k is given + * by the formula 251-frame_type. + */ + public static final int CHOP_FRAME = 248; // to 250 (f8-fA) + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is zero. Offset is bigger then 63; + */ + public static final int SAME_FRAME_EXTENDED = 251; // fb + + /** + * Frame where current locals are the same as the locals in the previous + * frame, except that k additional locals are defined. The value of k is + * given by the formula frame_type-251. + */ + public static final int APPEND_FRAME = 252; // to 254 // fc-fe + + /** + * Full frame + */ + public static final int FULL_FRAME = 255; // ff + + private static final int MAX_SHORT = 65535; + + /** + * A <code>List</code> of <code>StackMapFrame</code> instances. + */ + private List frames; + + public StackMapTableAttribute() { + super("StackMapTable"); + } + + public StackMapTableAttribute(List frames) { + this(); + this.frames = frames; + } + + public List getFrames() { + return frames; + } + + public StackMapFrame getFrame(Label label) { + for (int i = 0; i < frames.size(); i++) { + StackMapFrame frame = (StackMapFrame) frames.get(i); + if (frame.label == label) { + return frame; + } + } + return null; + } + + public boolean isUnknown() { + return false; + } + + public boolean isCodeAttribute() { + return true; + } + + protected Attribute read( + ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + + ArrayList frames = new ArrayList(); + + // note that this is not the size of Code attribute + boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SHORT; + boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SHORT; + boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SHORT; + + int offset = 0; + + int methodOff = getMethodOff(cr, codeOff, buf); + StackMapFrame frame = new StackMapFrame(getLabel(offset, labels), + calculateLocals(cr.readClass(cr.header + 2, buf), // owner + cr.readUnsignedShort(methodOff), // method access + cr.readUTF8(methodOff + 2, buf), // method name + cr.readUTF8(methodOff + 4, buf)), // method desc + Collections.EMPTY_LIST); + frames.add(frame); + + // System.err.println( cr.readUTF8( methodOff + 2, buf)); + // System.err.println( offset +" delta:" + 0 +" : "+ frame); + + int size; + if (isExtCodeSize) { + size = cr.readInt(off); + off += 4; + } else { + size = cr.readUnsignedShort(off); + off += 2; + } + + for (; size > 0; size--) { + int tag = cr.readByte(off); // & 0xff; + off++; + + List stack; + List locals; + + int offsetDelta; + if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { // SAME_FRAME + offsetDelta = tag; + + locals = new ArrayList(frame.locals); + stack = Collections.EMPTY_LIST; + + } else if (tag < RESERVED) { // SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME; + + locals = new ArrayList(frame.locals); + stack = new ArrayList(); + // read verification_type_info stack[1]; + off = readType(stack, isExtCodeSize, cr, off, labels, buf); + + } else { + if (isExtCodeSize) { + offsetDelta = cr.readInt(off); + off += 4; + } else { + offsetDelta = cr.readUnsignedShort(off); + off += 2; + } + + if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED + locals = new ArrayList(frame.locals); + stack = new ArrayList(); + // read verification_type_info stack[1]; + off = readType(stack, isExtCodeSize, cr, off, labels, buf); + + } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) { // CHOP_FRAME + stack = Collections.EMPTY_LIST; + + int k = SAME_FRAME_EXTENDED - tag; + // copy locals from prev frame and chop last k + locals = new ArrayList(frame.locals.subList(0, + frame.locals.size() - k)); + + } else if (tag == SAME_FRAME_EXTENDED) { // SAME_FRAME_EXTENDED + stack = Collections.EMPTY_LIST; + locals = new ArrayList(frame.locals); + + } else if ( /* tag>=APPEND && */tag < FULL_FRAME) { // APPEND_FRAME + stack = Collections.EMPTY_LIST; + + // copy locals from prev frame and append new k + locals = new ArrayList(frame.locals); + for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) { + off = readType(locals, + isExtCodeSize, + cr, + off, + labels, + buf); + } + + } else if (tag == FULL_FRAME) { // FULL_FRAME + // read verification_type_info locals[number_of_locals]; + locals = new ArrayList(); + off = readTypes(locals, + isExtLocals, + isExtCodeSize, + cr, + off, + labels, + buf); + + // read verification_type_info stack[number_of_stack_items]; + stack = new ArrayList(); + off = readTypes(stack, + isExtStack, + isExtCodeSize, + cr, + off, + labels, + buf); + + } else { + throw new RuntimeException("Unknown frame type " + tag + + " after offset " + offset); + + } + } + + offset += offsetDelta; + + Label offsetLabel = getLabel(offset, labels); + + frame = new StackMapFrame(offsetLabel, locals, stack); + frames.add(frame); + // System.err.println( tag +" " + offset +" delta:" + offsetDelta + + // " frameType:"+ frameType+" : "+ frame); + + offset++; + } + + return new StackMapTableAttribute(frames); + } + + protected ByteVector write( + ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector bv = new ByteVector(); + // TODO verify this value (MAX_SHORT) + boolean isExtCodeSize = code != null && code.length > MAX_SHORT; + writeSize(frames.size() - 1, bv, isExtCodeSize); + + if (frames.size() < 2) { + return bv; + } + + boolean isExtLocals = maxLocals > MAX_SHORT; + boolean isExtStack = maxStack > MAX_SHORT; + + // skip the first frame + StackMapFrame frame = (StackMapFrame) frames.get(0); + List locals = frame.locals; + int offset = frame.label.getOffset(); + + for (int i = 1; i < frames.size(); i++) { + frame = (StackMapFrame) frames.get(i); + + List clocals = frame.locals; + List cstack = frame.stack; + int coffset = frame.label.getOffset(); + + int clocalsSize = clocals.size(); + int cstackSize = cstack.size(); + + int localsSize = locals.size(); + + int delta = coffset - offset; + + int type = FULL_FRAME; + int k = 0; + if (cstackSize == 0) { + k = clocalsSize - localsSize; + switch (k) { + case -3: + case -2: + case -1: + type = CHOP_FRAME; // CHOP or FULL + localsSize = clocalsSize; // for full_frame check + break; + + case 0: + // SAME, SAME_EXTENDED or FULL + type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; + break; + + case 1: + case 2: + case 3: + type = APPEND_FRAME; // APPEND or FULL + break; + } + } else if (localsSize == clocalsSize && cstackSize == 1) { + // SAME_LOCAL_1_STACK or FULL + type = delta < 63 + ? SAME_LOCALS_1_STACK_ITEM_FRAME + : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; + } + + if (type != FULL_FRAME) { + // verify if stack and locals are the same + for (int j = 0; j < localsSize && type != FULL_FRAME; j++) { + if (!locals.get(j).equals(clocals.get(j))) + type = FULL_FRAME; + } + } + + switch (type) { + case SAME_FRAME: + bv.putByte(delta); + break; + + case SAME_LOCALS_1_STACK_ITEM_FRAME: + bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + writeTypeInfos(bv, cw, cstack, 0, 1); + break; + + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED); + writeSize(delta, bv, isExtCodeSize); + writeTypeInfos(bv, cw, cstack, 0, 1); + break; + + case SAME_FRAME_EXTENDED: + bv.putByte(SAME_FRAME_EXTENDED); + writeSize(delta, bv, isExtCodeSize); + break; + + case CHOP_FRAME: + bv.putByte(SAME_FRAME_EXTENDED + k); // negative k + writeSize(delta, bv, isExtCodeSize); + break; + + case APPEND_FRAME: + bv.putByte(SAME_FRAME_EXTENDED + k); // positive k + writeSize(delta, bv, isExtCodeSize); + writeTypeInfos(bv, + cw, + clocals, + clocalsSize - 1, + clocalsSize); + break; + + case FULL_FRAME: + bv.putByte(FULL_FRAME); + writeSize(delta, bv, isExtCodeSize); + writeSize(clocalsSize, bv, isExtLocals); + writeTypeInfos(bv, cw, clocals, 0, clocalsSize); + writeSize(cstackSize, bv, isExtStack); + writeTypeInfos(bv, cw, cstack, 0, cstackSize); + break; + + default: + throw new RuntimeException(); + } + offset = coffset + 1; // compensating non first offset + locals = clocals; + } + return bv; + } + + private void writeSize(int delta, ByteVector bv, boolean isExt) { + if (isExt) { + bv.putInt(delta); + } else { + bv.putShort(delta); + } + } + + private void writeTypeInfos( + ByteVector bv, + ClassWriter cw, + List info, + int start, + int end) + { + for (int j = start; j < end; j++) { + StackMapType typeInfo = (StackMapType) info.get(j); + bv.putByte(typeInfo.getType()); + + switch (typeInfo.getType()) { + case StackMapType.ITEM_Object: // + bv.putShort(cw.newClass(typeInfo.getObject())); + break; + + case StackMapType.ITEM_Uninitialized: // + bv.putShort(typeInfo.getLabel().getOffset()); + break; + + } + } + } + + public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) { + int off = cr.header + 6; + + int interfacesCount = cr.readUnsignedShort(off); + off += 2 + interfacesCount * 2; + + int fieldsCount = cr.readUnsignedShort(off); + off += 2; + for (; fieldsCount > 0; --fieldsCount) { + int attrCount = cr.readUnsignedShort(off + 6); // field attributes + off += 8; + for (; attrCount > 0; --attrCount) { + off += 6 + cr.readInt(off + 2); + } + } + + int methodsCount = cr.readUnsignedShort(off); + off += 2; + for (; methodsCount > 0; --methodsCount) { + int methodOff = off; + int attrCount = cr.readUnsignedShort(off + 6); // method attributes + off += 8; + for (; attrCount > 0; --attrCount) { + String attrName = cr.readUTF8(off, buf); + off += 6; + if (attrName.equals("Code")) { + if (codeOff == off) { + return methodOff; + } + } + off += cr.readInt(off - 4); + } + } + + return -1; + } + + /** + * Use method signature and access flags to resolve initial locals state. + * + * @param className name of the method's owner class. + * @param access access flags of the method. + * @param methodName name of the method. + * @param methodDesc descriptor of the method. + * @return list of <code>StackMapType</code> instances representing locals + * for an initial frame. + */ + public static List calculateLocals( + String className, + int access, + String methodName, + String methodDesc) + { + List locals = new ArrayList(); + + // TODO + if ("<init>".equals(methodName) + && !className.equals("java/lang/Object")) + { + StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis); + typeInfo.setObject(className); // this + locals.add(typeInfo); + } else if ((access & Opcodes.ACC_STATIC) == 0) { + StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object); + typeInfo.setObject(className); // this + locals.add(typeInfo); + } + + Type[] types = Type.getArgumentTypes(methodDesc); + for (int i = 0; i < types.length; i++) { + Type t = types[i]; + StackMapType smt; + switch (t.getSort()) { + case Type.LONG: + smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long); + break; + case Type.DOUBLE: + smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double); + break; + + case Type.FLOAT: + smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float); + break; + + case Type.ARRAY: + case Type.OBJECT: + smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object); + smt.setObject(t.getDescriptor()); // TODO verify name + break; + + default: + smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer); + break; + } + } + + return locals; + } + + private int readTypes( + List info, + boolean isExt, + boolean isExtCodeSize, + ClassReader cr, + int off, + Label[] labels, + char[] buf) + { + int n = 0; + if (isExt) { + n = cr.readInt(off); + off += 4; + } else { + n = cr.readUnsignedShort(off); + off += 2; + } + + for (; n > 0; n--) { + off = readType(info, isExtCodeSize, cr, off, labels, buf); + } + return off; + } + + private int readType( + List info, + boolean isExtCodeSize, + ClassReader cr, + int off, + Label[] labels, + char[] buf) + { + int itemType = cr.readByte(off++); + StackMapType typeInfo = StackMapType.getTypeInfo(itemType); + info.add(typeInfo); + switch (itemType) { + // case StackMapType.ITEM_Long: // + // case StackMapType.ITEM_Double: // + // info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top)); + // break; + + case StackMapType.ITEM_Object: // + typeInfo.setObject(cr.readClass(off, buf)); + off += 2; + break; + + case StackMapType.ITEM_Uninitialized: // + int offset; + if (isExtCodeSize) { + offset = cr.readInt(off); + off += 4; + } else { + offset = cr.readUnsignedShort(off); + off += 2; + } + + typeInfo.setLabel(getLabel(offset, labels)); + break; + } + return off; + } + + private Label getLabel(int offset, Label[] labels) { + Label l = labels[offset]; + if (l != null) { + return l; + } + return labels[offset] = new Label(); + } + + public String toString() { + StringBuffer sb = new StringBuffer("StackMapTable["); + for (int i = 0; i < frames.size(); i++) { + sb.append('\n').append('[').append(frames.get(i)).append(']'); + } + sb.append("\n]"); + return sb.toString(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapType.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapType.java new file mode 100644 index 000000000..30cadf1fc --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/attrs/StackMapType.java @@ -0,0 +1,114 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.attrs; + +import org.objectweb.asm.Label; + +/** + * Verification type info used by {@link StackMapAttribute}. + * + * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected + * Limited Device Configuration 1.1</a> + * + * @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM" + * + * @author Eugene Kuleshov + */ + +public class StackMapType { + + public static final int ITEM_Top = 0; + public static final int ITEM_Integer = 1; + public static final int ITEM_Float = 2; + public static final int ITEM_Double = 3; + public static final int ITEM_Long = 4; + public static final int ITEM_Null = 5; + public static final int ITEM_UninitializedThis = 6; + public static final int ITEM_Object = 7; + public static final int ITEM_Uninitialized = 8; + + public static final String[] ITEM_NAMES = { + "Top", + "Integer", + "Float", + "Double", + "Long", + "Null", + "UninitializedThis", + "Object", + "Uninitialized" }; + + private int type; + private Label offset; + private String object; + + private StackMapType(int type) { + this.type = type; + } + + public int getType() { + return type; + } + + public static StackMapType getTypeInfo(int itemType) { + if (itemType < ITEM_Top || itemType > ITEM_Uninitialized) { + throw new IllegalArgumentException("" + itemType); + } + return new StackMapType(itemType); + } + + public void setLabel(Label offset) { + this.offset = offset; + } + + public void setObject(String object) { + this.object = object; + } + + public Label getLabel() { + return offset; + } + + public String getObject() { + return object; + } + + public String toString() { + StringBuffer sb = new StringBuffer(ITEM_NAMES[type]); + if (type == ITEM_Object) { + sb.append(":").append(object); + } + if (type == ITEM_Uninitialized) { + sb.append(":L").append(System.identityHashCode(offset)); + } + return sb.toString(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/AdviceAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/AdviceAdapter.java new file mode 100644 index 000000000..13fbaa68c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/AdviceAdapter.java @@ -0,0 +1,642 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * A <code>MethodAdapter</code> to dispatch method body instruction + * <p> + * The behavior is like this: + * <ol> + * + * <li>as long as the INVOKESPECIAL for the object initialization has not been + * reached, every bytecode instruction is dispatched in the ctor code visitor</li> + * + * <li>when this one is reached, it is only added in the ctor code visitor and + * a JP invoke is added</li> + * <li>after that, only the other code visitor receives the instructions</li> + * + * </ol> + * + * @author Eugene Kuleshov + * @author Eric Bruneton + */ +public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { + private static final Object THIS = new Object(); + private static final Object OTHER = new Object(); + + protected int methodAccess; + protected String methodDesc; + + private boolean constructor; + private boolean superInitialized; + private ArrayList stackFrame; + private HashMap branches; + + + /** + * Creates a new {@link AdviceAdapter}. + * + * @param mv the method visitor to which this adapter delegates calls. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + */ + public AdviceAdapter(MethodVisitor mv, int access, String name, String desc) { + super(mv, access, name, desc); + methodAccess = access; + methodDesc = desc; + + constructor = "<init>".equals(name); + if (!constructor) { + superInitialized = true; + onMethodEnter(); + } else { + stackFrame = new ArrayList(); + branches = new HashMap(); + } + } + + public void visitLabel(Label label) { + mv.visitLabel(label); + + if (constructor && branches != null) { + ArrayList frame = (ArrayList) branches.get(label); + if (frame != null) { + stackFrame = frame; + branches.remove(label); + } + } + } + + public void visitInsn(int opcode) { + if (constructor) { + switch (opcode) { + case RETURN: // empty stack + onMethodExit(opcode); + break; + + case IRETURN: // 1 before n/a after + case FRETURN: // 1 before n/a after + case ARETURN: // 1 before n/a after + case ATHROW: // 1 before n/a after + popValue(); + popValue(); + onMethodExit(opcode); + break; + + case LRETURN: // 2 before n/a after + case DRETURN: // 2 before n/a after + popValue(); + popValue(); + onMethodExit(opcode); + break; + + case NOP: + case LALOAD: // remove 2 add 2 + case DALOAD: // remove 2 add 2 + case LNEG: + case DNEG: + case FNEG: + case INEG: + case L2D: + case D2L: + case F2I: + case I2B: + case I2C: + case I2S: + case I2F: + case Opcodes.ARRAYLENGTH: + break; + + case ACONST_NULL: + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + case FCONST_0: + case FCONST_1: + case FCONST_2: + case F2L: // 1 before 2 after + case F2D: + case I2L: + case I2D: + pushValue(OTHER); + break; + + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + pushValue(OTHER); + pushValue(OTHER); + break; + + case IALOAD: // remove 2 add 1 + case FALOAD: // remove 2 add 1 + case AALOAD: // remove 2 add 1 + case BALOAD: // remove 2 add 1 + case CALOAD: // remove 2 add 1 + case SALOAD: // remove 2 add 1 + case POP: + case IADD: + case FADD: + case ISUB: + case LSHL: // 3 before 2 after + case LSHR: // 3 before 2 after + case LUSHR: // 3 before 2 after + case L2I: // 2 before 1 after + case L2F: // 2 before 1 after + case D2I: // 2 before 1 after + case D2F: // 2 before 1 after + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: // 2 before 1 after + case FCMPG: // 2 before 1 after + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case MONITORENTER: + case MONITOREXIT: + popValue(); + break; + + case POP2: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LADD: + case LAND: + case LOR: + case LXOR: + case DADD: + case DMUL: + case DSUB: + case DDIV: + case DREM: + popValue(); + popValue(); + break; + + case IASTORE: + case FASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case LCMP: // 4 before 1 after + case DCMPL: + case DCMPG: + popValue(); + popValue(); + popValue(); + break; + + case LASTORE: + case DASTORE: + popValue(); + popValue(); + popValue(); + popValue(); + break; + + case DUP: + pushValue(peekValue()); + break; + + case DUP_X1: + // TODO optimize this + { + Object o1 = popValue(); + Object o2 = popValue(); + pushValue(o1); + pushValue(o2); + pushValue(o1); + } + break; + + case DUP_X2: + // TODO optimize this + { + Object o1 = popValue(); + Object o2 = popValue(); + Object o3 = popValue(); + pushValue(o1); + pushValue(o3); + pushValue(o2); + pushValue(o1); + } + break; + + case DUP2: + // TODO optimize this + { + Object o1 = popValue(); + Object o2 = popValue(); + pushValue(o2); + pushValue(o1); + pushValue(o2); + pushValue(o1); + } + break; + + case DUP2_X1: + // TODO optimize this + { + Object o1 = popValue(); + Object o2 = popValue(); + Object o3 = popValue(); + pushValue(o2); + pushValue(o1); + pushValue(o3); + pushValue(o2); + pushValue(o1); + } + break; + + case DUP2_X2: + // TODO optimize this + { + Object o1 = popValue(); + Object o2 = popValue(); + Object o3 = popValue(); + Object o4 = popValue(); + pushValue(o2); + pushValue(o1); + pushValue(o4); + pushValue(o3); + pushValue(o2); + pushValue(o1); + } + break; + + case SWAP: { + Object o1 = popValue(); + Object o2 = popValue(); + pushValue(o1); + pushValue(o2); + } + break; + } + } else { + switch (opcode) { + case RETURN: + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + case ATHROW: + onMethodExit(opcode); + break; + } + } + mv.visitInsn(opcode); + } + + public void visitVarInsn(int opcode, int var) { + super.visitVarInsn(opcode, var); + + if (constructor) { + switch (opcode) { + case ILOAD: + case FLOAD: + pushValue(OTHER); + break; + case LLOAD: + case DLOAD: + pushValue(OTHER); + pushValue(OTHER); + break; + case ALOAD: + pushValue(var == 0 ? THIS : OTHER); + break; + case ASTORE: + case ISTORE: + case FSTORE: + popValue(); + break; + case LSTORE: + case DSTORE: + popValue(); + popValue(); + break; + } + } + } + + public void visitFieldInsn( + int opcode, + String owner, + String name, + String desc) + { + mv.visitFieldInsn(opcode, owner, name, desc); + + if (constructor) { + char c = desc.charAt(0); + boolean longOrDouble = c == 'J' || c == 'D'; + switch (opcode) { + case GETSTATIC: + pushValue(OTHER); + if (longOrDouble) { + pushValue(OTHER); + } + break; + case PUTSTATIC: + popValue(); + if(longOrDouble) { + popValue(); + } + break; + case PUTFIELD: + popValue(); + if(longOrDouble) { + popValue(); + popValue(); + } + break; + // case GETFIELD: + default: + if (longOrDouble) { + pushValue(OTHER); + } + } + } + } + + public void visitIntInsn(int opcode, int operand) { + mv.visitIntInsn(opcode, operand); + + if (constructor) { + switch (opcode) { + case BIPUSH: + case SIPUSH: + pushValue(OTHER); + } + } + } + + public void visitLdcInsn(Object cst) { + mv.visitLdcInsn(cst); + + if (constructor) { + pushValue(OTHER); + if (cst instanceof Double || cst instanceof Long) { + pushValue(OTHER); + } + } + } + + public void visitMultiANewArrayInsn(String desc, int dims) { + mv.visitMultiANewArrayInsn(desc, dims); + + if (constructor) { + for (int i = 0; i < dims; i++) { + popValue(); + } + pushValue(OTHER); + } + } + + public void visitTypeInsn(int opcode, String name) { + mv.visitTypeInsn(opcode, name); + + // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack + if (constructor && opcode == NEW) { + pushValue(OTHER); + } + } + + public void visitMethodInsn( + int opcode, + String owner, + String name, + String desc) + { + mv.visitMethodInsn(opcode, owner, name, desc); + + if (constructor) { + Type[] types = Type.getArgumentTypes(desc); + for (int i = 0; i < types.length; i++) { + popValue(); + if (types[i].getSize() == 2) { + popValue(); + } + } + switch (opcode) { + // case INVOKESTATIC: + // break; + + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + popValue(); // objectref + break; + + case INVOKESPECIAL: + Object type = popValue(); // objectref + if (type == THIS && !superInitialized) { + onMethodEnter(); + superInitialized = true; + // once super has been initialized it is no longer + // necessary to keep track of stack state + constructor = false; + } + break; + } + + Type returnType = Type.getReturnType(desc); + if (returnType != Type.VOID_TYPE) { + pushValue(OTHER); + if (returnType.getSize() == 2) { + pushValue(OTHER); + } + } + } + } + + public void visitJumpInsn(int opcode, Label label) { + mv.visitJumpInsn(opcode, label); + + if (constructor) { + switch (opcode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IFNULL: + case IFNONNULL: + popValue(); + break; + + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + popValue(); + popValue(); + break; + + case JSR: + pushValue(OTHER); + break; + } + addBranch(label); + } + } + + public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + + if (constructor) { + popValue(); + addBranches(dflt, labels); + } + } + + public void visitTableSwitchInsn( + int min, + int max, + Label dflt, + Label[] labels) + { + mv.visitTableSwitchInsn(min, max, dflt, labels); + + if (constructor) { + popValue(); + addBranches(dflt, labels); + } + } + + private void addBranches(Label dflt, Label[] labels) { + addBranch(dflt); + for (int i = 0; i < labels.length; i++) { + addBranch(labels[i]); + } + } + + private void addBranch(Label label) { + if (branches.containsKey(label)) { + return; + } + ArrayList frame = new ArrayList(); + frame.addAll(stackFrame); + branches.put(label, frame); + } + + private Object popValue() { + return stackFrame.remove(stackFrame.size()-1); + } + + private Object peekValue() { + return stackFrame.get(stackFrame.size()-1); + } + + private void pushValue(Object o) { + stackFrame.add(o); + } + + /** + * Called at the beginning of the method or after super + * class class call in the constructor. + * <br><br> + * + * <i>Custom code can use or change all the local variables, + * but should not change state of the stack.</i> + */ + protected abstract void onMethodEnter(); + + /** + * Called before explicit exit from the method using either + * return or throw. Top element on the stack contains the + * return value or exception instance. For example: + * + * <pre> + * public void onMethodExit(int opcode) { + * if(opcode==RETURN) { + * visitInsn(ACONST_NULL); + * } else if(opcode==ARETURN || opcode==ATHROW) { + * dup(); + * } else { + * if(opcode==LRETURN || opcode==DRETURN) { + * dup2(); + * } else { + * dup(); + * } + * box(Type.getReturnType(this.methodDesc)); + * } + * visitIntInsn(SIPUSH, opcode); + * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V"); + * } + * + * // an actual call back method + * public static void onExit(int opcode, Object param) { + * ... + * </pre> + * + * <br><br> + * + * <i>Custom code can use or change all the local variables, + * but should not change state of the stack.</i> + * + * @param opcode one of the RETURN, IRETURN, FRETURN, + * ARETURN, LRETURN, DRETURN or ATHROW + * + */ + protected abstract void onMethodExit(int opcode); + + // TODO onException, onMethodCall + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/EmptyVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/EmptyVisitor.java new file mode 100644 index 000000000..d979659bd --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/EmptyVisitor.java @@ -0,0 +1,211 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; + +/** + * An empty implementation of the ASM visitor interfaces. + * + * @author Eric Bruneton + */ +public class EmptyVisitor implements + ClassVisitor, + FieldVisitor, + MethodVisitor, + AnnotationVisitor +{ + + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) + { + } + + public void visitSource(String source, String debug) { + } + + public void visitOuterClass(String owner, String name, String desc) { + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return this; + } + + public void visitAttribute(Attribute attr) { + } + + public void visitInnerClass( + String name, + String outerName, + String innerName, + int access) + { + } + + public FieldVisitor visitField( + int access, + String name, + String desc, + String signature, + Object value) + { + return this; + } + + public MethodVisitor visitMethod( + int access, + String name, + String desc, + String signature, + String[] exceptions) + { + return this; + } + + public void visitEnd() { + } + + public AnnotationVisitor visitAnnotationDefault() { + return this; + } + + public AnnotationVisitor visitParameterAnnotation( + int parameter, + String desc, + boolean visible) + { + return this; + } + + public void visitCode() { + } + + public void visitInsn(int opcode) { + } + + public void visitIntInsn(int opcode, int operand) { + } + + public void visitVarInsn(int opcode, int var) { + } + + public void visitTypeInsn(int opcode, String desc) { + } + + public void visitFieldInsn( + int opcode, + String owner, + String name, + String desc) + { + } + + public void visitMethodInsn( + int opcode, + String owner, + String name, + String desc) + { + } + + public void visitJumpInsn(int opcode, Label label) { + } + + public void visitLabel(Label label) { + } + + public void visitLdcInsn(Object cst) { + } + + public void visitIincInsn(int var, int increment) { + } + + public void visitTableSwitchInsn( + int min, + int max, + Label dflt, + Label labels[]) + { + } + + public void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]) { + } + + public void visitMultiANewArrayInsn(String desc, int dims) { + } + + public void visitTryCatchBlock( + Label start, + Label end, + Label handler, + String type) + { + } + + public void visitLocalVariable( + String name, + String desc, + String signature, + Label start, + Label end, + int index) + { + } + + public void visitLineNumber(int line, Label start) { + } + + public void visitMaxs(int maxStack, int maxLocals) { + } + + public void visit(String name, Object value) { + } + + public void visitEnum(String name, String desc, String value) { + } + + public AnnotationVisitor visitAnnotation(String name, String desc) { + return this; + } + + public AnnotationVisitor visitArray(String name) { + return this; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/GeneratorAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/GeneratorAdapter.java new file mode 100644 index 000000000..aacb27cf5 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/GeneratorAdapter.java @@ -0,0 +1,1454 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate + * code. For example, using this adapter, the class below + * + * <pre> + * public class Example { + * public static void main(String[] args) { + * System.out.println("Hello world!"); + * } + * } + * </pre> + * + * can be generated as follows: + * + * <pre> + * ClassWriter cw = new ClassWriter(true); + * cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); + * + * Method m = Method.getMethod("void <init> ()"); + * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); + * mg.loadThis(); + * mg.invokeConstructor(Type.getType(Object.class), m); + * mg.returnValue(); + * mg.endMethod(); + * + * m = Method.getMethod("void main (String[])"); + * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); + * mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); + * mg.push("Hello world!"); + * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); + * mg.returnValue(); + * mg.endMethod(); + * + * cw.visitEnd(); + * </pre> + * + * @author Juozas Baliuka + * @author Chris Nokleberg + * @author Eric Bruneton + */ +public class GeneratorAdapter extends LocalVariablesSorter { + + private final static Type BYTE_TYPE = Type.getType("Ljava/lang/Byte;"); + + private final static Type BOOLEAN_TYPE = Type.getType("Ljava/lang/Boolean;"); + + private final static Type SHORT_TYPE = Type.getType("Ljava/lang/Short;"); + + private final static Type CHARACTER_TYPE = Type.getType("Ljava/lang/Character;"); + + private final static Type INTEGER_TYPE = Type.getType("Ljava/lang/Integer;"); + + private final static Type FLOAT_TYPE = Type.getType("Ljava/lang/Float;"); + + private final static Type LONG_TYPE = Type.getType("Ljava/lang/Long;"); + + private final static Type DOUBLE_TYPE = Type.getType("Ljava/lang/Double;"); + + private final static Type NUMBER_TYPE = Type.getType("Ljava/lang/Number;"); + + private final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + + private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()"); + + private final static Method CHAR_VALUE = Method.getMethod("char charValue()"); + + private final static Method INT_VALUE = Method.getMethod("int intValue()"); + + private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()"); + + private final static Method LONG_VALUE = Method.getMethod("long longValue()"); + + private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()"); + + /** + * Constant for the {@link #math math} method. + */ + public final static int ADD = Opcodes.IADD; + + /** + * Constant for the {@link #math math} method. + */ + public final static int SUB = Opcodes.ISUB; + + /** + * Constant for the {@link #math math} method. + */ + public final static int MUL = Opcodes.IMUL; + + /** + * Constant for the {@link #math math} method. + */ + public final static int DIV = Opcodes.IDIV; + + /** + * Constant for the {@link #math math} method. + */ + public final static int REM = Opcodes.IREM; + + /** + * Constant for the {@link #math math} method. + */ + public final static int NEG = Opcodes.INEG; + + /** + * Constant for the {@link #math math} method. + */ + public final static int SHL = Opcodes.ISHL; + + /** + * Constant for the {@link #math math} method. + */ + public final static int SHR = Opcodes.ISHR; + + /** + * Constant for the {@link #math math} method. + */ + public final static int USHR = Opcodes.IUSHR; + + /** + * Constant for the {@link #math math} method. + */ + public final static int AND = Opcodes.IAND; + + /** + * Constant for the {@link #math math} method. + */ + public final static int OR = Opcodes.IOR; + + /** + * Constant for the {@link #math math} method. + */ + public final static int XOR = Opcodes.IXOR; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int EQ = Opcodes.IFEQ; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int NE = Opcodes.IFNE; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int LT = Opcodes.IFLT; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int GE = Opcodes.IFGE; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int GT = Opcodes.IFGT; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public final static int LE = Opcodes.IFLE; + + /** + * Access flags of the method visited by this adapter. + */ + private final int access; + + /** + * Return type of the method visited by this adapter. + */ + private final Type returnType; + + /** + * Argument types of the method visited by this adapter. + */ + private final Type[] argumentTypes; + + /** + * Types of the local variables of the method visited by this adapter. + */ + private final List localTypes; + + /** + * Creates a new {@link GeneratorAdapter}. + * + * @param mv the method visitor to which this adapter delegates calls. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + */ + public GeneratorAdapter( + MethodVisitor mv, + int access, + String name, + String desc) + { + super(access, desc, mv); + this.access = access; + this.returnType = Type.getReturnType(desc); + this.argumentTypes = Type.getArgumentTypes(desc); + this.localTypes = new ArrayList(); + } + + /** + * Creates a new {@link GeneratorAdapter}. + * + * @param access access flags of the adapted method. + * @param method the adapted method. + * @param mv the method visitor to which this adapter delegates calls. + */ + public GeneratorAdapter( + final int access, + final Method method, + final MethodVisitor mv) + { + super(access, method.getDescriptor(), mv); + this.access = access; + this.returnType = method.getReturnType(); + this.argumentTypes = method.getArgumentTypes(); + this.localTypes = new ArrayList(); + } + + /** + * Creates a new {@link GeneratorAdapter}. + * + * @param access access flags of the adapted method. + * @param method the adapted method. + * @param signature the signature of the adapted method (may be + * <tt>null</tt>). + * @param exceptions the exceptions thrown by the adapted method (may be + * <tt>null</tt>). + * @param cv the class visitor to which this adapter delegates calls. + */ + public GeneratorAdapter( + final int access, + final Method method, + final String signature, + final Type[] exceptions, + final ClassVisitor cv) + { + this(access, method, cv.visitMethod(access, + method.getName(), + method.getDescriptor(), + signature, + getInternalNames(exceptions))); + } + + /** + * Returns the internal names of the given types. + * + * @param types a set of types. + * @return the internal names of the given types. + */ + private static String[] getInternalNames(final Type[] types) { + if (types == null) { + return null; + } + String[] names = new String[types.length]; + for (int i = 0; i < names.length; ++i) { + names[i] = types[i].getInternalName(); + } + return names; + } + + // ------------------------------------------------------------------------ + // Instructions to push constants on the stack + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final boolean value) { + push(value ? 1 : 0); + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final int value) { + if (value >= -1 && value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } else { + mv.visitLdcInsn(new Integer(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final long value) { + if (value == 0L || value == 1L) { + mv.visitInsn(Opcodes.LCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Long(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final float value) { + int bits = Float.floatToIntBits(value); + if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 + mv.visitInsn(Opcodes.FCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Float(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final double value) { + long bits = Double.doubleToLongBits(value); + if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d + mv.visitInsn(Opcodes.DCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Double(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. May be <tt>null</tt>. + */ + public void push(final String value) { + if (value == null) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else { + mv.visitLdcInsn(value); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value the value to be pushed on the stack. + */ + public void push(final Type value) { + if (value == null) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else { + mv.visitLdcInsn(value); + } + } + + // ------------------------------------------------------------------------ + // Instructions to load and store method arguments + // ------------------------------------------------------------------------ + + /** + * Returns the index of the given method argument in the frame's local + * variables array. + * + * @param arg the index of a method argument. + * @return the index of the given method argument in the frame's local + * variables array. + */ + private int getArgIndex(final int arg) { + int index = ((access & Opcodes.ACC_STATIC) == 0 ? 1 : 0); + for (int i = 0; i < arg; i++) { + index += argumentTypes[i].getSize(); + } + return index; + } + + /** + * Generates the instruction to push a local variable on the stack. + * + * @param type the type of the local variable to be loaded. + * @param index an index in the frame's local variables array. + */ + private void loadInsn(final Type type, final int index) { + mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); + } + + /** + * Generates the instruction to store the top stack value in a local + * variable. + * + * @param type the type of the local variable to be stored. + * @param index an index in the frame's local variables array. + */ + private void storeInsn(final Type type, final int index) { + mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); + } + + /** + * Generates the instruction to load 'this' on the stack. + */ + public void loadThis() { + if ((access & Opcodes.ACC_STATIC) != 0) { + throw new IllegalStateException("no 'this' pointer within static method"); + } + mv.visitVarInsn(Opcodes.ALOAD, 0); + } + + /** + * Generates the instruction to load the given method argument on the stack. + * + * @param arg the index of a method argument. + */ + public void loadArg(final int arg) { + loadInsn(argumentTypes[arg], getArgIndex(arg)); + } + + /** + * Generates the instructions to load the given method arguments on the + * stack. + * + * @param arg the index of the first method argument to be loaded. + * @param count the number of method arguments to be loaded. + */ + public void loadArgs(final int arg, final int count) { + int index = getArgIndex(arg); + for (int i = 0; i < count; ++i) { + Type t = argumentTypes[arg + i]; + loadInsn(t, index); + index += t.getSize(); + } + } + + /** + * Generates the instructions to load all the method arguments on the stack. + */ + public void loadArgs() { + loadArgs(0, argumentTypes.length); + } + + /** + * Generates the instructions to load all the method arguments on the stack, + * as a single object array. + */ + public void loadArgArray() { + push(argumentTypes.length); + newArray(OBJECT_TYPE); + for (int i = 0; i < argumentTypes.length; i++) { + dup(); + push(i); + loadArg(i); + box(argumentTypes[i]); + arrayStore(OBJECT_TYPE); + } + } + + /** + * Generates the instruction to store the top stack value in the given + * method argument. + * + * @param arg the index of a method argument. + */ + public void storeArg(final int arg) { + storeInsn(argumentTypes[arg], getArgIndex(arg)); + } + + // ------------------------------------------------------------------------ + // Instructions to load and store local variables + // ------------------------------------------------------------------------ + + /** + * Creates a new local variable of the given type. + * + * @param type the type of the local variable to be created. + * @return the identifier of the newly created local variable. + */ + public int newLocal(final Type type) { + int local = super.newLocal(type.getSize()); + setLocalType(local, type); + return local; + } + + /** + * Returns the type of the given local variable. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + * @return the type of the given local variable. + */ + public Type getLocalType(final int local) { + return (Type) localTypes.get(local - firstLocal); + } + + /** + * Sets the current type of the given local variable. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + * @param type the type of the value being stored in the local variable + */ + private void setLocalType(final int local, final Type type) { + int index = local - firstLocal; + while (localTypes.size() < index + 1) + localTypes.add(null); + localTypes.set(index, type); + } + + /** + * Generates the instruction to load the given local variable on the stack. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + */ + public void loadLocal(final int local) { + loadInsn(getLocalType(local), local); + } + + /** + * Generates the instruction to load the given local variable on the stack. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + * @param type the type of this local variable. + */ + public void loadLocal(final int local, final Type type) { + setLocalType(local, type); + loadInsn(type, local); + } + + /** + * Generates the instruction to store the top stack value in the given local + * variable. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + */ + public void storeLocal(final int local) { + storeInsn(getLocalType(local), local); + } + + /** + * Generates the instruction to store the top stack value in the given local + * variable. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + * @param type the type of this local variable. + */ + public void storeLocal(final int local, final Type type) { + setLocalType(local, type); + storeInsn(type, local); + } + + /** + * Generates the instruction to load an element from an array. + * + * @param type the type of the array element to be loaded. + */ + public void arrayLoad(final Type type) { + mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); + } + + /** + * Generates the instruction to store an element in an array. + * + * @param type the type of the array element to be stored. + */ + public void arrayStore(final Type type) { + mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); + } + + // ------------------------------------------------------------------------ + // Instructions to manage the stack + // ------------------------------------------------------------------------ + + /** + * Generates a POP instruction. + */ + public void pop() { + mv.visitInsn(Opcodes.POP); + } + + /** + * Generates a POP2 instruction. + */ + public void pop2() { + mv.visitInsn(Opcodes.POP2); + } + + /** + * Generates a DUP instruction. + */ + public void dup() { + mv.visitInsn(Opcodes.DUP); + } + + /** + * Generates a DUP2 instruction. + */ + public void dup2() { + mv.visitInsn(Opcodes.DUP2); + } + + /** + * Generates a DUP_X1 instruction. + */ + public void dupX1() { + mv.visitInsn(Opcodes.DUP_X1); + } + + /** + * Generates a DUP_X2 instruction. + */ + public void dupX2() { + mv.visitInsn(Opcodes.DUP_X2); + } + + /** + * Generates a DUP2_X1 instruction. + */ + public void dup2X1() { + mv.visitInsn(Opcodes.DUP2_X1); + } + + /** + * Generates a DUP2_X2 instruction. + */ + public void dup2X2() { + mv.visitInsn(Opcodes.DUP2_X2); + } + + /** + * Generates a SWAP instruction. + */ + public void swap() { + mv.visitInsn(Opcodes.SWAP); + } + + /** + * Generates the instructions to swap the top two stack values. + * + * @param prev type of the top - 1 stack value. + * @param type type of the top stack value. + */ + public void swap(final Type prev, final Type type) { + if (type.getSize() == 1) { + if (prev.getSize() == 1) { + swap(); // same as dupX1(), pop(); + } else { + dupX2(); + pop(); + } + } else { + if (prev.getSize() == 1) { + dup2X1(); + pop2(); + } else { + dup2X2(); + pop2(); + } + } + } + + // ------------------------------------------------------------------------ + // Instructions to do mathematical and logical operations + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to do the specified mathematical or logical + * operation. + * + * @param op a mathematical or logical operation. Must be one of ADD, SUB, + * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR. + * @param type the type of the operand(s) for this operation. + */ + public void math(final int op, final Type type) { + mv.visitInsn(type.getOpcode(op)); + } + + /** + * Generates the instructions to compute the bitwise negation of the top + * stack value. + */ + public void not() { + mv.visitInsn(Opcodes.ICONST_1); + mv.visitInsn(Opcodes.IXOR); + } + + /** + * Generates the instruction to increment the given local variable. + * + * @param local the local variable to be incremented. + * @param amount the amount by which the local variable must be incremented. + */ + public void iinc(final int local, final int amount) { + mv.visitIincInsn(local, amount); + } + + /** + * Generates the instructions to cast a numerical value from one type to + * another. + * + * @param from the type of the top stack value + * @param to the type into which this value must be cast. + */ + public void cast(final Type from, final Type to) { + if (from != to) { + if (from == Type.DOUBLE_TYPE) { + if (to == Type.FLOAT_TYPE) { + mv.visitInsn(Opcodes.D2F); + } else if (to == Type.LONG_TYPE) { + mv.visitInsn(Opcodes.D2L); + } else { + mv.visitInsn(Opcodes.D2I); + cast(Type.INT_TYPE, to); + } + } else if (from == Type.FLOAT_TYPE) { + if (to == Type.DOUBLE_TYPE) { + mv.visitInsn(Opcodes.F2D); + } else if (to == Type.LONG_TYPE) { + mv.visitInsn(Opcodes.F2L); + } else { + mv.visitInsn(Opcodes.F2I); + cast(Type.INT_TYPE, to); + } + } else if (from == Type.LONG_TYPE) { + if (to == Type.DOUBLE_TYPE) { + mv.visitInsn(Opcodes.L2D); + } else if (to == Type.FLOAT_TYPE) { + mv.visitInsn(Opcodes.L2F); + } else { + mv.visitInsn(Opcodes.L2I); + cast(Type.INT_TYPE, to); + } + } else { + if (to == Type.BYTE_TYPE) { + mv.visitInsn(Opcodes.I2B); + } else if (to == Type.CHAR_TYPE) { + mv.visitInsn(Opcodes.I2C); + } else if (to == Type.DOUBLE_TYPE) { + mv.visitInsn(Opcodes.I2D); + } else if (to == Type.FLOAT_TYPE) { + mv.visitInsn(Opcodes.I2F); + } else if (to == Type.LONG_TYPE) { + mv.visitInsn(Opcodes.I2L); + } else if (to == Type.SHORT_TYPE) { + mv.visitInsn(Opcodes.I2S); + } + } + } + } + + // ------------------------------------------------------------------------ + // Instructions to do boxing and unboxing operations + // ------------------------------------------------------------------------ + + /** + * Generates the instructions to box the top stack value. This value is + * replaced by its boxed equivalent on top of the stack. + * + * @param type the type of the top stack value. + */ + public void box(final Type type) { + if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { + return; + } + if (type == Type.VOID_TYPE) { + push((String) null); + } else { + Type boxed = type; + switch (type.getSort()) { + case Type.BYTE: + boxed = BYTE_TYPE; + break; + case Type.BOOLEAN: + boxed = BOOLEAN_TYPE; + break; + case Type.SHORT: + boxed = SHORT_TYPE; + break; + case Type.CHAR: + boxed = CHARACTER_TYPE; + break; + case Type.INT: + boxed = INTEGER_TYPE; + break; + case Type.FLOAT: + boxed = FLOAT_TYPE; + break; + case Type.LONG: + boxed = LONG_TYPE; + break; + case Type.DOUBLE: + boxed = DOUBLE_TYPE; + break; + } + newInstance(boxed); + if (type.getSize() == 2) { + // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o + dupX2(); + dupX2(); + pop(); + } else { + // p -> po -> opo -> oop -> o + dupX1(); + swap(); + } + invokeConstructor(boxed, new Method("<init>", + Type.VOID_TYPE, + new Type[] { type })); + } + } + + /** + * Generates the instructions to unbox the top stack value. This value is + * replaced by its unboxed equivalent on top of the stack. + * + * @param type the type of the top stack value. + */ + public void unbox(final Type type) { + Type t = NUMBER_TYPE; + Method sig = null; + switch (type.getSort()) { + case Type.VOID: + return; + case Type.CHAR: + t = CHARACTER_TYPE; + sig = CHAR_VALUE; + break; + case Type.BOOLEAN: + t = BOOLEAN_TYPE; + sig = BOOLEAN_VALUE; + break; + case Type.DOUBLE: + sig = DOUBLE_VALUE; + break; + case Type.FLOAT: + sig = FLOAT_VALUE; + break; + case Type.LONG: + sig = LONG_VALUE; + break; + case Type.INT: + case Type.SHORT: + case Type.BYTE: + sig = INT_VALUE; + } + if (sig == null) { + checkCast(type); + } else { + checkCast(t); + invokeVirtual(t, sig); + } + } + + // ------------------------------------------------------------------------ + // Instructions to jump to other instructions + // ------------------------------------------------------------------------ + + /** + * Creates a new {@link Label}. + * + * @return a new {@link Label}. + */ + public Label newLabel() { + return new Label(); + } + + /** + * Marks the current code position with the given label. + * + * @param label a label. + */ + public void mark(final Label label) { + mv.visitLabel(label); + } + + /** + * Marks the current code position with a new label. + * + * @return the label that was created to mark the current code position. + */ + public Label mark() { + Label label = new Label(); + mv.visitLabel(label); + return label; + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top two stack values. + * + * @param type the type of the top two stack values. + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label where to jump if the comparison result is <tt>true</tt>. + */ + public void ifCmp(final Type type, final int mode, final Label label) { + int intOp = -1; + int jumpMode = mode; + switch (mode) { + case GE: + jumpMode = LT; + break; + case LE: + jumpMode = GT; + break; + } + switch (type.getSort()) { + case Type.LONG: + mv.visitInsn(Opcodes.LCMP); + break; + case Type.DOUBLE: + mv.visitInsn(Opcodes.DCMPG); + break; + case Type.FLOAT: + mv.visitInsn(Opcodes.FCMPG); + break; + case Type.ARRAY: + case Type.OBJECT: + switch (mode) { + case EQ: + mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); + return; + case NE: + mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); + return; + } + throw new IllegalArgumentException("Bad comparison for type " + + type); + default: + switch (mode) { + case EQ: + intOp = Opcodes.IF_ICMPEQ; + break; + case NE: + intOp = Opcodes.IF_ICMPNE; + break; + case GE: + intOp = Opcodes.IF_ICMPGE; + break; + case LT: + intOp = Opcodes.IF_ICMPLT; + break; + case LE: + intOp = Opcodes.IF_ICMPLE; + break; + case GT: + intOp = Opcodes.IF_ICMPGT; + break; + } + mv.visitJumpInsn(intOp, label); + return; + } + mv.visitJumpInsn(jumpMode, label); + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top two integer stack values. + * + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label where to jump if the comparison result is <tt>true</tt>. + */ + public void ifICmp(final int mode, final Label label) { + ifCmp(Type.INT_TYPE, mode, label); + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top integer stack value with zero. + * + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label where to jump if the comparison result is <tt>true</tt>. + */ + public void ifZCmp(final int mode, final Label label) { + mv.visitJumpInsn(mode, label); + } + + /** + * Generates the instruction to jump to the given label if the top stack + * value is null. + * + * @param label where to jump if the condition is <tt>true</tt>. + */ + public void ifNull(final Label label) { + mv.visitJumpInsn(Opcodes.IFNULL, label); + } + + /** + * Generates the instruction to jump to the given label if the top stack + * value is not null. + * + * @param label where to jump if the condition is <tt>true</tt>. + */ + public void ifNonNull(final Label label) { + mv.visitJumpInsn(Opcodes.IFNONNULL, label); + } + + /** + * Generates the instruction to jump to the given label. + * + * @param label where to jump if the condition is <tt>true</tt>. + */ + public void goTo(final Label label) { + mv.visitJumpInsn(Opcodes.GOTO, label); + } + + /** + * Generates a RET instruction. + * + * @param local a local variable identifier, as returned by {@link #newLocal + * newLocal}. + */ + public void ret(final int local) { + mv.visitVarInsn(Opcodes.RET, local); + } + + /** + * Generates the instructions for a switch statement. + * + * @param keys the switch case keys. + * @param generator a generator to generate the code for the switch cases. + */ + public void tableSwitch( + final int[] keys, + final TableSwitchGenerator generator) + { + float density; + if (keys.length == 0) { + density = 0; + } else { + density = (float) keys.length + / (keys[keys.length - 1] - keys[0] + 1); + } + tableSwitch(keys, generator, density >= 0.5f); + } + + /** + * Generates the instructions for a switch statement. + * + * @param keys the switch case keys. + * @param generator a generator to generate the code for the switch cases. + * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or + * <tt>false</tt> to use a LOOKUPSWITCH instruction. + */ + public void tableSwitch( + final int[] keys, + final TableSwitchGenerator generator, + final boolean useTable) + { + for (int i = 1; i < keys.length; ++i) { + if (keys[i] < keys[i - 1]) { + throw new IllegalArgumentException("keys must be sorted ascending"); + } + } + Label def = newLabel(); + Label end = newLabel(); + if (keys.length > 0) { + int len = keys.length; + int min = keys[0]; + int max = keys[len - 1]; + int range = max - min + 1; + if (useTable) { + Label[] labels = new Label[range]; + Arrays.fill(labels, def); + for (int i = 0; i < len; ++i) { + labels[keys[i] - min] = newLabel(); + } + mv.visitTableSwitchInsn(min, max, def, labels); + for (int i = 0; i < range; ++i) { + Label label = labels[i]; + if (label != def) { + mark(label); + generator.generateCase(i + min, end); + } + } + } else { + Label[] labels = new Label[len]; + for (int i = 0; i < len; ++i) { + labels[i] = newLabel(); + } + mv.visitLookupSwitchInsn(def, keys, labels); + for (int i = 0; i < len; ++i) { + mark(labels[i]); + generator.generateCase(keys[i], end); + } + } + } + mark(def); + generator.generateDefault(); + mark(end); + } + + /** + * Generates the instruction to return the top stack value to the caller. + */ + public void returnValue() { + mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); + } + + // ------------------------------------------------------------------------ + // Instructions to load and store fields + // ------------------------------------------------------------------------ + + /** + * Generates a get field or set field instruction. + * + * @param opcode the instruction's opcode. + * @param ownerType the class in which the field is defined. + * @param name the name of the field. + * @param fieldType the type of the field. + */ + private void fieldInsn( + final int opcode, + final Type ownerType, + final String name, + final Type fieldType) + { + mv.visitFieldInsn(opcode, + ownerType.getInternalName(), + name, + fieldType.getDescriptor()); + } + + /** + * Generates the instruction to push the value of a static field on the + * stack. + * + * @param owner the class in which the field is defined. + * @param name the name of the field. + * @param type the type of the field. + */ + public void getStatic(final Type owner, final String name, final Type type) + { + fieldInsn(Opcodes.GETSTATIC, owner, name, type); + } + + /** + * Generates the instruction to store the top stack value in a static field. + * + * @param owner the class in which the field is defined. + * @param name the name of the field. + * @param type the type of the field. + */ + public void putStatic(final Type owner, final String name, final Type type) + { + fieldInsn(Opcodes.PUTSTATIC, owner, name, type); + } + + /** + * Generates the instruction to push the value of a non static field on the + * stack. + * + * @param owner the class in which the field is defined. + * @param name the name of the field. + * @param type the type of the field. + */ + public void getField(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.GETFIELD, owner, name, type); + } + + /** + * Generates the instruction to store the top stack value in a non static + * field. + * + * @param owner the class in which the field is defined. + * @param name the name of the field. + * @param type the type of the field. + */ + public void putField(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.PUTFIELD, owner, name, type); + } + + // ------------------------------------------------------------------------ + // Instructions to invoke methods + // ------------------------------------------------------------------------ + + /** + * Generates an invoke method instruction. + * + * @param opcode the instruction's opcode. + * @param type the class in which the method is defined. + * @param method the method to be invoked. + */ + private void invokeInsn( + final int opcode, + final Type type, + final Method method) + { + String owner = type.getSort() == Type.ARRAY + ? type.getDescriptor() + : type.getInternalName(); + mv.visitMethodInsn(opcode, + owner, + method.getName(), + method.getDescriptor()); + } + + /** + * Generates the instruction to invoke a normal method. + * + * @param owner the class in which the method is defined. + * @param method the method to be invoked. + */ + public void invokeVirtual(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); + } + + /** + * Generates the instruction to invoke a constructor. + * + * @param type the class in which the constructor is defined. + * @param method the constructor to be invoked. + */ + public void invokeConstructor(final Type type, final Method method) { + invokeInsn(Opcodes.INVOKESPECIAL, type, method); + } + + /** + * Generates the instruction to invoke a static method. + * + * @param owner the class in which the method is defined. + * @param method the method to be invoked. + */ + public void invokeStatic(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKESTATIC, owner, method); + } + + /** + * Generates the instruction to invoke an interface method. + * + * @param owner the class in which the method is defined. + * @param method the method to be invoked. + */ + public void invokeInterface(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); + } + + // ------------------------------------------------------------------------ + // Instructions to create objects and arrays + // ------------------------------------------------------------------------ + + /** + * Generates a type dependent instruction. + * + * @param opcode the instruction's opcode. + * @param type the instruction's operand. + */ + private void typeInsn(final int opcode, final Type type) { + String desc; + if (type.getSort() == Type.ARRAY) { + desc = type.getDescriptor(); + } else { + desc = type.getInternalName(); + } + mv.visitTypeInsn(opcode, desc); + } + + /** + * Generates the instruction to create a new object. + * + * @param type the class of the object to be created. + */ + public void newInstance(final Type type) { + typeInsn(Opcodes.NEW, type); + } + + /** + * Generates the instruction to create a new array. + * + * @param type the type of the array elements. + */ + public void newArray(final Type type) { + int typ; + switch (type.getSort()) { + case Type.BOOLEAN: + typ = Opcodes.T_BOOLEAN; + break; + case Type.CHAR: + typ = Opcodes.T_CHAR; + break; + case Type.BYTE: + typ = Opcodes.T_BYTE; + break; + case Type.SHORT: + typ = Opcodes.T_SHORT; + break; + case Type.INT: + typ = Opcodes.T_INT; + break; + case Type.FLOAT: + typ = Opcodes.T_FLOAT; + break; + case Type.LONG: + typ = Opcodes.T_LONG; + break; + case Type.DOUBLE: + typ = Opcodes.T_DOUBLE; + break; + default: + typeInsn(Opcodes.ANEWARRAY, type); + return; + } + mv.visitIntInsn(Opcodes.NEWARRAY, typ); + } + + // ------------------------------------------------------------------------ + // Miscelaneous instructions + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to compute the length of an array. + */ + public void arrayLength() { + mv.visitInsn(Opcodes.ARRAYLENGTH); + } + + /** + * Generates the instruction to throw an exception. + */ + public void throwException() { + mv.visitInsn(Opcodes.ATHROW); + } + + /** + * Generates the instructions to create and throw an exception. The + * exception class must have a constructor with a single String argument. + * + * @param type the class of the exception to be thrown. + * @param msg the detailed message of the exception. + */ + public void throwException(final Type type, final String msg) { + newInstance(type); + dup(); + push(msg); + invokeConstructor(type, Method.getMethod("void <init> (String)")); + throwException(); + } + + /** + * Generates the instruction to check that the top stack value is of the + * given type. + * + * @param type a class or interface type. + */ + public void checkCast(final Type type) { + if (!type.equals(OBJECT_TYPE)) { + typeInsn(Opcodes.CHECKCAST, type); + } + } + + /** + * Generates the instruction to test if the top stack value is of the given + * type. + * + * @param type a class or interface type. + */ + public void instanceOf(final Type type) { + typeInsn(Opcodes.INSTANCEOF, type); + } + + /** + * Generates the instruction to get the monitor of the top stack value. + */ + public void monitorEnter() { + mv.visitInsn(Opcodes.MONITORENTER); + } + + /** + * Generates the instruction to release the monitor of the top stack value. + */ + public void monitorExit() { + mv.visitInsn(Opcodes.MONITOREXIT); + } + + // ------------------------------------------------------------------------ + // Non instructions + // ------------------------------------------------------------------------ + + /** + * Marks the end of the visited method. + */ + public void endMethod() { + if ((access & Opcodes.ACC_ABSTRACT) == 0) { + mv.visitMaxs(0, 0); + } + } + + /** + * Marks the start of an exception handler. + * + * @param start beginning of the exception handler's scope (inclusive). + * @param end end of the exception handler's scope (exclusive). + * @param exception internal name of the type of exceptions handled by the + * handler. + */ + public void catchException( + final Label start, + final Label end, + final Type exception) + { + mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName()); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/LocalVariablesSorter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/LocalVariablesSorter.java new file mode 100644 index 000000000..bfc873247 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -0,0 +1,136 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * A {@link MethodAdapter} that renumbers local variables in their order of + * appearance. This adapter allows one to easily add new local variables to a + * method. + * + * @author Chris Nokleberg + * @author Eric Bruneton + */ +public class LocalVariablesSorter extends MethodAdapter { + + /** + * Mapping from old to new local variable indexes. A local variable at index + * i of size 1 is remapped to 'mapping[2*i]', while a local variable at + * index i of size 2 is remapped to 'mapping[2*i+1]'. + */ + private int[] mapping = new int[40]; + + protected final int firstLocal; + + private int nextLocal; + + public LocalVariablesSorter( + final int access, + final String desc, + final MethodVisitor mv) + { + super(mv); + Type[] args = Type.getArgumentTypes(desc); + nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1; + for (int i = 0; i < args.length; i++) { + nextLocal += args[i].getSize(); + } + firstLocal = nextLocal; + } + + public void visitVarInsn(final int opcode, final int var) { + int size; + switch (opcode) { + case Opcodes.LLOAD: + case Opcodes.LSTORE: + case Opcodes.DLOAD: + case Opcodes.DSTORE: + size = 2; + break; + default: + size = 1; + } + mv.visitVarInsn(opcode, remap(var, size)); + } + + public void visitIincInsn(final int var, final int increment) { + mv.visitIincInsn(remap(var, 1), increment); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + mv.visitMaxs(maxStack, nextLocal); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1; + mv.visitLocalVariable(name, desc, signature, start, end, remap(index, size)); + } + + // ------------- + + protected int newLocal(final int size) { + int var = nextLocal; + nextLocal += size; + return var; + } + + private int remap(final int var, final int size) { + if (var < firstLocal) { + return var; + } + int key = 2 * var + size - 1; + int length = mapping.length; + if (key >= length) { + int[] newMapping = new int[Math.max(2 * length, key + 1)]; + System.arraycopy(mapping, 0, newMapping, 0, length); + mapping = newMapping; + } + int value = mapping[key]; + if (value == 0) { + value = nextLocal + 1; + mapping[key] = value; + nextLocal += size; + } + return value - 1; + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/Method.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/Method.java new file mode 100644 index 000000000..c5ce31407 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/Method.java @@ -0,0 +1,220 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import java.util.HashMap; +import java.util.Map; + +import org.objectweb.asm.Type; + +/** + * A named method descriptor. + * + * @author Juozas Baliuka + * @author Chris Nokleberg + * @author Eric Bruneton + */ +public class Method { + + /** + * The method name. + */ + private final String name; + + /** + * The method descriptor. + */ + private final String desc; + + /** + * Maps primitive Java type names to their descriptors. + */ + private final static Map DESCRIPTORS; + + static { + DESCRIPTORS = new HashMap(); + DESCRIPTORS.put("void", "V"); + DESCRIPTORS.put("byte", "B"); + DESCRIPTORS.put("char", "C"); + DESCRIPTORS.put("double", "D"); + DESCRIPTORS.put("float", "F"); + DESCRIPTORS.put("int", "I"); + DESCRIPTORS.put("long", "J"); + DESCRIPTORS.put("short", "S"); + DESCRIPTORS.put("boolean", "Z"); + } + + /** + * Creates a new {@link Method}. + * + * @param name the method's name. + * @param desc the method's descriptor. + */ + public Method(final String name, final String desc) { + this.name = name; + this.desc = desc; + } + + /** + * Creates a new {@link Method}. + * + * @param name the method's name. + * @param returnType the method's return type. + * @param argumentTypes the method's argument types. + */ + public Method( + final String name, + final Type returnType, + final Type[] argumentTypes) + { + this(name, Type.getMethodDescriptor(returnType, argumentTypes)); + } + + /** + * Returns a {@link Method} corresponding to the given Java method + * declaration. + * + * @param method a Java method declaration, without argument names, of the + * form "returnType name (argumentType1, ... argumentTypeN)", where + * the types are in plain Java (e.g. "int", "float", + * "java.util.List", ...). + * @return a {@link Method} corresponding to the given Java method + * declaration. + * @throws IllegalArgumentException if <code>method</code> could not get + * parsed. + */ + public static Method getMethod(final String method) + throws IllegalArgumentException + { + int space = method.indexOf(' '); + int start = method.indexOf('(', space) + 1; + int end = method.indexOf(')', start); + if (space == -1 || start == -1 || end == -1) { + throw new IllegalArgumentException(); + } + // TODO: Check validity of returnType, methodName and arguments. + String returnType = method.substring(0, space); + String methodName = method.substring(space + 1, start - 1).trim(); + StringBuffer sb = new StringBuffer(); + sb.append('('); + int p; + do { + p = method.indexOf(',', start); + if (p == -1) { + sb.append(map(method.substring(start, end).trim())); + } else { + sb.append(map(method.substring(start, p).trim())); + start = p + 1; + } + } while (p != -1); + sb.append(')'); + sb.append(map(returnType)); + return new Method(methodName, sb.toString()); + } + + private static String map(final String type) { + if (type.equals("")) { + return type; + } + + StringBuffer sb = new StringBuffer(); + int index = 0; + while ((index = type.indexOf("[]", index) + 1) > 0) { + sb.append('['); + } + + String t = type.substring(0, type.length() - sb.length() * 2); + String desc = (String) DESCRIPTORS.get(t); + if (desc != null) { + sb.append(desc); + } else { + sb.append('L'); + if (t.indexOf('.') < 0) { + sb.append("java/lang/" + t); + } else { + sb.append(t.replace('.', '/')); + } + sb.append(';'); + } + return sb.toString(); + } + + /** + * Returns the name of the method described by this object. + * + * @return the name of the method described by this object. + */ + public String getName() { + return name; + } + + /** + * Returns the descriptor of the method described by this object. + * + * @return the descriptor of the method described by this object. + */ + public String getDescriptor() { + return desc; + } + + /** + * Returns the return type of the method described by this object. + * + * @return the return type of the method described by this object. + */ + public Type getReturnType() { + return Type.getReturnType(desc); + } + + /** + * Returns the argument types of the method described by this object. + * + * @return the argument types of the method described by this object. + */ + public Type[] getArgumentTypes() { + return Type.getArgumentTypes(desc); + } + + public String toString() { + return name + desc; + } + + public boolean equals(final Object o) { + if (!(o instanceof Method)) { + return false; + } + Method other = (Method) o; + return name.equals(other.name) && desc.equals(other.desc); + } + + public int hashCode() { + return name.hashCode() ^ desc.hashCode(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/SerialVersionUIDAdder.java new file mode 100644 index 000000000..3932a01ad --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -0,0 +1,490 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * A {@link ClassAdapter} that adds a serial version unique identifier to a + * class if missing. Here is typical usage of this class: + * + * <pre> + * ClassWriter cw = new ClassWriter(...); + * ClassVisitor sv = new SerialVersionUIDAdder(cw); + * ClassVisitor ca = new MyClassAdapter(sv); + * new ClassReader(orginalClass).accept(ca, false); + * </pre> + * + * The SVUID algorithm can be found <a href= + * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html" + * >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>: + * + * <pre> + * The serialVersionUID is computed using the signature of a stream of bytes + * that reflect the class definition. The National Institute of Standards and + * Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a + * signature for the stream. The first two 32-bit quantities are used to form a + * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data + * types to a sequence of bytes. The values input to the stream are defined by + * the Java Virtual Machine (VM) specification for classes. + * + * The sequence of items in the stream is as follows: + * + * 1. The class name written using UTF encoding. + * 2. The class modifiers written as a 32-bit integer. + * 3. The name of each interface sorted by name written using UTF encoding. + * 4. For each field of the class sorted by field name (except private static + * and private transient fields): + * 1. The name of the field in UTF encoding. + * 2. The modifiers of the field written as a 32-bit integer. + * 3. The descriptor of the field in UTF encoding + * 5. If a class initializer exists, write out the following: + * 1. The name of the method, <clinit>, in UTF encoding. + * 2. The modifier of the method, java.lang.reflect.Modifier.STATIC, + * written as a 32-bit integer. + * 3. The descriptor of the method, ()V, in UTF encoding. + * 6. For each non-private constructor sorted by method name and signature: + * 1. The name of the method, <init>, in UTF encoding. + * 2. The modifiers of the method written as a 32-bit integer. + * 3. The descriptor of the method in UTF encoding. + * 7. For each non-private method sorted by method name and signature: + * 1. The name of the method in UTF encoding. + * 2. The modifiers of the method written as a 32-bit integer. + * 3. The descriptor of the method in UTF encoding. + * 8. The SHA-1 algorithm is executed on the stream of bytes produced by + * DataOutputStream and produces five 32-bit values sha[0..4]. + * + * 9. The hash value is assembled from the first and second 32-bit values of + * the SHA-1 message digest. If the result of the message digest, the five + * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named + * sha, the hash value would be computed as follows: + * + * long hash = ((sha[0] >>> 24) & 0xFF) | + * ((sha[0] >>> 16) & 0xFF) << 8 | + * ((sha[0] >>> 8) & 0xFF) << 16 | + * ((sha[0] >>> 0) & 0xFF) << 24 | + * ((sha[1] >>> 24) & 0xFF) << 32 | + * ((sha[1] >>> 16) & 0xFF) << 40 | + * ((sha[1] >>> 8) & 0xFF) << 48 | + * ((sha[1] >>> 0) & 0xFF) << 56; + * </pre> + * + * @author Rajendra Inamdar, Vishal Vishnoi + */ +public class SerialVersionUIDAdder extends ClassAdapter { + + /** + * Flag that indicates if we need to compute SVUID. + */ + protected boolean computeSVUID; + + /** + * Set to true if the class already has SVUID. + */ + protected boolean hasSVUID; + + /** + * Classes access flags. + */ + protected int access; + + /** + * Internal name of the class + */ + protected String name; + + /** + * Interfaces implemented by the class. + */ + protected String[] interfaces; + + /** + * Collection of fields. (except private static and private transient + * fields) + */ + protected Collection svuidFields; + + /** + * Set to true if the class has static initializer. + */ + protected boolean hasStaticInitializer; + + /** + * Collection of non-private constructors. + */ + protected Collection svuidConstructors; + + /** + * Collection of non-private methods. + */ + protected Collection svuidMethods; + + /** + * Creates a new {@link SerialVersionUIDAdder}. + * + * @param cv a {@link ClassVisitor} to which this visitor will delegate + * calls. + */ + public SerialVersionUIDAdder(final ClassVisitor cv) { + super(cv); + svuidFields = new ArrayList(); + svuidConstructors = new ArrayList(); + svuidMethods = new ArrayList(); + } + + // ------------------------------------------------------------------------ + // Overriden methods + // ------------------------------------------------------------------------ + + /* + * Visit class header and get class name, access , and intefraces + * informatoin (step 1,2, and 3) for SVUID computation. + */ + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; + + if (computeSVUID) { + this.name = name; + this.access = access; + this.interfaces = interfaces; + } + + super.visit(version, access, name, signature, superName, interfaces); + } + + /* + * Visit the methods and get constructor and method information (step 5 and + * 7). Also determince if there is a class initializer (step 6). + */ + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + if (computeSVUID) { + if (name.equals("<clinit>")) { + hasStaticInitializer = true; + } + /* + * Remembers non private constructors and methods for SVUID + * computation For constructor and method modifiers, only the + * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, + * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags + * are used. + */ + int mods = access + & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE + | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC + | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED + | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT); + + // all non private methods + if ((access & Opcodes.ACC_PRIVATE) == 0) { + if (name.equals("<init>")) { + svuidConstructors.add(new Item(name, mods, desc)); + } else if (!name.equals("<clinit>")) { + svuidMethods.add(new Item(name, mods, desc)); + } + } + } + + return cv.visitMethod(access, name, desc, signature, exceptions); + } + + /* + * Gets class field information for step 4 of the alogrithm. Also determines + * if the class already has a SVUID. + */ + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + if (computeSVUID) { + if (name.equals("serialVersionUID")) { + // since the class already has SVUID, we won't be computing it. + computeSVUID = false; + hasSVUID = true; + } + /* + * Remember field for SVUID computation For field modifiers, only + * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, + * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when + * computing serialVersionUID values. + */ + int mods = access + & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE + | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC + | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT); + + if (((access & Opcodes.ACC_PRIVATE) == 0) + || ((access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0)) + { + svuidFields.add(new Item(name, mods, desc)); + } + } + + return super.visitField(access, name, desc, signature, value); + } + + /* + * Add the SVUID if class doesn't have one + */ + public void visitEnd() { + // compute SVUID and add it to the class + if (computeSVUID && !hasSVUID) { + try { + cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, + "serialVersionUID", + "J", + null, + new Long(computeSVUID())); + } catch (Throwable e) { + throw new RuntimeException("Error while computing SVUID for " + + name, e); + } + } + + super.visitEnd(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the value of SVUID if the class doesn't have one already. Please + * note that 0 is returned if the class already has SVUID, thus use + * <code>isHasSVUID</code> to determine if the class already had an SVUID. + * + * @return Returns the serial version UID + * @throws IOException + */ + protected long computeSVUID() throws IOException { + if (hasSVUID) { + return 0; + } + + ByteArrayOutputStream bos = null; + DataOutputStream dos = null; + long svuid = 0; + + try { + bos = new ByteArrayOutputStream(); + dos = new DataOutputStream(bos); + + /* + * 1. The class name written using UTF encoding. + */ + dos.writeUTF(name.replace('/', '.')); + + /* + * 2. The class modifiers written as a 32-bit integer. + */ + dos.writeInt(access + & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL + | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); + + /* + * 3. The name of each interface sorted by name written using UTF + * encoding. + */ + Arrays.sort(interfaces); + for (int i = 0; i < interfaces.length; i++) { + dos.writeUTF(interfaces[i].replace('/', '.')); + } + + /* + * 4. For each field of the class sorted by field name (except + * private static and private transient fields): + * + * 1. The name of the field in UTF encoding. 2. The modifiers of the + * field written as a 32-bit integer. 3. The descriptor of the field + * in UTF encoding + * + * Note that field signatutes are not dot separated. Method and + * constructor signatures are dot separated. Go figure... + */ + writeItems(svuidFields, dos, false); + + /* + * 5. If a class initializer exists, write out the following: 1. The + * name of the method, <clinit>, in UTF encoding. 2. The modifier of + * the method, java.lang.reflect.Modifier.STATIC, written as a + * 32-bit integer. 3. The descriptor of the method, ()V, in UTF + * encoding. + */ + if (hasStaticInitializer) { + dos.writeUTF("<clinit>"); + dos.writeInt(Opcodes.ACC_STATIC); + dos.writeUTF("()V"); + } // if.. + + /* + * 6. For each non-private constructor sorted by method name and + * signature: 1. The name of the method, <init>, in UTF encoding. 2. + * The modifiers of the method written as a 32-bit integer. 3. The + * descriptor of the method in UTF encoding. + */ + writeItems(svuidConstructors, dos, true); + + /* + * 7. For each non-private method sorted by method name and + * signature: 1. The name of the method in UTF encoding. 2. The + * modifiers of the method written as a 32-bit integer. 3. The + * descriptor of the method in UTF encoding. + */ + writeItems(svuidMethods, dos, true); + + dos.flush(); + + /* + * 8. The SHA-1 algorithm is executed on the stream of bytes + * produced by DataOutputStream and produces five 32-bit values + * sha[0..4]. + */ + byte[] hashBytes = computeSHAdigest(bos.toByteArray()); + + /* + * 9. The hash value is assembled from the first and second 32-bit + * values of the SHA-1 message digest. If the result of the message + * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of + * five int values named sha, the hash value would be computed as + * follows: + * + * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) << + * 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) << + * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) << + * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) << + * 56; + */ + for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { + svuid = (svuid << 8) | (hashBytes[i] & 0xFF); + } + } finally { + // close the stream (if open) + if (dos != null) { + dos.close(); + } + } + + return svuid; + } + + /** + * Returns the SHA-1 message digest of the given value. + * + * @param value the value whose SHA message digest must be computed. + * @return the SHA-1 message digest of the given value. + */ + protected byte[] computeSHAdigest(byte[] value) { + try { + return MessageDigest.getInstance("SHA").digest(value); + } catch (Exception e) { + throw new UnsupportedOperationException(e); + } + } + + /** + * Sorts the items in the collection and writes it to the data output stream + * + * @param itemCollection collection of items + * @param dos a <code>DataOutputStream</code> value + * @param dotted a <code>boolean</code> value + * @exception IOException if an error occurs + */ + private void writeItems( + final Collection itemCollection, + final DataOutputStream dos, + final boolean dotted) throws IOException + { + int size = itemCollection.size(); + Item items[] = (Item[]) itemCollection.toArray(new Item[size]); + Arrays.sort(items); + for (int i = 0; i < size; i++) { + dos.writeUTF(items[i].name); + dos.writeInt(items[i].access); + dos.writeUTF(dotted + ? items[i].desc.replace('/', '.') + : items[i].desc); + } + } + + // ------------------------------------------------------------------------ + // Inner classes + // ------------------------------------------------------------------------ + + static class Item implements Comparable { + + String name; + + int access; + + String desc; + + Item(final String name, final int access, final String desc) { + this.name = name; + this.access = access; + this.desc = desc; + } + + public int compareTo(final Object o) { + Item other = (Item) o; + int retVal = name.compareTo(other.name); + if (retVal == 0) { + retVal = desc.compareTo(other.desc); + } + return retVal; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/StaticInitMerger.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/StaticInitMerger.java new file mode 100644 index 000000000..2af409e87 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/StaticInitMerger.java @@ -0,0 +1,99 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * A {@link ClassAdapter} that merges clinit methods into a single one. + * + * @author Eric Bruneton + */ +public class StaticInitMerger extends ClassAdapter { + + private String name; + + private MethodVisitor clinit; + + private String prefix; + + private int counter; + + public StaticInitMerger(final String prefix, final ClassVisitor cv) { + super(cv); + this.prefix = prefix; + } + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + cv.visit(version, access, name, signature, superName, interfaces); + this.name = name; + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + MethodVisitor mv; + if (name.equals("<clinit>")) { + int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC; + String n = prefix + counter++; + mv = cv.visitMethod(a, n, desc, signature, exceptions); + + if (clinit == null) { + clinit = cv.visitMethod(a, name, desc, null, null); + } + clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc); + } else { + mv = cv.visitMethod(access, name, desc, signature, exceptions); + } + return mv; + } + + public void visitEnd() { + if (clinit != null) { + clinit.visitInsn(Opcodes.RETURN); + clinit.visitMaxs(0, 0); + } + cv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/TableSwitchGenerator.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/TableSwitchGenerator.java new file mode 100644 index 000000000..c90a9cabf --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/commons/TableSwitchGenerator.java @@ -0,0 +1,55 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.commons; + +import org.objectweb.asm.Label; + +/** + * A code generator for switch statements. + * + * @author Juozas Baliuka + * @author Chris Nokleberg + * @author Eric Bruneton + */ +public interface TableSwitchGenerator { + + /** + * Generates the code for a switch case. + * + * @param key the switch case key. + * @param end a label that corresponds to the end of the switch statement. + */ + void generateCase(int key, Label end); + + /** + * Generates the code for the default switch case. + */ + void generateDefault(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/AnnotationConstantsCollector.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/AnnotationConstantsCollector.java new file mode 100644 index 000000000..5bceca157 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/AnnotationConstantsCollector.java @@ -0,0 +1,150 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +/** + * An {@link AnnotationVisitor} that collects the {@link Constant}s of the + * annotations it visits. + * + * @author Eric Bruneton + */ +public class AnnotationConstantsCollector implements AnnotationVisitor { + + private AnnotationVisitor av; + + private ConstantPool cp; + + public AnnotationConstantsCollector( + final AnnotationVisitor av, + final ConstantPool cp) + { + this.av = av; + this.cp = cp; + } + + public void visit(final String name, final Object value) { + if (name != null) { + cp.newUTF8(name); + } + if (value instanceof Byte) { + cp.newInteger(((Byte) value).byteValue()); + } else if (value instanceof Boolean) { + cp.newInteger(((Boolean) value).booleanValue() ? 1 : 0); + } else if (value instanceof Character) { + cp.newInteger(((Character) value).charValue()); + } else if (value instanceof Short) { + cp.newInteger(((Short) value).shortValue()); + } else if (value instanceof Type) { + cp.newUTF8(((Type) value).getDescriptor()); + } else if (value instanceof byte[]) { + byte[] v = (byte[]) value; + for (int i = 0; i < v.length; i++) { + cp.newInteger(v[i]); + } + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + for (int i = 0; i < v.length; i++) { + cp.newInteger(v[i] ? 1 : 0); + } + } else if (value instanceof short[]) { + short[] v = (short[]) value; + for (int i = 0; i < v.length; i++) { + cp.newInteger(v[i]); + } + } else if (value instanceof char[]) { + char[] v = (char[]) value; + for (int i = 0; i < v.length; i++) { + cp.newInteger(v[i]); + } + } else if (value instanceof int[]) { + int[] v = (int[]) value; + for (int i = 0; i < v.length; i++) { + cp.newInteger(v[i]); + } + } else if (value instanceof long[]) { + long[] v = (long[]) value; + for (int i = 0; i < v.length; i++) { + cp.newLong(v[i]); + } + } else if (value instanceof float[]) { + float[] v = (float[]) value; + for (int i = 0; i < v.length; i++) { + cp.newFloat(v[i]); + } + } else if (value instanceof double[]) { + double[] v = (double[]) value; + for (int i = 0; i < v.length; i++) { + cp.newDouble(v[i]); + } + } else { + cp.newConst(value); + } + av.visit(name, value); + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + if (name != null) { + cp.newUTF8(name); + } + cp.newUTF8(desc); + cp.newUTF8(value); + av.visitEnum(name, desc, value); + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + if (name != null) { + cp.newUTF8(name); + } + cp.newUTF8(desc); + return new AnnotationConstantsCollector(av.visitAnnotation(name, desc), + cp); + } + + public AnnotationVisitor visitArray(final String name) { + if (name != null) { + cp.newUTF8(name); + } + return new AnnotationConstantsCollector(av.visitArray(name), cp); + } + + public void visitEnd() { + av.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassConstantsCollector.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassConstantsCollector.java new file mode 100644 index 000000000..4a6efe5d0 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassConstantsCollector.java @@ -0,0 +1,212 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * A {@link ClassVisitor} that collects the {@link Constant}s of the classes it + * visits. + * + * @author Eric Bruneton + */ +public class ClassConstantsCollector extends ClassAdapter { + + private ConstantPool cp; + + public ClassConstantsCollector(final ClassVisitor cv, final ConstantPool cp) + { + super(cv); + this.cp = cp; + } + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cp.newUTF8("Deprecated"); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + cp.newUTF8("Synthetic"); + } + cp.newClass(name); + if (signature != null) { + cp.newUTF8("Signature"); + cp.newUTF8(signature); + } + if (superName != null) { + cp.newClass(superName); + } + if (interfaces != null) { + for (int i = 0; i < interfaces.length; ++i) { + cp.newClass(interfaces[i]); + } + } + cv.visit(version, access, name, signature, superName, interfaces); + } + + public void visitSource(final String source, final String debug) { + if (source != null) { + cp.newUTF8("SourceFile"); + cp.newUTF8(source); + } + if (debug != null) { + cp.newUTF8("SourceDebugExtension"); + } + cv.visitSource(source, debug); + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + cp.newUTF8("EnclosingMethod"); + cp.newClass(owner); + if (name != null && desc != null) { + cp.newNameType(name, desc); + } + cv.visitOuterClass(owner, name, desc); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + cp.newUTF8(desc); + if (visible) { + cp.newUTF8("RuntimeVisibleAnnotations"); + } else { + cp.newUTF8("RuntimeInvisibleAnnotations"); + } + return new AnnotationConstantsCollector(cv.visitAnnotation(desc, + visible), cp); + } + + public void visitAttribute(final Attribute attr) { + // can do nothing + cv.visitAttribute(attr); + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + cp.newUTF8("InnerClasses"); + if (name != null) { + cp.newClass(name); + } + if (outerName != null) { + cp.newClass(outerName); + } + if (innerName != null) { + cp.newClass(innerName); + } + cv.visitInnerClass(name, outerName, innerName, access); + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + cp.newUTF8("Synthetic"); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cp.newUTF8("Deprecated"); + } + cp.newUTF8(name); + cp.newUTF8(desc); + if (signature != null) { + cp.newUTF8("Signature"); + cp.newUTF8(signature); + } + if (value != null) { + cp.newConst(value); + } + return new FieldConstantsCollector(cv.visitField(access, + name, + desc, + signature, + value), cp); + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + cp.newUTF8("Synthetic"); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cp.newUTF8("Deprecated"); + } + cp.newUTF8(name); + cp.newUTF8(desc); + if (signature != null) { + cp.newUTF8("Signature"); + cp.newUTF8(signature); + } + if (exceptions != null) { + cp.newUTF8("Exceptions"); + for (int i = 0; i < exceptions.length; ++i) { + cp.newClass(exceptions[i]); + } + } + return new MethodConstantsCollector(cv.visitMethod(access, + name, + desc, + signature, + exceptions), cp); + } + + public void visitEnd() { + cv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassOptimizer.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassOptimizer.java new file mode 100644 index 000000000..b9a1a421c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ClassOptimizer.java @@ -0,0 +1,182 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * A {@link ClassAdapter} that renames fields and methods, and removes debug + * info. + * + * @author Eric Bruneton + */ +public class ClassOptimizer extends ClassAdapter { + + private NameMapping mapping; + + private String className; + + private String pkgName; + + public ClassOptimizer(final ClassVisitor cv, final NameMapping mapping) { + super(cv); + this.mapping = mapping; + } + + public String getClassName() { + return className; + } + + // ------------------------------------------------------------------------ + // Overriden methods + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + className = name; + pkgName = name.substring(0, name.lastIndexOf('/')); + cv.visit(version, + access, + mapping.map(name), + null, + mapping.map(superName), + interfaces); + } + + public void visitSource(final String source, final String debug) { + // remove debug info + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + // remove debug info + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + throw new UnsupportedOperationException(); + } + + public void visitAttribute(final Attribute attr) { + // remove non standard attribute + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + // remove debug info + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + String s = className + "." + name; + if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) { + if ((access & Opcodes.ACC_FINAL) != 0 + && (access & Opcodes.ACC_STATIC) != 0 && desc.equals("I")) + { + return null; + } + if (pkgName.equals("org/objectweb/asm") + && mapping.map(s).equals(name)) + { + System.out.println("INFO: " + s + " could be renamed"); + } + cv.visitField(access, + mapping.map(s), + mapping.fix(desc), + null, + value); + } else { + if (!mapping.map(s).equals(name)) { + throw new RuntimeException("The public or protected field " + s + + " must not be renamed."); + } + cv.visitField(access, name, desc, null, value); + } + return null; // remove debug info + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + String s = className + "." + name + desc; + if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) { + if (pkgName.equals("org/objectweb/asm") && !name.startsWith("<") + && mapping.map(s).equals(name)) + { + System.out.println("INFO: " + s + " could be renamed"); + } + return new MethodOptimizer(cv.visitMethod(access, + mapping.map(s), + mapping.fix(desc), + null, + exceptions), mapping); + } else { + if (!mapping.map(s).equals(name)) { + throw new RuntimeException("The public or protected method " + + s + " must not be renamed."); + } + return new MethodOptimizer(cv.visitMethod(access, + name, + desc, + null, + exceptions), mapping); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Constant.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Constant.java new file mode 100644 index 000000000..c07599dea --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Constant.java @@ -0,0 +1,265 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.ClassWriter; + +/** + * A constant pool item. + * + * @author Eric Bruneton + */ +class Constant { + + /** + * Type of this constant pool item. A single class is used to represent all + * constant pool item types, in order to minimize the bytecode size of this + * package. The value of this field is I, J, F, D, S, s, C, T, G, M, or N + * (for Constant Integer, Long, Float, Double, STR, UTF8, Class, NameType, + * Fieldref, Methodref, or InterfaceMethodref constant pool items + * respectively). + */ + char type; + + /** + * Value of this item, for an integer item. + */ + int intVal; + + /** + * Value of this item, for a long item. + */ + long longVal; + + /** + * Value of this item, for a float item. + */ + float floatVal; + + /** + * Value of this item, for a double item. + */ + double doubleVal; + + /** + * First part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal1; + + /** + * Second part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal2; + + /** + * Third part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal3; + + /** + * The hash code value of this constant pool item. + */ + int hashCode; + + public Constant() { + } + + public Constant(final Constant i) { + type = i.type; + intVal = i.intVal; + longVal = i.longVal; + floatVal = i.floatVal; + doubleVal = i.doubleVal; + strVal1 = i.strVal1; + strVal2 = i.strVal2; + strVal3 = i.strVal3; + hashCode = i.hashCode; + } + + /** + * Sets this item to an integer item. + * + * @param intVal the value of this item. + */ + void set(final int intVal) { + this.type = 'I'; + this.intVal = intVal; + this.hashCode = 0x7FFFFFFF & (type + intVal); + } + + /** + * Sets this item to a long item. + * + * @param longVal the value of this item. + */ + void set(final long longVal) { + this.type = 'J'; + this.longVal = longVal; + this.hashCode = 0x7FFFFFFF & (type + (int) longVal); + } + + /** + * Sets this item to a float item. + * + * @param floatVal the value of this item. + */ + void set(final float floatVal) { + this.type = 'F'; + this.floatVal = floatVal; + this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); + } + + /** + * Sets this item to a double item. + * + * @param doubleVal the value of this item. + */ + void set(final double doubleVal) { + this.type = 'D'; + this.doubleVal = doubleVal; + this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); + } + + /** + * Sets this item to an item that do not hold a primitive value. + * + * @param type the type of this item. + * @param strVal1 first part of the value of this item. + * @param strVal2 second part of the value of this item. + * @param strVal3 third part of the value of this item. + */ + void set( + final char type, + final String strVal1, + final String strVal2, + final String strVal3) + { + this.type = type; + this.strVal1 = strVal1; + this.strVal2 = strVal2; + this.strVal3 = strVal3; + switch (type) { + case 's': + case 'S': + case 'C': + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); + return; + case 'T': + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode()); + return; + // case 'G': + // case 'M': + // case 'N': + default: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode() * strVal3.hashCode()); + } + } + + void write(final ClassWriter cw) { + switch (type) { + case 'I': + cw.newConst(new Integer(intVal)); + break; + case 'J': + cw.newConst(new Long(longVal)); + break; + case 'F': + cw.newConst(new Float(floatVal)); + break; + case 'D': + cw.newConst(new Double(doubleVal)); + break; + case 'S': + cw.newConst(strVal1); + break; + case 's': + cw.newUTF8(strVal1); + break; + case 'C': + cw.newClass(strVal1); + break; + case 'T': + cw.newNameType(strVal1, strVal2); + break; + case 'G': + cw.newField(strVal1, strVal2, strVal3); + break; + case 'M': + cw.newMethod(strVal1, strVal2, strVal3, false); + break; + case 'N': + cw.newMethod(strVal1, strVal2, strVal3, true); + break; + } + } + + public boolean equals(final Object o) { + if (!(o instanceof Constant)) { + return false; + } + Constant c = (Constant) o; + if (c.type == type) { + switch (type) { + case 'I': + return c.intVal == intVal; + case 'J': + return c.longVal == longVal; + case 'F': + return c.floatVal == floatVal; + case 'D': + return c.doubleVal == doubleVal; + case 's': + case 'S': + case 'C': + return c.strVal1.equals(strVal1); + case 'T': + return c.strVal1.equals(strVal1) + && c.strVal2.equals(strVal2); + // case 'G': + // case 'M': + // case 'N': + default: + return c.strVal1.equals(strVal1) + && c.strVal2.equals(strVal2) + && c.strVal3.equals(strVal3); + } + } + return false; + } + + public int hashCode() { + return hashCode; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ConstantPool.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ConstantPool.java new file mode 100644 index 000000000..dff17dec6 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/ConstantPool.java @@ -0,0 +1,198 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import java.util.HashMap; + +import org.objectweb.asm.Type; + +/** + * A constant pool. + * + * @author Eric Bruneton + */ +public class ConstantPool extends HashMap { + + private Constant key1 = new Constant(); + + private Constant key2 = new Constant(); + + private Constant key3 = new Constant(); + + public Constant newInteger(final int value) { + key1.set(value); + Constant result = get(key1); + if (result == null) { + result = new Constant(key1); + put(result); + } + return result; + } + + public Constant newFloat(final float value) { + key1.set(value); + Constant result = get(key1); + if (result == null) { + result = new Constant(key1); + put(result); + } + return result; + } + + public Constant newLong(final long value) { + key1.set(value); + Constant result = get(key1); + if (result == null) { + result = new Constant(key1); + put(result); + } + return result; + } + + public Constant newDouble(final double value) { + key1.set(value); + Constant result = get(key1); + if (result == null) { + result = new Constant(key1); + put(result); + } + return result; + } + + public Constant newUTF8(final String value) { + key1.set('s', value, null, null); + Constant result = get(key1); + if (result == null) { + result = new Constant(key1); + put(result); + } + return result; + } + + private Constant newString(final String value) { + key2.set('S', value, null, null); + Constant result = get(key2); + if (result == null) { + newUTF8(value); + result = new Constant(key2); + put(result); + } + return result; + } + + public Constant newClass(final String value) { + key2.set('C', value, null, null); + Constant result = get(key2); + if (result == null) { + newUTF8(value); + result = new Constant(key2); + put(result); + } + return result; + } + + public Constant newConst(final Object cst) { + if (cst instanceof Integer) { + int val = ((Integer) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Float) { + float val = ((Float) cst).floatValue(); + return newFloat(val); + } else if (cst instanceof Long) { + long val = ((Long) cst).longValue(); + return newLong(val); + } else if (cst instanceof Double) { + double val = ((Double) cst).doubleValue(); + return newDouble(val); + } else if (cst instanceof String) { + return newString((String) cst); + } else if (cst instanceof Type) { + Type t = (Type) cst; + return newClass(t.getSort() == Type.OBJECT + ? t.getInternalName() + : t.getDescriptor()); + } else { + throw new IllegalArgumentException("value " + cst); + } + } + + public Constant newField( + final String owner, + final String name, + final String desc) + { + key3.set('G', owner, name, desc); + Constant result = get(key3); + if (result == null) { + newClass(owner); + newNameType(name, desc); + result = new Constant(key3); + put(result); + } + return result; + } + + public Constant newMethod( + final String owner, + final String name, + final String desc, + final boolean itf) + { + key3.set(itf ? 'N' : 'M', owner, name, desc); + Constant result = get(key3); + if (result == null) { + newClass(owner); + newNameType(name, desc); + result = new Constant(key3); + put(result); + } + return result; + } + + public Constant newNameType(final String name, final String desc) { + key2.set('T', name, desc, null); + Constant result = get(key2); + if (result == null) { + newUTF8(name); + newUTF8(desc); + result = new Constant(key2); + put(result); + } + return result; + } + + private Constant get(final Constant key) { + return (Constant) get((Object) key); + } + + private void put(final Constant cst) { + put(cst, cst); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/FieldConstantsCollector.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/FieldConstantsCollector.java new file mode 100644 index 000000000..ac5d0d317 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/FieldConstantsCollector.java @@ -0,0 +1,76 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; + +/** + * A {@link FieldVisitor} that collects the {@link Constant}s of the fields it + * visits. + * + * @author Eric Bruneton + */ +public class FieldConstantsCollector implements FieldVisitor { + + private FieldVisitor fv; + + private ConstantPool cp; + + public FieldConstantsCollector(final FieldVisitor fv, final ConstantPool cp) + { + this.fv = fv; + this.cp = cp; + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + cp.newUTF8(desc); + if (visible) { + cp.newUTF8("RuntimeVisibleAnnotations"); + } else { + cp.newUTF8("RuntimeInvisibleAnnotations"); + } + return new AnnotationConstantsCollector(fv.visitAnnotation(desc, + visible), cp); + } + + public void visitAttribute(final Attribute attr) { + // can do nothing + fv.visitAttribute(attr); + } + + public void visitEnd() { + fv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/JarOptimizer.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/JarOptimizer.java new file mode 100644 index 000000000..994b4584e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/JarOptimizer.java @@ -0,0 +1,87 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +/** + * A Jar file optimizer. + * + * @author Eric Bruneton + */ +public class JarOptimizer { + + public static void main(final String[] args) throws IOException { + File f = new File(args[0]); + optimize(f); + } + + static void optimize(final File f) throws IOException { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; ++i) { + optimize(files[i]); + } + } else if (f.getName().endsWith(".jar")) { + File g = new File(f.getParentFile(), f.getName() + ".new"); + ZipFile zf = new ZipFile(f); + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(g)); + Enumeration e = zf.entries(); + byte[] buf = new byte[10000]; + while (e.hasMoreElements()) { + ZipEntry ze = (ZipEntry) e.nextElement(); + if (ze.isDirectory()) { + continue; + } + out.putNextEntry(ze); + InputStream is = zf.getInputStream(ze); + int n; + do { + n = is.read(buf, 0, buf.length); + if (n != -1) { + out.write(buf, 0, n); + } + } while (n != -1); + out.closeEntry(); + } + out.close(); + zf.close(); + f.delete(); + g.renameTo(f); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodConstantsCollector.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodConstantsCollector.java new file mode 100644 index 000000000..33d82e952 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodConstantsCollector.java @@ -0,0 +1,168 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * An {@link MethodVisitor} that collects the {@link Constant}s of the methods + * it visits. + * + * @author Eric Bruneton + */ +public class MethodConstantsCollector extends MethodAdapter { + + private ConstantPool cp; + + public MethodConstantsCollector( + final MethodVisitor mv, + final ConstantPool cp) + { + super(mv); + this.cp = cp; + } + + public AnnotationVisitor visitAnnotationDefault() { + cp.newUTF8("AnnotationDefault"); + return new AnnotationConstantsCollector(mv.visitAnnotationDefault(), cp); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + cp.newUTF8(desc); + if (visible) { + cp.newUTF8("RuntimeVisibleAnnotations"); + } else { + cp.newUTF8("RuntimeInvisibleAnnotations"); + } + return new AnnotationConstantsCollector(mv.visitAnnotation(desc, + visible), cp); + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + cp.newUTF8(desc); + if (visible) { + cp.newUTF8("RuntimeVisibleParameterAnnotations"); + } else { + cp.newUTF8("RuntimeInvisibleParameterAnnotations"); + } + return new AnnotationConstantsCollector(mv.visitParameterAnnotation(parameter, + desc, + visible), + cp); + } + + public void visitTypeInsn(final int opcode, final String desc) { + cp.newClass(desc); + mv.visitTypeInsn(opcode, desc); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + cp.newField(owner, name, desc); + mv.visitFieldInsn(opcode, owner, name, desc); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + cp.newMethod(owner, name, desc, itf); + mv.visitMethodInsn(opcode, owner, name, desc); + } + + public void visitLdcInsn(final Object cst) { + cp.newConst(cst); + mv.visitLdcInsn(cst); + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + cp.newClass(desc); + mv.visitMultiANewArrayInsn(desc, dims); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + if (type != null) { + cp.newClass(type); + } + mv.visitTryCatchBlock(start, end, handler, type); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + if (signature != null) { + cp.newUTF8("LocalVariableTypeTable"); + cp.newUTF8(name); + cp.newUTF8(signature); + } + cp.newUTF8("LocalVariableTable"); + cp.newUTF8(name); + cp.newUTF8(desc); + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + + public void visitLineNumber(final int line, final Label start) { + cp.newUTF8("LineNumberTable"); + mv.visitLineNumber(line, start); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + cp.newUTF8("Code"); + mv.visitMaxs(maxStack, maxLocals); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodOptimizer.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodOptimizer.java new file mode 100644 index 000000000..ea2927498 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/MethodOptimizer.java @@ -0,0 +1,108 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; + +/** + * A {@link MethodAdapter} that renames fields and methods, and removes debug + * info. + * + * @author Eric Bruneton + */ +public class MethodOptimizer extends MethodAdapter { + + private NameMapping mapping; + + public MethodOptimizer(final MethodVisitor mv, final NameMapping mapping) { + super(mv); + this.mapping = mapping; + } + + // ------------------------------------------------------------------------ + // Overriden methods + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotationDefault() { + throw new UnsupportedOperationException(); + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + throw new UnsupportedOperationException(); + } + + public void visitTypeInsn(final int opcode, final String desc) { + mv.visitTypeInsn(opcode, desc.startsWith("[") + ? mapping.fix(desc) + : mapping.map(desc)); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitFieldInsn(opcode, mapping.map(owner), mapping.map(owner + "." + + name), mapping.fix(desc)); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitMethodInsn(opcode, mapping.map(owner), mapping.map(owner + "." + + name + desc), mapping.fix(desc)); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + // remove debug info + } + + public void visitLineNumber(final int line, final Label start) { + // remove debug info + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/NameMapping.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/NameMapping.java new file mode 100644 index 000000000..77a856b46 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/NameMapping.java @@ -0,0 +1,101 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import org.objectweb.asm.Type; + +/** + * A mapping from names to names, used to rename classes, fields and methods. + * + * @author Eric Bruneton + */ +public class NameMapping extends Properties { + + public final Set unused; + + public NameMapping(final String file) throws IOException { + load(new FileInputStream(file)); + unused = new HashSet(keySet()); + } + + public String map(final String name) { + String s = (String) get(name); + if (s == null) { + int p = name.indexOf('.'); + if (p != -1) { + int q = name.indexOf('('); + if (q != -1) { + s = name.substring(p + 1, q); + } else { + s = name.substring(p + 1); + } + } else { + s = name; + } + } else { + unused.remove(name); + } + return s; + } + + public String fix(final String desc) { + if (desc.startsWith("(")) { + Type[] arguments = Type.getArgumentTypes(desc); + Type result = Type.getReturnType(desc); + for (int i = 0; i < arguments.length; ++i) { + arguments[i] = fix(arguments[i]); + } + result = fix(result); + return Type.getMethodDescriptor(result, arguments); + } else { + return fix(Type.getType(desc)).getDescriptor(); + } + } + + private Type fix(final Type t) { + if (t.getSort() == Type.OBJECT) { + return Type.getType("L" + map(t.getInternalName()) + ";"); + } else if (t.getSort() == Type.ARRAY) { + String s = fix(t.getElementType()).getDescriptor(); + for (int i = 0; i < t.getDimensions(); ++i) { + s = "[" + s; + } + return Type.getType(s); + } else { + return t; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Shrinker.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Shrinker.java new file mode 100644 index 000000000..86da30779 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/Shrinker.java @@ -0,0 +1,168 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.optimizer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; + +/** + * A class file shrinker utility. + * + * @author Eric Bruneton + */ +public class Shrinker { + + public static void main(final String[] args) throws IOException { + NameMapping mapping = new NameMapping(args[0]); + File f = new File(args[1]); + File d = new File(args[2]); + optimize(f, d, mapping); + Iterator i = mapping.unused.iterator(); + while (i.hasNext()) { + System.out.println("INFO: unused mapping " + i.next()); + } + } + + static void optimize(final File f, final File d, final NameMapping mapping) + throws IOException + { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; ++i) { + optimize(files[i], d, mapping); + } + } else if (f.getName().endsWith(".class")) { + ConstantPool cp = new ConstantPool(); + ClassReader cr = new ClassReader(new FileInputStream(f)); + ClassWriter cw = new ClassWriter(false); + ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp); + ClassOptimizer co = new ClassOptimizer(ccc, mapping); + cr.accept(co, true); + + Set constants = new TreeSet(new ConstantComparator()); + constants.addAll(cp.values()); + + cr = new ClassReader(cw.toByteArray()); + cw = new ClassWriter(false); + Iterator i = constants.iterator(); + while (i.hasNext()) { + Constant c = (Constant) i.next(); + c.write(cw); + } + cr.accept(cw, true); + + String n = mapping.map(co.getClassName()); + File g = new File(d, n + ".class"); + if (!g.exists() || g.lastModified() < f.lastModified()) { + g.getParentFile().mkdirs(); + OutputStream os = new FileOutputStream(g); + os.write(cw.toByteArray()); + os.close(); + } + } + } + + static class ConstantComparator implements Comparator { + + public int compare(final Object o1, final Object o2) { + Constant c1 = (Constant) o1; + Constant c2 = (Constant) o2; + int d = getSort(c1) - getSort(c2); + if (d == 0) { + switch (c1.type) { + case 'I': + return new Integer(c1.intVal).compareTo(new Integer(c2.intVal)); + case 'J': + return new Long(c1.longVal).compareTo(new Long(c2.longVal)); + case 'F': + return new Float(c1.floatVal).compareTo(new Float(c2.floatVal)); + case 'D': + return new Double(c1.doubleVal).compareTo(new Double(c2.doubleVal)); + case 's': + case 'S': + case 'C': + return c1.strVal1.compareTo(c2.strVal1); + case 'T': + d = c1.strVal1.compareTo(c2.strVal1); + if (d == 0) { + d = c1.strVal2.compareTo(c2.strVal2); + } + break; + default: + d = c1.strVal1.compareTo(c2.strVal1); + if (d == 0) { + d = c1.strVal2.compareTo(c2.strVal2); + if (d == 0) { + d = c1.strVal3.compareTo(c2.strVal3); + } + } + } + } + return d; + } + + private int getSort(Constant c) { + switch (c.type) { + case 'I': + return 0; + case 'J': + return 1; + case 'F': + return 2; + case 'D': + return 3; + case 's': + return 4; + case 'S': + return 5; + case 'C': + return 6; + case 'T': + return 7; + case 'G': + return 8; + case 'M': + return 9; + default: + return 10; + } + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/shrink.properties b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/shrink.properties new file mode 100644 index 000000000..868780bdd --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/optimizer/shrink.properties @@ -0,0 +1,225 @@ +# class mappings + +#org/objectweb/asm/Edge=org/objectweb/asm/a +#org/objectweb/asm/Item=org/objectweb/asm/b +#org/objectweb/asm/FieldWriter=org/objectweb/asm/c +#org/objectweb/asm/MethodWriter=org/objectweb/asm/d +#org/objectweb/asm/AnnotationWriter=org/objectweb/asm/e + +# field mappings + +org/objectweb/asm/AnnotationWriter.cw=a +org/objectweb/asm/AnnotationWriter.size=b +org/objectweb/asm/AnnotationWriter.named=c +org/objectweb/asm/AnnotationWriter.bv=d +org/objectweb/asm/AnnotationWriter.parent=e +org/objectweb/asm/AnnotationWriter.offset=f +org/objectweb/asm/AnnotationWriter.next=g +org/objectweb/asm/AnnotationWriter.prev=h + +org/objectweb/asm/Attribute.next=a +org/objectweb/asm/Attribute.value=b + +org/objectweb/asm/ByteVector.data=a +org/objectweb/asm/ByteVector.length=b + +org/objectweb/asm/ClassReader.items=a +org/objectweb/asm/ClassReader.strings=c +org/objectweb/asm/ClassReader.maxStringLength=d +#org/objectweb/asm/ClassReader.header=e + +org/objectweb/asm/ClassWriter.TYPE=a +org/objectweb/asm/ClassWriter.version=b +org/objectweb/asm/ClassWriter.index=c +org/objectweb/asm/ClassWriter.pool=d +org/objectweb/asm/ClassWriter.items=e +org/objectweb/asm/ClassWriter.threshold=f +org/objectweb/asm/ClassWriter.key=g +org/objectweb/asm/ClassWriter.key2=h +org/objectweb/asm/ClassWriter.key3=i +org/objectweb/asm/ClassWriter.access=j +org/objectweb/asm/ClassWriter.name=k +org/objectweb/asm/ClassWriter.signature=l +org/objectweb/asm/ClassWriter.superName=m +org/objectweb/asm/ClassWriter.interfaceCount=n +org/objectweb/asm/ClassWriter.interfaces=o +org/objectweb/asm/ClassWriter.sourceFile=p +org/objectweb/asm/ClassWriter.sourceDebug=q +org/objectweb/asm/ClassWriter.enclosingMethodOwner=r +org/objectweb/asm/ClassWriter.enclosingMethod=s +org/objectweb/asm/ClassWriter.anns=t +org/objectweb/asm/ClassWriter.ianns=u +org/objectweb/asm/ClassWriter.attrs=v +org/objectweb/asm/ClassWriter.innerClassesCount=w +org/objectweb/asm/ClassWriter.innerClasses=x +org/objectweb/asm/ClassWriter.firstField=y +org/objectweb/asm/ClassWriter.lastField=z +org/objectweb/asm/ClassWriter.firstMethod=A +org/objectweb/asm/ClassWriter.lastMethod=B +org/objectweb/asm/ClassWriter.computeMaxs=C +org/objectweb/asm/ClassWriter.cr=D + +org/objectweb/asm/Edge.stackSize=a +org/objectweb/asm/Edge.successor=b +org/objectweb/asm/Edge.next=c + +org/objectweb/asm/Handler.start=a +org/objectweb/asm/Handler.end=b +org/objectweb/asm/Handler.handler=c +org/objectweb/asm/Handler.desc=d +org/objectweb/asm/Handler.type=e +org/objectweb/asm/Handler.next=f + +org/objectweb/asm/FieldWriter.next=a +org/objectweb/asm/FieldWriter.cw=b +org/objectweb/asm/FieldWriter.access=c +org/objectweb/asm/FieldWriter.name=d +org/objectweb/asm/FieldWriter.desc=e +org/objectweb/asm/FieldWriter.signature=f +org/objectweb/asm/FieldWriter.value=g +org/objectweb/asm/FieldWriter.anns=h +org/objectweb/asm/FieldWriter.ianns=i +org/objectweb/asm/FieldWriter.attrs=j + +org/objectweb/asm/Item.index=a +org/objectweb/asm/Item.type=b +org/objectweb/asm/Item.intVal=c +org/objectweb/asm/Item.longVal=d +org/objectweb/asm/Item.floatVal=e +org/objectweb/asm/Item.doubleVal=f +org/objectweb/asm/Item.strVal1=g +org/objectweb/asm/Item.strVal2=h +org/objectweb/asm/Item.strVal3=i +org/objectweb/asm/Item.hashCode=j +org/objectweb/asm/Item.next=k + +org/objectweb/asm/Label.resolved=a +org/objectweb/asm/Label.position=b +org/objectweb/asm/Label.resized=c +org/objectweb/asm/Label.referenceCount=d +org/objectweb/asm/Label.srcAndRefPositions=e +org/objectweb/asm/Label.beginStackSize=f +org/objectweb/asm/Label.maxStackSize=g +org/objectweb/asm/Label.successors=h +org/objectweb/asm/Label.next=i +org/objectweb/asm/Label.pushed=j +org/objectweb/asm/Label.line=k + +org/objectweb/asm/MethodWriter.next=a +org/objectweb/asm/MethodWriter.cw=b +org/objectweb/asm/MethodWriter.access=c +org/objectweb/asm/MethodWriter.name=d +org/objectweb/asm/MethodWriter.desc=e +org/objectweb/asm/MethodWriter.descriptor=f +org/objectweb/asm/MethodWriter.signature=g +org/objectweb/asm/MethodWriter.exceptionCount=h +org/objectweb/asm/MethodWriter.exceptions=i +org/objectweb/asm/MethodWriter.annd=j +org/objectweb/asm/MethodWriter.anns=k +org/objectweb/asm/MethodWriter.ianns=l +org/objectweb/asm/MethodWriter.panns=m +org/objectweb/asm/MethodWriter.ipanns=n +org/objectweb/asm/MethodWriter.attrs=o +org/objectweb/asm/MethodWriter.code=p +org/objectweb/asm/MethodWriter.maxStack=q +org/objectweb/asm/MethodWriter.maxLocals=r +org/objectweb/asm/MethodWriter.catchCount=s +org/objectweb/asm/MethodWriter.catchTable=t +org/objectweb/asm/MethodWriter.localVarCount=u +org/objectweb/asm/MethodWriter.localVar=v +org/objectweb/asm/MethodWriter.localVarTypeCount=w +org/objectweb/asm/MethodWriter.localVarType=x +org/objectweb/asm/MethodWriter.lineNumberCount=y +org/objectweb/asm/MethodWriter.lineNumber=z +org/objectweb/asm/MethodWriter.cattrs=A +org/objectweb/asm/MethodWriter.resize=B +org/objectweb/asm/MethodWriter.computeMaxs=C +org/objectweb/asm/MethodWriter.stackSize=D +org/objectweb/asm/MethodWriter.maxStackSize=E +org/objectweb/asm/MethodWriter.currentBlock=F +org/objectweb/asm/MethodWriter.blockStack=G +org/objectweb/asm/MethodWriter.SIZE=H +org/objectweb/asm/MethodWriter.classReaderOffset=I +org/objectweb/asm/MethodWriter.classReaderLength=J +org/objectweb/asm/MethodWriter.lastHandler=K + +org/objectweb/asm/Type.sort=a +org/objectweb/asm/Type.buf=b +org/objectweb/asm/Type.off=c +org/objectweb/asm/Type.len=d + +org/objectweb/asm/signature/SignatureReader.signature=a + +org/objectweb/asm/signature/SignatureWriter.buf=a +org/objectweb/asm/signature/SignatureWriter.hasFormals=b +org/objectweb/asm/signature/SignatureWriter.hasParameters=c +org/objectweb/asm/signature/SignatureWriter.argumentStack=d + +# method mappings + +org/objectweb/asm/AnnotationWriter.getSize()I=a +org/objectweb/asm/AnnotationWriter.put([Lorg/objectweb/asm/AnnotationWriter;Lorg/objectweb/asm/ByteVector;)V=a +org/objectweb/asm/AnnotationWriter.put(Lorg/objectweb/asm/ByteVector;)V=a + +org/objectweb/asm/Attribute.getCount()I=a +org/objectweb/asm/Attribute.getSize(Lorg/objectweb/asm/ClassWriter;[BIII)I=a +org/objectweb/asm/Attribute.put(Lorg/objectweb/asm/ClassWriter;[BIIILorg/objectweb/asm/ByteVector;)V=a + +org/objectweb/asm/ByteVector.enlarge(I)V=a +org/objectweb/asm/ByteVector.put11(II)Lorg/objectweb/asm/ByteVector;=a +org/objectweb/asm/ByteVector.put12(II)Lorg/objectweb/asm/ByteVector;=b + +org/objectweb/asm/ClassReader.copyPool(Lorg/objectweb/asm/ClassWriter;)V=a +org/objectweb/asm/ClassReader.readAnnotationValue(I[CLjava/lang/String;Lorg/objectweb/asm/AnnotationVisitor;)I=a +org/objectweb/asm/ClassReader.readAnnotationValues(I[CLorg/objectweb/asm/AnnotationVisitor;)I=a +org/objectweb/asm/ClassReader.readAttribute([Lorg/objectweb/asm/Attribute;Ljava/lang/String;II[CI[Lorg/objectweb/asm/Label;)Lorg/objectweb/asm/Attribute;=a +org/objectweb/asm/ClassReader.readClass(Ljava/io/InputStream;)[B=a +org/objectweb/asm/ClassReader.readParameterAnnotations(I[CZLorg/objectweb/asm/MethodVisitor;)V=a +org/objectweb/asm/ClassReader.readUTF(II[C)Ljava/lang/String;=a + +org/objectweb/asm/ClassWriter.get(Lorg/objectweb/asm/Item;)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newClassItem(Ljava/lang/String;)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newConstItem(Ljava/lang/Object;)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newDouble(D)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newFloat(F)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newInteger(I)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newLong(J)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newMethodItem(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lorg/objectweb/asm/Item;=a +org/objectweb/asm/ClassWriter.newString(Ljava/lang/String;)Lorg/objectweb/asm/Item;=b +org/objectweb/asm/ClassWriter.put122(III)V=a +org/objectweb/asm/ClassWriter.put(Lorg/objectweb/asm/Item;)V=b + +org/objectweb/asm/FieldWriter.getSize()I=a +org/objectweb/asm/FieldWriter.put(Lorg/objectweb/asm/ByteVector;)V=a + +org/objectweb/asm/Item.isEqualTo(Lorg/objectweb/asm/Item;)Z=a +org/objectweb/asm/Item.set(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V=a +org/objectweb/asm/Item.set(D)V=a +org/objectweb/asm/Item.set(F)V=a +org/objectweb/asm/Item.set(I)V=a +org/objectweb/asm/Item.set(J)V=a + +org/objectweb/asm/Label.addReference(II)V=a +org/objectweb/asm/Label.put(Lorg/objectweb/asm/MethodWriter;Lorg/objectweb/asm/ByteVector;IZ)V=a +org/objectweb/asm/Label.resolve(Lorg/objectweb/asm/MethodWriter;I[B)Z=a + +org/objectweb/asm/MethodWriter.addSuccessor(ILorg/objectweb/asm/Label;)V=a +org/objectweb/asm/MethodWriter.getArgumentsAndReturnSizes(Ljava/lang/String;)I=a +org/objectweb/asm/MethodWriter.getNewOffset([I[III)I=a +org/objectweb/asm/MethodWriter.getSize()I=a +org/objectweb/asm/MethodWriter.put(Lorg/objectweb/asm/ByteVector;)V=a +org/objectweb/asm/MethodWriter.readInt([BI)I=a +org/objectweb/asm/MethodWriter.readShort([BI)S=b +org/objectweb/asm/MethodWriter.readUnsignedShort([BI)I=c +org/objectweb/asm/MethodWriter.resizeInstructions([I[II)[I=a +org/objectweb/asm/MethodWriter.writeShort([BII)V=a +org/objectweb/asm/MethodWriter.getNewOffset([I[ILorg/objectweb/asm/Label;)V=a + +org/objectweb/asm/Type.getType([CI)Lorg/objectweb/asm/Type;=a +org/objectweb/asm/Type.getDescriptor(Ljava/lang/StringBuffer;)V=a +org/objectweb/asm/Type.getDescriptor(Ljava/lang/StringBuffer;Ljava/lang/Class;)V=a + +org/objectweb/asm/signature/SignatureReader.parseType(Ljava/lang/String;ILorg/objectweb/asm/signature/SignatureVisitor;)I=a + +org/objectweb/asm/signature/SignatureWriter.endFormals()V=a +org/objectweb/asm/signature/SignatureWriter.endArguments()V=b diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureReader.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureReader.java new file mode 100644 index 000000000..a2f31f39e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureReader.java @@ -0,0 +1,233 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.signature; + +/** + * A type signature parser to make a signature visitor visit an existing + * signature. + * + * @author Thomas Hallgren + * @author Eric Bruneton + */ +public class SignatureReader { + + /** + * The signature to be read. + */ + private final String signature; + + /** + * Constructs a {@link SignatureReader} for the given signature. + * + * @param signature A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, + * or <i>FieldTypeSignature</i>. + */ + public SignatureReader(final String signature) { + this.signature = signature; + } + + /** + * Makes the given visitor visit the signature of this + * {@link SignatureReader}. This signature is the one specified in the + * constructor (see {@link #SignatureReader(String) SignatureReader}). This + * method is intended to be called on a {@link SignatureReader} that was + * created using a <i>ClassSignature</i> (such as the + * <code>signature</code> parameter of the + * {@link org.objectweb.asm.ClassVisitor#visit ClassVisitor.visit} method) + * or a <i>MethodTypeSignature</i> (such as the <code>signature</code> + * parameter of the + * {@link org.objectweb.asm.ClassVisitor#visitMethod ClassVisitor.visitMethod} + * method). + * + * @param v the visitor that must visit this signature. + */ + public void accept(final SignatureVisitor v) { + String signature = this.signature; + int len = signature.length(); + int pos; + char c; + + if (signature.charAt(0) == '<') { + pos = 2; + do { + int end = signature.indexOf(':', pos); + v.visitFormalTypeParameter(signature.substring(pos - 1, end)); + pos = end + 1; + + c = signature.charAt(pos); + if (c == 'L' || c == '[' || c == 'T') { + pos = parseType(signature, pos, v.visitClassBound()); + } + + for (;;) { + if ((c = signature.charAt(pos++)) == ':') { + pos = parseType(signature, pos, v.visitInterfaceBound()); + } else { + break; + } + } + } while (c != '>'); + } else { + pos = 0; + } + + if (signature.charAt(pos) == '(') { + pos = pos + 1; + while (signature.charAt(pos) != ')') { + pos = parseType(signature, pos, v.visitParameterType()); + } + pos = parseType(signature, pos + 1, v.visitReturnType()); + while (pos < len) { + pos = parseType(signature, pos + 1, v.visitExceptionType()); + } + } else { + pos = parseType(signature, pos, v.visitSuperclass()); + while (pos < len) { + pos = parseType(signature, pos, v.visitInterface()); + } + } + } + + /** + * Makes the given visitor visit the signature of this + * {@link SignatureReader}. This signature is the one specified in the + * constructor (see {@link #SignatureReader(String) SignatureReader}). This + * method is intended to be called on a {@link SignatureReader} that was + * created using a <i>FieldTypeSignature</i>, such as the + * <code>signature</code> parameter of the + * {@link org.objectweb.asm.ClassVisitor#visitField + * ClassVisitor.visitField} or {@link + * org.objectweb.asm.MethodVisitor#visitLocalVariable + * MethodVisitor.visitLocalVariable} methods. + * + * @param v the visitor that must visit this signature. + */ + public void acceptType(final SignatureVisitor v) { + parseType(this.signature, 0, v); + } + + /** + * Parses a field type signature and makes the given visitor visit it. + * + * @param signature a string containing the signature that must be parsed. + * @param pos index of the first character of the signature to parsed. + * @param v the visitor that must visit this signature. + * @return the index of the first character after the parsed signature. + */ + private static int parseType( + final String signature, + int pos, + final SignatureVisitor v) + { + char c; + int start, end; + boolean visited, inner; + String name; + + switch (c = signature.charAt(pos++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'V': + v.visitBaseType(c); + return pos; + + case '[': + return parseType(signature, pos, v.visitArrayType()); + + case 'T': + end = signature.indexOf(';', pos); + v.visitTypeVariable(signature.substring(pos, end)); + return end + 1; + + default: // case 'L': + start = pos; + visited = false; + inner = false; + for (;;) { + switch (c = signature.charAt(pos++)) { + case '.': + case ';': + if (!visited) { + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name); + } else { + v.visitClassType(name); + } + } + if (c == ';') { + v.visitEnd(); + return pos; + } + start = pos; + visited = false; + inner = true; + break; + + case '<': + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name); + } else { + v.visitClassType(name); + } + visited = true; + top: for (;;) { + switch (c = signature.charAt(pos)) { + case '>': + break top; + case '*': + ++pos; + v.visitTypeArgument(); + break; + case '+': + case '-': + pos = parseType(signature, + pos + 1, + v.visitTypeArgument(c)); + break; + default: + pos = parseType(signature, + pos, + v.visitTypeArgument('=')); + break; + } + } + } + } + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureVisitor.java new file mode 100644 index 000000000..46df8c939 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureVisitor.java @@ -0,0 +1,185 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.signature; + +/** + * A visitor to visit a generic signature. The methods of this interface must be + * called in one of the three following orders (the last one is the only valid + * order for a {@link SignatureVisitor} that is returned by a method of this + * interface): <ul> <li><i>ClassSignature</i> = ( + * <tt>visitFormalTypeParameter</tt> + * <tt>visitClassBound</tt>? + * <tt>visitInterfaceBound</tt>* )* ( <tt>visitSuperClass</tt> + * <tt>visitInterface</tt>* )</li> + * <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt> + * <tt>visitClassBound</tt>? + * <tt>visitInterfaceBound</tt>* )* ( <tt>visitParameterType</tt>* + * <tt>visitReturnType</tt> + * <tt>visitExceptionType</tt>* )</li> <li><i>TypeSignature</i> = + * <tt>visitBaseType</tt> | <tt>visitTypeVariable</tt> | + * <tt>visitArrayType</tt> | ( + * <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* ( + * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* + * <tt>visitEnd</tt> ) )</li> </ul> + * + * @author Thomas Hallgren + * @author Eric Bruneton + */ +public interface SignatureVisitor { + + /** + * Wildcard for an "extends" type argument. + */ + char EXTENDS = '+'; + + /** + * Wildcard for a "super" type argument. + */ + char SUPER = '-'; + + /** + * Wildcard for a normal type argument. + */ + char INSTANCEOF = '='; + + /** + * Visits a formal type parameter. + * + * @param name the name of the formal parameter. + */ + void visitFormalTypeParameter(String name); + + /** + * Visits the class bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the class bound. + */ + SignatureVisitor visitClassBound(); + + /** + * Visits an interface bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the interface bound. + */ + SignatureVisitor visitInterfaceBound(); + + /** + * Visits the type of the super class. + * + * @return a non null visitor to visit the signature of the super class + * type. + */ + SignatureVisitor visitSuperclass(); + + /** + * Visits the type of an interface implemented by the class. + * + * @return a non null visitor to visit the signature of the interface type. + */ + SignatureVisitor visitInterface(); + + /** + * Visits the type of a method parameter. + * + * @return a non null visitor to visit the signature of the parameter type. + */ + SignatureVisitor visitParameterType(); + + /** + * Visits the return type of the method. + * + * @return a non null visitor to visit the signature of the return type. + */ + SignatureVisitor visitReturnType(); + + /** + * Visits the type of a method exception. + * + * @return a non null visitor to visit the signature of the exception type. + */ + SignatureVisitor visitExceptionType(); + + /** + * Visits a signature corresponding to a primitive type. + * + * @param descriptor the descriptor of the primitive type, or 'V' for + * <tt>void</tt>. + */ + void visitBaseType(char descriptor); + + /** + * Visits a signature corresponding to a type variable. + * + * @param name the name of the type variable. + */ + void visitTypeVariable(String name); + + /** + * Visits a signature corresponding to an array type. + * + * @return a non null visitor to visit the signature of the array element + * type. + */ + SignatureVisitor visitArrayType(); + + /** + * Starts the visit of a signature corresponding to a class or interface + * type. + * + * @param name the internal name of the class or interface. + */ + void visitClassType(String name); + + /** + * Visits an inner class. + * + * @param name the local name of the inner class in its enclosing class. + */ + void visitInnerClassType(String name); + + /** + * Visits an unbounded type argument of the last visited class or inner + * class type. + */ + void visitTypeArgument(); + + /** + * Visits a type argument of the last visited class or inner class type. + * + * @param wildcard '+', '-' or '='. + * @return a non null visitor to visit the signature of the type argument. + */ + SignatureVisitor visitTypeArgument(char wildcard); + + /** + * Ends the visit of a signature corresponding to a class or interface type. + */ + void visitEnd(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureWriter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureWriter.java new file mode 100644 index 000000000..833d688b8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/signature/SignatureWriter.java @@ -0,0 +1,207 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.signature; + +/** + * A signature visitor that generates signatures in string format. + * + * @author Thomas Hallgren + * @author Eric Bruneton + */ +public class SignatureWriter implements SignatureVisitor { + + /** + * Buffer used to construct the signature. + */ + private final StringBuffer buf = new StringBuffer(); + + /** + * Indicates if the signature contains formal type parameters. + */ + private boolean hasFormals; + + /** + * Indicates if the signature contains method parameter types. + */ + private boolean hasParameters; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Constructs a new {@link SignatureWriter} object. + */ + public SignatureWriter() { + } + + // ------------------------------------------------------------------------ + // Implementation of the SignatureVisitor interface + // ------------------------------------------------------------------------ + + public void visitFormalTypeParameter(String name) { + if (!hasFormals) { + hasFormals = true; + buf.append('<'); + } + buf.append(name); + buf.append(':'); + } + + public SignatureVisitor visitClassBound() { + return this; + } + + public SignatureVisitor visitInterfaceBound() { + buf.append(':'); + return this; + } + + public SignatureVisitor visitSuperclass() { + endFormals(); + return this; + } + + public SignatureVisitor visitInterface() { + return this; + } + + public SignatureVisitor visitParameterType() { + endFormals(); + if (!hasParameters) { + hasParameters = true; + buf.append('('); + } + return this; + } + + public SignatureVisitor visitReturnType() { + endFormals(); + if (!hasParameters) { + buf.append('('); + } + buf.append(')'); + return this; + } + + public SignatureVisitor visitExceptionType() { + buf.append('^'); + return this; + } + + public void visitBaseType(char descriptor) { + buf.append(descriptor); + } + + public void visitTypeVariable(String name) { + buf.append('T'); + buf.append(name); + buf.append(';'); + } + + public SignatureVisitor visitArrayType() { + buf.append('['); + return this; + } + + public void visitClassType(String name) { + buf.append('L'); + buf.append(name); + argumentStack *= 2; + } + + public void visitInnerClassType(String name) { + endArguments(); + buf.append('.'); + buf.append(name); + argumentStack *= 2; + } + + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + buf.append('*'); + } + + public SignatureVisitor visitTypeArgument(char wildcard) { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + if (wildcard != '=') { + buf.append(wildcard); + } + return this; + } + + public void visitEnd() { + endArguments(); + buf.append(';'); + } + + /** + * Returns the signature that was built by this signature writer. + * + * @return the signature that was built by this signature writer. + */ + public String toString() { + return buf.toString(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Ends the formal type parameters section of the signature. + */ + private void endFormals() { + if (hasFormals) { + hasFormals = false; + buf.append('>'); + } + } + + /** + * Ends the type arguments of a class or inner class type. + */ + private void endArguments() { + if (argumentStack % 2 == 1) { + buf.append('>'); + } + argumentStack /= 2; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AbstractInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AbstractInsnNode.java new file mode 100644 index 000000000..e0009da98 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AbstractInsnNode.java @@ -0,0 +1,143 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 bytecode instruction. + * + * @author Eric Bruneton + */ +public abstract class AbstractInsnNode { + + /** + * The type of {@link InsnNode} instructions. + */ + public final static int INSN = 0; + + /** + * The type of {@link IntInsnNode} instructions. + */ + public final static int INT_INSN = 1; + + /** + * The type of {@link VarInsnNode} instructions. + */ + public final static int VAR_INSN = 2; + + /** + * The type of {@link TypeInsnNode} instructions. + */ + public final static int TYPE_INSN = 3; + + /** + * The type of {@link FieldInsnNode} instructions. + */ + public final static int FIELD_INSN = 4; + + /** + * The type of {@link MethodInsnNode} instructions. + */ + public final static int METHOD_INSN = 5; + + /** + * The type of {@link JumpInsnNode} instructions. + */ + public final static int JUMP_INSN = 6; + + /** + * The type of {@link LabelNode} "instructions". + */ + public final static int LABEL = 7; + + /** + * The type of {@link LdcInsnNode} instructions. + */ + public final static int LDC_INSN = 8; + + /** + * The type of {@link IincInsnNode} instructions. + */ + public final static int IINC_INSN = 9; + + /** + * The type of {@link TableSwitchInsnNode} instructions. + */ + public final static int TABLESWITCH_INSN = 10; + + /** + * The type of {@link LookupSwitchInsnNode} instructions. + */ + public final static int LOOKUPSWITCH_INSN = 11; + + /** + * The type of {@link MultiANewArrayInsnNode} instructions. + */ + public final static int MULTIANEWARRAY_INSN = 12; + + /** + * The opcode of this instruction. + */ + protected int opcode; + + /** + * Constructs a new {@link AbstractInsnNode}. + * + * @param opcode the opcode of the instruction to be constructed. + */ + protected AbstractInsnNode(final int opcode) { + this.opcode = opcode; + } + + /** + * 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(); + + /** + * Makes the given code visitor visit this instruction. + * + * @param cv a code visitor. + */ + public abstract void accept(final MethodVisitor cv); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AnnotationNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AnnotationNode.java new file mode 100644 index 000000000..c9c1cb98f --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/AnnotationNode.java @@ -0,0 +1,187 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A node that represents an annotationn. + * + * @author Eric Bruneton + */ +public class AnnotationNode implements 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 values; + + /** + * Constructs a new {@link AnnotationNode}. + * + * @param desc the class descriptor of the annotation class. + */ + public AnnotationNode(final String desc) { + 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 values) { + this.values = values; + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor interface + // ------------------------------------------------------------------------ + + public void visit(final String name, final Object value) { + if (values == null) { + values = new ArrayList(this.desc != null ? 2 : 1); + } + if (this.desc != null) { + values.add(name); + } + values.add(value); + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + if (values == null) { + values = new ArrayList(this.desc != null ? 2 : 1); + } + if (this.desc != null) { + values.add(name); + } + values.add(new String[] { desc, value }); + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + if (values == null) { + values = new ArrayList(this.desc != null ? 2 : 1); + } + if (this.desc != null) { + values.add(name); + } + AnnotationNode annotation = new AnnotationNode(desc); + values.add(annotation); + return annotation; + } + + public AnnotationVisitor visitArray(final String name) { + if (values == null) { + values = new ArrayList(this.desc != null ? 2 : 1); + } + if (this.desc != null) { + values.add(name); + } + List array = new ArrayList(); + values.add(array); + return new AnnotationNode(array); + } + + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Accept methods + // ------------------------------------------------------------------------ + + /** + * Makes the given visitor visit this annotation. + * + * @param av an annotation visitor. + */ + public void accept(final AnnotationVisitor av) { + 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. + * @param name the value name. + * @param value the actual value. + */ + static void accept( + final AnnotationVisitor av, + final String name, + final Object value) + { + 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); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/ClassNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/ClassNode.java new file mode 100644 index 000000000..85134e3a5 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/ClassNode.java @@ -0,0 +1,283 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Attribute; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.FieldVisitor; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A node that represents a class. + * + * @author Eric Bruneton + */ +public class ClassNode extends MemberNode implements ClassVisitor { + + /** + * The class version. + */ + public int version; + + /** + * The class's access flags (see {@link org.objectweb.asm.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. Mayt 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 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 correspondance 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; + + /** + * 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 innerClasses; + + /** + * The fields of this class. This list is a list of {@link FieldNode} + * objects. + * + * @associates org.objectweb.asm.tree.FieldNode + */ + public List fields; + + /** + * The methods of this class. This list is a list of {@link MethodNode} + * objects. + * + * @associates org.objectweb.asm.tree.MethodNode + */ + public List methods; + + /** + * Constructs a new {@link ClassNode}. + */ + public ClassNode() { + this.interfaces = new ArrayList(); + this.innerClasses = new ArrayList(); + this.fields = new ArrayList(); + this.methods = new ArrayList(); + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + this.version = version; + this.access = access; + this.name = name; + this.signature = signature; + this.superName = superName; + if (interfaces != null) { + this.interfaces.addAll(Arrays.asList(interfaces)); + } + } + + public void visitSource(final String file, final String debug) { + sourceFile = file; + sourceDebug = debug; + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + outerClass = owner; + outerMethod = name; + outerMethodDesc = desc; + } + + 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); + } + + 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; + } + + 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; + } + + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Accept method + // ------------------------------------------------------------------------ + + /** + * 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 = (AnnotationNode) visibleAnnotations.get(i); + an.accept(cv.visitAnnotation(an.desc, true)); + } + n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); + an.accept(cv.visitAnnotation(an.desc, false)); + } + n = attrs == null ? 0 : attrs.size(); + for (i = 0; i < n; ++i) { + cv.visitAttribute((Attribute) attrs.get(i)); + } + // visits inner classes + for (i = 0; i < innerClasses.size(); ++i) { + ((InnerClassNode) innerClasses.get(i)).accept(cv); + } + // visits fields + for (i = 0; i < fields.size(); ++i) { + ((FieldNode) fields.get(i)).accept(cv); + } + // visits methods + for (i = 0; i < methods.size(); ++i) { + ((MethodNode) methods.get(i)).accept(cv); + } + // visits end + cv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldInsnNode.java new file mode 100644 index 000000000..2ae5388b1 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldInsnNode.java @@ -0,0 +1,97 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 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; + } + + public void accept(final MethodVisitor cv) { + cv.visitFieldInsn(opcode, owner, name, desc); + } + + public int getType() { + return FIELD_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldNode.java new file mode 100644 index 000000000..8a97b1cbc --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/FieldNode.java @@ -0,0 +1,123 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Attribute; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; + +/** + * A node that represents a field. + * + * @author Eric Bruneton + */ +public class FieldNode extends MemberNode implements FieldVisitor { + + /** + * The field's access flags (see {@link org.objectweb.asm.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; + + /** + * Constructs a new {@link FieldNode}. + * + * @param access the field's access flags (see + * {@link org.objectweb.asm.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}). + * @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.access = access; + this.name = name; + this.desc = desc; + this.signature = signature; + this.value = value; + } + + /** + * 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); + int i, n; + n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); + an.accept(fv.visitAnnotation(an.desc, true)); + } + n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); + an.accept(fv.visitAnnotation(an.desc, false)); + } + n = attrs == null ? 0 : attrs.size(); + for (i = 0; i < n; ++i) { + fv.visitAttribute((Attribute) attrs.get(i)); + } + fv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IincInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IincInsnNode.java new file mode 100644 index 000000000..b5399b07d --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IincInsnNode.java @@ -0,0 +1,71 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; +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; + } + + public void accept(final MethodVisitor mv) { + mv.visitIincInsn(var, incr); + } + + public int getType() { + return IINC_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InnerClassNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InnerClassNode.java new file mode 100644 index 000000000..6af060ee8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InnerClassNode.java @@ -0,0 +1,101 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InsnNode.java new file mode 100644 index 000000000..718272600 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/InsnNode.java @@ -0,0 +1,96 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 zero operand instruction. + * + * @author Eric Bruneton + */ +public class InsnNode extends AbstractInsnNode { + + private final static InsnNode[] INSNS; + + static { + INSNS = new InsnNode[255]; + for (int i = 0; i < INSNS.length; ++i) { + INSNS[i] = new InsnNode(i); + } + } + + /** + * Returns the {@link InsnNode} corresponding to the given opcode. + * + * @deprecated uses the constructor instead. + * + * @param opcode an instruction opcode. + * @return the {@link InsnNode} corresponding to the given opcode. + */ + public final static InsnNode getByOpcode(final int opcode) { + return INSNS[opcode]; + } + + /** + * 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); + } + + /** + * Makes the given visitor visit this instruction. + * + * @param mv a method visitor. + */ + public void accept(final MethodVisitor mv) { + mv.visitInsn(opcode); + } + + public int getType() { + return INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IntInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IntInsnNode.java new file mode 100644 index 000000000..b9b02e382 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/IntInsnNode.java @@ -0,0 +1,75 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 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; + } + + public void accept(final MethodVisitor mv) { + mv.visitIntInsn(opcode, operand); + } + + public int getType() { + return INT_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/JumpInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/JumpInsnNode.java new file mode 100644 index 000000000..7dccf32be --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/JumpInsnNode.java @@ -0,0 +1,84 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +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 Label 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 Label 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; + } + + public void accept(final MethodVisitor mv) { + mv.visitJumpInsn(opcode, label); + } + + public int getType() { + return JUMP_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LabelNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LabelNode.java new file mode 100644 index 000000000..0f8c93351 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LabelNode.java @@ -0,0 +1,54 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.MethodVisitor; + +/** + * An {@link AbstractInsnNode} that encapsulates a {@link Label}. + */ +public class LabelNode extends AbstractInsnNode { + + public Label label; + + public LabelNode(final Label label) { + super(-1); + this.label = label; + } + + public void accept(final MethodVisitor cv) { + cv.visitLabel(label); + } + + public int getType() { + return LABEL; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LdcInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LdcInsnNode.java new file mode 100644 index 000000000..234b41fe3 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LdcInsnNode.java @@ -0,0 +1,68 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; +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; + } + + public void accept(final MethodVisitor mv) { + mv.visitLdcInsn(cst); + } + + public int getType() { + return LDC_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LineNumberNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LineNumberNode.java new file mode 100644 index 000000000..2a3498844 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LineNumberNode.java @@ -0,0 +1,73 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.MethodVisitor; + +/** + * A node that represents a line number declaration. + * + * @author Eric Bruneton + */ +public class LineNumberNode { + + /** + * 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 Label 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 Label start) { + this.line = line; + this.start = start; + } + + /** + * Makes the given visitor visit this line number declaration. + * + * @param mv a method visitor. + */ + public void accept(final MethodVisitor mv) { + mv.visitLineNumber(line, start); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LocalVariableNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LocalVariableNode.java new file mode 100644 index 000000000..511dcf964 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LocalVariableNode.java @@ -0,0 +1,111 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; +import org.objectweb.asm.Label; + +/** + * 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 Label start; + + /** + * The last instruction corresponding to the scope of this local variable + * (exclusive). + */ + public Label 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 Label start, + final Label 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, end, index); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LookupSwitchInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LookupSwitchInsnNode.java new file mode 100644 index 000000000..31eb234e8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/LookupSwitchInsnNode.java @@ -0,0 +1,103 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.MethodVisitor; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A node that represents a LOOKUPSWITCH instruction. + * + * @author Eric Bruneton + */ +public class LookupSwitchInsnNode extends AbstractInsnNode { + + /** + * Beginning of the default handler block. + */ + public Label dflt; + + /** + * The values of the keys. This list is a list of {@link Integer} objects. + */ + public List keys; + + /** + * Beginnings of the handler blocks. This list is a list of {@link Label} + * objects. + */ + public List 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 Label dflt, + final int[] keys, + final Label[] labels) + { + super(Opcodes.LOOKUPSWITCH); + this.dflt = dflt; + this.keys = new ArrayList(keys == null ? 0 : keys.length); + this.labels = new ArrayList(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)); + } + } + + public void accept(final MethodVisitor mv) { + int[] keys = new int[this.keys.size()]; + for (int i = 0; i < keys.length; ++i) { + keys[i] = ((Integer) this.keys.get(i)).intValue(); + } + Label[] labels = new Label[this.labels.size()]; + this.labels.toArray(labels); + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + + public int getType() { + return LOOKUPSWITCH_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MemberNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MemberNode.java new file mode 100644 index 000000000..11dfad862 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MemberNode.java @@ -0,0 +1,120 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * An abstract class, field or method node. + * + * @author Eric Bruneton + */ +public abstract class MemberNode { + + /** + * The runtime visible annotations of this class, field or 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 visibleAnnotations; + + /** + * The runtime invisible annotations of this class, field or 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 invisibleAnnotations; + + /** + * The non standard attributes of this class, field or method. This list is + * a list of {@link Attribute} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.Attribute + */ + public List attrs; + + /** + * Constructs a new {@link MemberNode}. + */ + public MemberNode() { + } + + /** + * Visits an annotation of this class, field or method. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values. + */ + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationNode an = new AnnotationNode(desc); + if (visible) { + if (visibleAnnotations == null) { + visibleAnnotations = new ArrayList(1); + } + visibleAnnotations.add(an); + } else { + if (invisibleAnnotations == null) { + invisibleAnnotations = new ArrayList(1); + } + invisibleAnnotations.add(an); + } + return an; + } + + /** + * Visits a non standard attribute of this class, field or method. + * + * @param attr an attribute. + */ + public void visitAttribute(final Attribute attr) { + if (attrs == null) { + attrs = new ArrayList(1); + } + attrs.add(attr); + } + + /** + * Visits the end of this class, field or method. + */ + public void visitEnd() { + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodInsnNode.java new file mode 100644 index 000000000..f22744706 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodInsnNode.java @@ -0,0 +1,98 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 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; + } + + public void accept(final MethodVisitor mv) { + mv.visitMethodInsn(opcode, owner, name, desc); + } + + public int getType() { + return METHOD_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodNode.java new file mode 100644 index 000000000..9d0b2e9cf --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MethodNode.java @@ -0,0 +1,439 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A node that represents a method. + * + * @author Eric Bruneton + */ +public class MethodNode extends MemberNode implements 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 exceptions; + + /** + * 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[] 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[] invisibleParameterAnnotations; + + /** + * The instructions of this method. This list is a list of + * {@link AbstractInsnNode} objects. + * + * @associates org.objectweb.asm.tree.AbstractInsnNode + * @label instructions + */ + public List 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 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 localVariables; + + /** + * The line numbers of this method. This list is a list of + * {@link LineNumberNode} objects. May be <tt>null</tt> + * + * @associates org.objectweb.asm.tree.LineNumberNode + */ + public List lineNumbers; + + /** + * Constructs a new {@link MethodNode}. + * + * @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.access = access; + this.name = name; + this.desc = desc; + this.signature = signature; + this.exceptions = new ArrayList(exceptions == null + ? 0 + : exceptions.length); + boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; + this.instructions = new ArrayList(isAbstract ? 0 : 24); + if (!isAbstract) { + this.localVariables = new ArrayList(5); + this.lineNumbers = new ArrayList(5); + } + this.tryCatchBlocks = new ArrayList(); + if (exceptions != null) { + this.exceptions.addAll(Arrays.asList(exceptions)); + } + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor interface + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotationDefault() { + return new AnnotationNode(new ArrayList(0) { + public boolean add(Object o) { + annotationDefault = o; + return super.add(o); + } + }); + } + + 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 = new List[params]; + } + if (visibleParameterAnnotations[parameter] == null) { + visibleParameterAnnotations[parameter] = new ArrayList(1); + } + visibleParameterAnnotations[parameter].add(an); + } else { + if (invisibleParameterAnnotations == null) { + int params = Type.getArgumentTypes(this.desc).length; + invisibleParameterAnnotations = new List[params]; + } + if (invisibleParameterAnnotations[parameter] == null) { + invisibleParameterAnnotations[parameter] = new ArrayList(1); + } + invisibleParameterAnnotations[parameter].add(an); + } + return an; + } + + public void visitCode() { + } + + public void visitInsn(final int opcode) { + instructions.add(new InsnNode(opcode)); + } + + public void visitIntInsn(final int opcode, final int operand) { + instructions.add(new IntInsnNode(opcode, operand)); + } + + public void visitVarInsn(final int opcode, final int var) { + instructions.add(new VarInsnNode(opcode, var)); + } + + public void visitTypeInsn(final int opcode, final String desc) { + instructions.add(new TypeInsnNode(opcode, desc)); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + instructions.add(new FieldInsnNode(opcode, owner, name, desc)); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + instructions.add(new MethodInsnNode(opcode, owner, name, desc)); + } + + public void visitJumpInsn(final int opcode, final Label label) { + instructions.add(new JumpInsnNode(opcode, label)); + } + + public void visitLabel(final Label label) { + instructions.add(new LabelNode(label)); + } + + public void visitLdcInsn(final Object cst) { + instructions.add(new LdcInsnNode(cst)); + } + + public void visitIincInsn(final int var, final int increment) { + instructions.add(new IincInsnNode(var, increment)); + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label[] labels) + { + instructions.add(new TableSwitchInsnNode(min, max, dflt, labels)); + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int[] keys, + final Label[] labels) + { + instructions.add(new LookupSwitchInsnNode(dflt, keys, labels)); + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + instructions.add(new MultiANewArrayInsnNode(desc, dims)); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + tryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, type)); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + localVariables.add(new LocalVariableNode(name, + desc, + signature, + start, + end, + index)); + } + + public void visitLineNumber(final int line, final Label start) { + lineNumbers.add(new LineNumberNode(line, start)); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + + // ------------------------------------------------------------------------ + // Accept method + // ------------------------------------------------------------------------ + + /** + * 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 attributes + int i, j, n; + if (annotationDefault != null) { + AnnotationVisitor av = mv.visitAnnotationDefault(); + AnnotationNode.accept(av, null, annotationDefault); + av.visitEnd(); + } + n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); + an.accept(mv.visitAnnotation(an.desc, true)); + } + n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); + an.accept(mv.visitAnnotation(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)); + } + } + n = attrs == null ? 0 : attrs.size(); + for (i = 0; i < n; ++i) { + mv.visitAttribute((Attribute) attrs.get(i)); + } + // visits the method's code + if (instructions.size() > 0) { + mv.visitCode(); + // visits try catch blocks + for (i = 0; i < tryCatchBlocks.size(); ++i) { + ((TryCatchBlockNode) tryCatchBlocks.get(i)).accept(mv); + } + // visits instructions + for (i = 0; i < instructions.size(); ++i) { + ((AbstractInsnNode) instructions.get(i)).accept(mv); + } + // visits local variables + n = localVariables == null ? 0 : localVariables.size(); + for (i = 0; i < n; ++i) { + ((LocalVariableNode) localVariables.get(i)).accept(mv); + } + // visits line numbers + n = lineNumbers == null ? 0 : lineNumbers.size(); + for (i = 0; i < n; ++i) { + ((LineNumberNode) lineNumbers.get(i)).accept(mv); + } + // visits maxs + mv.visitMaxs(maxStack, maxLocals); + } + mv.visitEnd(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MultiANewArrayInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MultiANewArrayInsnNode.java new file mode 100644 index 000000000..ed81347dc --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/MultiANewArrayInsnNode.java @@ -0,0 +1,71 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.MethodVisitor; + +/** + * 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; + } + + public void accept(final MethodVisitor mv) { + mv.visitMultiANewArrayInsn(desc, dims); + } + + public int getType() { + return MULTIANEWARRAY_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TableSwitchInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TableSwitchInsnNode.java new file mode 100644 index 000000000..840309dd6 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TableSwitchInsnNode.java @@ -0,0 +1,102 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.MethodVisitor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 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 Label dflt; + + /** + * Beginnings of the handler blocks. This list is a list of {@link Label} + * objects. + */ + public List 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 Label dflt, + final Label[] labels) + { + super(Opcodes.TABLESWITCH); + this.min = min; + this.max = max; + this.dflt = dflt; + this.labels = new ArrayList(); + if (labels != null) { + this.labels.addAll(Arrays.asList(labels)); + } + } + + public void accept(final MethodVisitor mv) { + Label[] labels = new Label[this.labels.size()]; + this.labels.toArray(labels); + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + + public int getType() { + return TABLESWITCH_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TryCatchBlockNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TryCatchBlockNode.java new file mode 100644 index 000000000..56b146574 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TryCatchBlockNode.java @@ -0,0 +1,93 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +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 Label start; + + /** + * End of the exception handler's scope (exclusive). + */ + public Label end; + + /** + * Beginning of the exception handler's code. + */ + public Label 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; + + /** + * 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 Label start, + final Label end, + final Label handler, + final String type) + { + this.start = start; + this.end = end; + this.handler = handler; + this.type = type; + } + + /** + * Makes the given visitor visit this try catch block. + * + * @param mv a method visitor. + */ + public void accept(final MethodVisitor mv) { + mv.visitTryCatchBlock(start, end, handler, type); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TypeInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TypeInsnNode.java new file mode 100644 index 000000000..9f830b4dd --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/TypeInsnNode.java @@ -0,0 +1,78 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 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 a type descriptor (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 a type descriptor (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; + } + + public void accept(final MethodVisitor mv) { + mv.visitTypeInsn(opcode, desc); + } + + public int getType() { + return TYPE_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/VarInsnNode.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/VarInsnNode.java new file mode 100644 index 000000000..92e28ded0 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/VarInsnNode.java @@ -0,0 +1,81 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 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; + } + + public void accept(final MethodVisitor mv) { + mv.visitVarInsn(opcode, var); + } + + public int getType() { + return VAR_INSN; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Analyzer.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Analyzer.java new file mode 100644 index 000000000..cfd48149c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Analyzer.java @@ -0,0 +1,416 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.IincInsnNode; +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. + * + * @author Eric Bruneton + */ +public class Analyzer implements Opcodes { + + private Interpreter interpreter; + + private int n; + + private IntMap indexes; + + private List[] handlers; + + private Frame[] frames; + + private Subroutine[] subroutines; + + private boolean[] queued; + + private int[] queue; + + private int top; + + private boolean jsr; + + /** + * Constructs a new {@link Analyzer}. + * + * @param interpreter the interpreter to be used to symbolically interpret + * the bytecode instructions. + */ + public Analyzer(final Interpreter 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. + */ + public Frame[] analyze(final String owner, final MethodNode m) + throws AnalyzerException + { + n = m.instructions.size(); + indexes = new IntMap(2 * n); + handlers = new List[n]; + frames = new Frame[n]; + subroutines = new Subroutine[n]; + queued = new boolean[n]; + queue = new int[n]; + top = 0; + + // computes instruction indexes + for (int i = 0; i < n; ++i) { + Object insn = m.instructions.get(i); + if (insn instanceof LabelNode) { + insn = ((LabelNode) insn).label; + } + indexes.put(insn, i); + } + + // computes exception handlers for each instruction + for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { + TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); + int begin = indexes.get(tcb.start); + int end = indexes.get(tcb.end); + for (int j = begin; j < end; ++j) { + List insnHandlers = handlers[j]; + if (insnHandlers == null) { + insnHandlers = new ArrayList(); + handlers[j] = insnHandlers; + } + insnHandlers.add(tcb); + } + } + + // initializes the data structures for the control flow analysis + // algorithm + Frame current = newFrame(m.maxLocals, m.maxStack); + Frame handler = newFrame(m.maxLocals, m.maxStack); + Type[] args = Type.getArgumentTypes(m.desc); + int local = 0; + if ((m.access & ACC_STATIC) == 0) { + Type ctype = Type.getType("L" + 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); + + // control flow analysis + while (top > 0) { + int insn = queue[--top]; + Frame f = frames[insn]; + Subroutine subroutine = subroutines[insn]; + queued[insn] = false; + + try { + Object o = m.instructions.get(insn); + jsr = false; + + if (o instanceof LabelNode) { + merge(insn + 1, f, subroutine); + } else { + AbstractInsnNode insnNode = (AbstractInsnNode) o; + int insnOpcode = insnNode.getOpcode(); + + 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); + } + if (insnOpcode == JSR) { + jsr = true; + merge(indexes.get(j.label), + current, + new Subroutine(j.label, m.maxLocals, j)); + } else { + merge(indexes.get(j.label), current, subroutine); + } + } else if (insnNode instanceof LookupSwitchInsnNode) { + LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; + merge(indexes.get(lsi.dflt), current, subroutine); + for (int j = 0; j < lsi.labels.size(); ++j) { + Label label = (Label) lsi.labels.get(j); + merge(indexes.get(label), current, subroutine); + } + } else if (insnNode instanceof TableSwitchInsnNode) { + TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; + merge(indexes.get(tsi.dflt), current, subroutine); + for (int j = 0; j < tsi.labels.size(); ++j) { + Label label = (Label) tsi.labels.get(j); + merge(indexes.get(label), current, subroutine); + } + } else if (insnOpcode == RET) { + if (subroutine == null) { + throw new AnalyzerException("RET instruction outside of a sub routine"); + } + for (int i = 0; i < subroutine.callers.size(); ++i) { + int caller = indexes.get(subroutine.callers.get(i)); + merge(caller + 1, + frames[caller], + current, + subroutines[caller], + subroutine.access); + } + } 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); + } + } + + List insnHandlers = handlers[insn]; + if (insnHandlers != null) { + for (int i = 0; i < insnHandlers.size(); ++i) { + TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); + Type type; + if (tcb.type == null) { + type = Type.getType("Ljava/lang/Throwable;"); + } else { + type = Type.getType("L" + tcb.type + ";"); + } + handler.init(f); + handler.clearStack(); + handler.push(interpreter.newValue(type)); + merge(indexes.get(tcb.handler), handler, subroutine); + } + } + } catch (AnalyzerException e) { + throw new AnalyzerException("Error at instruction " + insn + + ": " + e.getMessage(), e); + } catch(Exception e) { + throw new AnalyzerException("Error at instruction " + insn + + ": " + e.getMessage(), e); + } + } + + return frames; + } + + /** + * 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[] getFrames() { + return frames; + } + + /** + * Returns the index of the given instruction. + * + * @param insn a {@link Label} or {@link AbstractInsnNode} of the last + * recently analyzed method. + * @return the index of the given instruction of the last recently analyzed + * method. + */ + public int getIndex(final Object insn) { + return indexes.get(insn); + } + + /** + * 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 getHandlers(final int insn) { + return handlers[insn]; + } + + /** + * 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 newFrame(final int nLocals, final int nStack) { + return new Frame(nLocals, nStack); + } + + /** + * Constructs a new frame that is identical to the given frame. + * + * @param src a frame. + * @return the created frame. + */ + protected Frame newFrame(final Frame src) { + return new Frame(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 frame the frame corresponding to an instruction. + * @param successor the frame corresponding to a successor instruction. + */ + protected void newControlFlowEdge(final Frame frame, final Frame successor) + { + } + + // ------------------------------------------------------------------------- + + private void merge( + final int insn, + final Frame frame, + final Subroutine subroutine) throws AnalyzerException + { + if (insn > n - 1) { + throw new AnalyzerException("Execution can fall off end of the code"); + } + + Frame oldFrame = frames[insn]; + Subroutine oldSubroutine = subroutines[insn]; + boolean changes = false; + + if (oldFrame == null) { + frames[insn] = newFrame(frame); + changes = true; + } else { + changes |= oldFrame.merge(frame, interpreter); + } + + newControlFlowEdge(frame, oldFrame); + + if (oldSubroutine == null) { + if (subroutine != null) { + subroutines[insn] = subroutine.copy(); + changes = true; + } + } else { + if (subroutine != null) { + changes |= oldSubroutine.merge(subroutine, !jsr); + } + } + if (changes && !queued[insn]) { + queued[insn] = true; + queue[top++] = insn; + } + } + + private void merge( + final int insn, + final Frame beforeJSR, + final Frame afterRET, + final Subroutine subroutineBeforeJSR, + final boolean[] access) throws AnalyzerException + { + if (insn > n - 1) { + throw new AnalyzerException("Execution can fall off end of the code"); + } + + Frame oldFrame = frames[insn]; + Subroutine oldSubroutine = subroutines[insn]; + boolean changes = false; + + afterRET.merge(beforeJSR, access); + + if (oldFrame == null) { + frames[insn] = newFrame(afterRET); + changes = true; + } else { + changes |= oldFrame.merge(afterRET, access); + } + + newControlFlowEdge(afterRET, oldFrame); + + if (oldSubroutine == null) { + if (subroutineBeforeJSR != null) { + subroutines[insn] = subroutineBeforeJSR.copy(); + changes = true; + } + } else { + if (subroutineBeforeJSR != null) { + changes |= oldSubroutine.merge(subroutineBeforeJSR, !jsr); + } + } + if (changes && !queued[insn]) { + queued[insn] = true; + queue[top++] = insn; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/AnalyzerException.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/AnalyzerException.java new file mode 100644 index 000000000..c024fbade --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/AnalyzerException.java @@ -0,0 +1,56 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * Thrown if a problem occurs during the analysis of a method. + * + * @author Bing Ran + * @author Eric Bruneton + */ +public class AnalyzerException extends Exception { + + public AnalyzerException(final String msg) { + super(msg); + } + + public AnalyzerException(final String msg, final Throwable exception) { + super(msg, exception); + } + + public AnalyzerException( + final String msg, + final Object expected, + final Value encountered) + { + super((msg == null ? "Expected " : msg + ": expected ") + expected + + ", but found " + encountered); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicInterpreter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicInterpreter.java new file mode 100644 index 000000000..5e0c70277 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicInterpreter.java @@ -0,0 +1,335 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.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.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 implements Opcodes, Interpreter { + + public Value 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 RuntimeException("Internal error."); + } + } + + public Value newOperation(final AbstractInsnNode insn) { + switch (insn.getOpcode()) { + case ACONST_NULL: + return newValue(Type.getType("Lnull;")); + 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 Type) { + return newValue(Type.getType("Ljava/lang/Class;")); + } else { + return newValue(Type.getType(cst.getClass())); + } + case JSR: + return BasicValue.RETURNADDRESS_VALUE; + case GETSTATIC: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEW: + return newValue(Type.getType("L" + ((TypeInsnNode) insn).desc + + ";")); + default: + throw new RuntimeException("Internal error."); + } + } + + public Value copyOperation(final AbstractInsnNode insn, final Value value) + throws AnalyzerException + { + return value; + } + + public Value unaryOperation(final AbstractInsnNode insn, final Value 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("Invalid array type"); + } + case ANEWARRAY: + String desc = ((TypeInsnNode) insn).desc; + if (desc.charAt(0) == '[') { + return newValue(Type.getType("[" + desc)); + } else { + return newValue(Type.getType("[L" + desc + ";")); + } + case ARRAYLENGTH: + return BasicValue.INT_VALUE; + case ATHROW: + return null; + case CHECKCAST: + desc = ((TypeInsnNode) insn).desc; + if (desc.charAt(0) == '[') { + return newValue(Type.getType(desc)); + } else { + return newValue(Type.getType("L" + desc + ";")); + } + case INSTANCEOF: + return BasicValue.INT_VALUE; + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + return null; + default: + throw new RuntimeException("Internal error."); + } + } + + public Value binaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value 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: + Type t = ((BasicValue) value1).getType(); + if (t != null && t.getSort() == Type.ARRAY) { + return newValue(t.getElementType()); + } else { + 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 RuntimeException("Internal error."); + } + } + + public Value ternaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value value2, + final Value value3) throws AnalyzerException + { + return null; + } + + public Value naryOperation(final AbstractInsnNode insn, final List values) + throws AnalyzerException + { + if (insn.getOpcode() == MULTIANEWARRAY) { + return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); + } else { + return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); + } + } + + public Value merge(final Value v, final Value w) { + if (!v.equals(w)) { + return BasicValue.UNINITIALIZED_VALUE; + } + return v; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicValue.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicValue.java new file mode 100644 index 000000000..46b8cf49a --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicValue.java @@ -0,0 +1,105 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 sytem. + * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, + * REFERENCE and RETURNADDRESS types. + * + * @author Eric Bruneton + */ +public class BasicValue implements Value { + + public final static Value UNINITIALIZED_VALUE = new BasicValue(null); + + public final static Value INT_VALUE = new BasicValue(Type.INT_TYPE); + + public final static Value FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE); + + public final static Value LONG_VALUE = new BasicValue(Type.LONG_TYPE); + + public final static Value DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE); + + public final static Value REFERENCE_VALUE = new BasicValue(Type.getType("Ljava/lang/Object;")); + + public final static Value RETURNADDRESS_VALUE = new BasicValue(null); + + private 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); + } + + 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; + } + } + + public int hashCode() { + return type == null ? 0 : type.hashCode(); + } + + 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(); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicVerifier.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicVerifier.java new file mode 100644 index 000000000..f65b56d8e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/BasicVerifier.java @@ -0,0 +1,428 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.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 Value copyOperation(final AbstractInsnNode insn, final Value 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 (!((BasicValue) value).isReference()) { + throw new AnalyzerException(null, + "an object reference", + value); + } + return value; + case ASTORE: + if (!((BasicValue) value).isReference() + && value != BasicValue.RETURNADDRESS_VALUE) + { + throw new AnalyzerException(null, + "an object reference or a return address", + value); + } + return value; + default: + return value; + } + // type is necessarily a primitive type here, + // so value must be == to expected value + if (value != expected) { + throw new AnalyzerException(null, expected, value); + } + return value; + } + + public Value unaryOperation(final AbstractInsnNode insn, Value value) + throws AnalyzerException + { + Value 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.getType("L" + + ((FieldInsnNode) insn).owner + ";")); + break; + case CHECKCAST: + if (!((BasicValue) value).isReference()) { + throw new AnalyzerException(null, + "an object reference", + value); + } + return super.unaryOperation(insn, value); + case ARRAYLENGTH: + if (!isArrayValue(value)) { + throw new AnalyzerException(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 (!((BasicValue) value).isReference()) { + throw new AnalyzerException(null, + "an object reference", + value); + } + return super.unaryOperation(insn, value); + case PUTSTATIC: + expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); + break; + default: + throw new RuntimeException("Internal error."); + } + if (!isSubTypeOf(value, expected)) { + throw new AnalyzerException(null, expected, value); + } + return super.unaryOperation(insn, value); + } + + public Value binaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value value2) throws AnalyzerException + { + Value expected1; + Value 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("[B")); + } else { + expected1 = newValue(Type.getType("[Z")); + } + 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.getType("L" + fin.owner + ";")); + expected2 = newValue(Type.getType(fin.desc)); + break; + default: + throw new RuntimeException("Internal error."); + } + if (!isSubTypeOf(value1, expected1)) { + throw new AnalyzerException("First argument", expected1, value1); + } else if (!isSubTypeOf(value2, expected2)) { + throw new AnalyzerException("Second argument", expected2, value2); + } + if (insn.getOpcode() == AALOAD) { + return getElementValue(value1); + } else { + return super.binaryOperation(insn, value1, value2); + } + } + + public Value ternaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value value2, + final Value value3) throws AnalyzerException + { + Value expected1; + Value 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("[B")); + } else { + expected1 = newValue(Type.getType("[Z")); + } + 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 RuntimeException("Internal error."); + } + if (!isSubTypeOf(value1, expected1)) { + throw new AnalyzerException("First argument", "a " + expected1 + + " array reference", value1); + } else if (value2 != BasicValue.INT_VALUE) { + throw new AnalyzerException("Second argument", + BasicValue.INT_VALUE, + value2); + } else if (!isSubTypeOf(value3, expected3)) { + throw new AnalyzerException("Third argument", expected3, value3); + } + return null; + } + + public Value naryOperation(final AbstractInsnNode insn, final List values) + throws AnalyzerException + { + int opcode = insn.getOpcode(); + if (opcode == MULTIANEWARRAY) { + for (int i = 0; i < values.size(); ++i) { + if (values.get(i) != BasicValue.INT_VALUE) { + throw new AnalyzerException(null, + BasicValue.INT_VALUE, + (Value) values.get(i)); + } + } + } else { + int i = 0; + int j = 0; + if (opcode != INVOKESTATIC) { + String own = ((MethodInsnNode) insn).owner; + if (own.charAt(0) != '[') { // can happen with JDK1.5 clone() + own = "L" + own + ";"; + } + Type owner = Type.getType(own); + if (!isSubTypeOf((Value) values.get(i++), newValue(owner))) { + throw new AnalyzerException("Method owner", + newValue(owner), + (Value) values.get(0)); + } + } + Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc); + while (i < values.size()) { + Value expected = newValue(args[j++]); + Value encountered = (Value) values.get(i++); + if (!isSubTypeOf(encountered, expected)) { + throw new AnalyzerException("Argument " + j, + expected, + encountered); + } + } + } + return super.naryOperation(insn, values); + } + + protected boolean isArrayValue(final Value value) { + return ((BasicValue) value).isReference(); + } + + protected Value getElementValue(final Value objectArrayValue) + throws AnalyzerException + { + return BasicValue.REFERENCE_VALUE; + } + + protected boolean isSubTypeOf(final Value value, final Value expected) { + return value == expected; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowInterpreter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowInterpreter.java new file mode 100644 index 000000000..3847d4949 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowInterpreter.java @@ -0,0 +1,174 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; + +/** + * An {@link Interpreter} for {@link DataflowValue} values. + * + * @author Eric Bruneton + */ +public class DataflowInterpreter implements Opcodes, Interpreter { + + public Value newValue(final Type type) { + return new DataflowValue(type == null ? 1 : type.getSize()); + } + + public Value 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 DataflowValue(size, insn); + } + + public Value copyOperation(final AbstractInsnNode insn, final Value value) { + return new DataflowValue(value.getSize(), insn); + } + + public Value unaryOperation(final AbstractInsnNode insn, final Value 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 DataflowValue(size, insn); + } + + public Value binaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value 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 DataflowValue(size, insn); + } + + public Value ternaryOperation( + final AbstractInsnNode insn, + final Value value1, + final Value value2, + final Value value3) + { + return new DataflowValue(1, insn); + } + + public Value naryOperation(final AbstractInsnNode insn, final List values) { + int size; + if (insn.getOpcode() == MULTIANEWARRAY) { + size = 1; + } else { + size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize(); + } + return new DataflowValue(size, insn); + } + + public Value merge(final Value v, final Value w) { + DataflowValue dv = (DataflowValue) v; + DataflowValue dw = (DataflowValue) w; + if (dv.insns instanceof SmallSet && dw.insns instanceof SmallSet) { + Set s = ((SmallSet) dv.insns).union((SmallSet) dw.insns); + if (s == dv.insns && dv.size == dw.size) { + return v; + } else { + return new DataflowValue(Math.min(dv.size, dw.size), s); + } + } + if (dv.size != dw.size || !dv.insns.containsAll(dw.insns)) { + Set s = new HashSet(); + s.addAll(dv.insns); + s.addAll(dw.insns); + return new DataflowValue(Math.min(dv.size, dw.size), s); + } + return v; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowValue.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowValue.java new file mode 100644 index 000000000..7b7756f78 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/DataflowValue.java @@ -0,0 +1,92 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 DataflowValue 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 insns; + + public DataflowValue(final int size) { + this(size, SmallSet.EMPTY_SET); + } + + public DataflowValue(final int size, final AbstractInsnNode insn) { + this.size = size; + this.insns = new SmallSet(insn, null); + } + + public DataflowValue(final int size, final Set insns) { + this.size = size; + this.insns = insns; + } + + public int getSize() { + return size; + } + + public boolean equals(final Object value) { + DataflowValue v = (DataflowValue) value; + return size == v.size && insns.equals(v.insns); + } + + public int hashCode() { + return insns.hashCode(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Frame.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Frame.java new file mode 100644 index 000000000..1edf40c3d --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Frame.java @@ -0,0 +1,670 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.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. + * + * @author Eric Bruneton + */ +public class Frame { + + /** + * The local variables and operand stack of this frame. + */ + private Value[] 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. + */ + public Frame(final int nLocals, final int nStack) { + this.values = 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 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 init(final Frame src) { + System.arraycopy(src.values, 0, values, 0, values.length); + top = src.top; + return this; + } + + /** + * 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 Value 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 Value value) + throws IndexOutOfBoundsException + { + if (i >= locals) { + throw new IndexOutOfBoundsException("Trying to access an inexistant local variable"); + } + 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 Value getStack(final int i) throws IndexOutOfBoundsException { + if (i >= top) { + throw new IndexOutOfBoundsException("Trying to access an inexistant stack element"); + } + 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 Value 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 Value 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 interpreter) throws AnalyzerException + { + Value value1, value2, value3, value4; + List 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("Illegal use of POP"); + } + break; + case Opcodes.POP2: + if (pop().getSize() == 1) { + if (pop().getSize() != 1) { + throw new AnalyzerException("Illegal use of POP2"); + } + } + break; + case Opcodes.DUP: + value1 = pop(); + if (value1.getSize() != 1) { + throw new AnalyzerException("Illegal use of DUP"); + } + push(interpreter.copyOperation(insn, 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("Illegal use of DUP_X1"); + } + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, 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(interpreter.copyOperation(insn, value3)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } else { + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } + throw new AnalyzerException("Illegal use of DUP_X2"); + case Opcodes.DUP2: + value1 = pop(); + if (value1.getSize() == 1) { + value2 = pop(); + if (value2.getSize() == 1) { + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } else { + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value1)); + break; + } + throw new AnalyzerException("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(interpreter.copyOperation(insn, value3)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } + } else { + value2 = pop(); + if (value2.getSize() == 1) { + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } + throw new AnalyzerException("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(interpreter.copyOperation(insn, value4)); + push(interpreter.copyOperation(insn, value3)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } else { + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value3)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } + } else { + value2 = pop(); + if (value2.getSize() == 1) { + value3 = pop(); + if (value3.getSize() == 1) { + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value3)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } else { + push(interpreter.copyOperation(insn, value1)); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + } + } + throw new AnalyzerException("Illegal use of DUP2_X2"); + case Opcodes.SWAP: + value2 = pop(); + value1 = pop(); + if (value1.getSize() != 1 || value2.getSize() != 1) { + throw new AnalyzerException("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: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.RETURN: + 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(); + 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.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(); + 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"); + } + } + + /** + * 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 frame, final Interpreter interpreter) + throws AnalyzerException + { + if (top != frame.top) { + throw new AnalyzerException("Incompatible stack heights"); + } + boolean changes = false; + for (int i = 0; i < locals + top; ++i) { + Value v = interpreter.merge(values[i], frame.values[i]); + if (v != 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 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. + */ + public String toString() { + StringBuffer b = new StringBuffer(); + for (int i = 0; i < locals; ++i) { + b.append(values[i]).append(' '); + } + b.append(' '); + for (int i = 0; i < top; ++i) { + b.append(values[i + locals].toString()).append(' '); + } + return b.toString(); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/IntMap.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/IntMap.java new file mode 100644 index 000000000..cac091cb7 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/IntMap.java @@ -0,0 +1,73 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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; + +/** + * A fixed size map of integer values. + * + * @author Eric Bruneton + */ +class IntMap { + + private int size; + + private Object[] keys; + + private int[] values; + + public IntMap(final int size) { + this.size = size; + this.keys = new Object[size]; + this.values = new int[size]; + } + + public int get(final Object key) { + int n = size; + int h = (key.hashCode() & 0x7FFFFFFF) % n; + int i = h; + while (keys[i] != key) { + i = (i + 1) % n; + if (i == h) { + throw new RuntimeException("Cannot find index of " + key); + } + } + return values[i]; + } + + public void put(final Object key, final int value) { + int n = size; + int i = (key.hashCode() & 0x7FFFFFFF) % n; + while (keys[i] != null) { + i = (i + 1) % n; + } + keys[i] = key; + values[i] = value; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Interpreter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Interpreter.java new file mode 100644 index 000000000..f989f4baf --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Interpreter.java @@ -0,0 +1,178 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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. + * + * @author Eric Bruneton + */ +public interface Interpreter { + + /** + * 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. + */ + Value 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. + */ + Value 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. + */ + Value copyOperation(AbstractInsnNode insn, Value 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. + */ + Value unaryOperation(AbstractInsnNode insn, Value 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. + */ + Value binaryOperation(AbstractInsnNode insn, Value value1, Value 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. + */ + Value ternaryOperation( + AbstractInsnNode insn, + Value value1, + Value value2, + Value 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 + * + * @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. + */ + Value naryOperation(AbstractInsnNode insn, List values) + 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>. + */ + Value merge(Value v, Value w); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SimpleVerifier.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SimpleVerifier.java new file mode 100644 index 000000000..1329f77b8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SimpleVerifier.java @@ -0,0 +1,266 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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 currentClassInterfaces; + + /** + * If the class that is verified is an interface. + */ + private final boolean isInterface; + + /** + * 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 currentClassInterfaces, + final boolean isInterface) + { + this.currentClass = currentClass; + this.currentSuperClass = currentSuperClass; + this.currentClassInterfaces = currentClassInterfaces; + this.isInterface = isInterface; + } + + public Value newValue(final Type type) { + Value v = super.newValue(type); + if (v == BasicValue.REFERENCE_VALUE) { + v = new BasicValue(type); + } + return v; + } + + protected boolean isArrayValue(final Value value) { + Type t = ((BasicValue) value).getType(); + if (t != null) { + return t.getDescriptor().equals("Lnull;") + || t.getSort() == Type.ARRAY; + } + return false; + } + + protected Value getElementValue(final Value objectArrayValue) + throws AnalyzerException + { + Type arrayType = ((BasicValue) objectArrayValue).getType(); + if (arrayType != null) { + if (arrayType.getSort() == Type.ARRAY) { + return newValue(Type.getType(arrayType.getDescriptor() + .substring(1))); + } else if (arrayType.getDescriptor().equals("Lnull;")) { + return objectArrayValue; + } + } + throw new AnalyzerException("Not an array type"); + } + + protected boolean isSubTypeOf(final Value value, final Value expected) { + Type expectedType = ((BasicValue) expected).getType(); + Type type = ((BasicValue) value).getType(); + if (expectedType == null) { + return type == null; + } + switch (expectedType.getSort()) { + case Type.INT: + case Type.FLOAT: + case Type.LONG: + case Type.DOUBLE: + return type == expectedType; + case Type.ARRAY: + case Type.OBJECT: + if (expectedType.getDescriptor().equals("Lnull;")) { + return type.getSort() == Type.OBJECT + || type.getSort() == Type.ARRAY; + } + if (type.getDescriptor().equals("Lnull;")) { + return true; + } else if (type.getSort() == Type.OBJECT + || type.getSort() == Type.ARRAY) + { + return isAssignableFrom(expectedType, type); + } else { + return false; + } + default: + throw new RuntimeException("Internal error"); + } + } + + public Value merge(final Value v, final Value w) { + if (!v.equals(w)) { + Type t = ((BasicValue) v).getType(); + Type u = ((BasicValue) 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 (t.getDescriptor().equals("Lnull;")) { + return w; + } + if (u.getDescriptor().equals("Lnull;")) { + 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; + } + + private boolean isInterface(final Type t) { + if (currentClass != null && t.equals(currentClass)) { + return isInterface; + } + return getClass(t).isInterface(); + } + + private 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); + } + + private boolean isAssignableFrom(final Type t, final Type u) { + if (t.equals(u)) { + return true; + } + if (currentClass != null && t.equals(currentClass)) { + 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 = (Type) currentClassInterfaces.get(i); + if (isAssignableFrom(t, v)) { + return true; + } + } + } + return false; + } + return getClass(t).isAssignableFrom(getClass(u)); + } + + protected Class getClass(final Type t) { + try { + if (t.getSort() == Type.ARRAY) { + return Class.forName(t.getDescriptor().replace('/', '.')); + } + return Class.forName(t.getClassName()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e.toString()); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SmallSet.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SmallSet.java new file mode 100644 index 000000000..3049d5a78 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/SmallSet.java @@ -0,0 +1,126 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Set; + +/** + * A set of at most two elements. + * + * @author Eric Bruneton + */ +class SmallSet extends AbstractSet implements Iterator { + + // if e1 is null, e2 must be null; otherwise e2 must be different from e1 + + Object e1, e2; + + final static SmallSet EMPTY_SET = new SmallSet(null, null); + + SmallSet(Object e1, Object e2) { + this.e1 = e1; + this.e2 = e2; + } + + // ------------------------------------------------------------------------- + // Implementation of inherited abstract methods + // ------------------------------------------------------------------------- + + public Iterator iterator() { + return new SmallSet(e1, e2); + } + + public int size() { + return e1 == null ? 0 : (e2 == null ? 1 : 2); + } + + // ------------------------------------------------------------------------- + // Implementation of the Iterator interface + // ------------------------------------------------------------------------- + + public boolean hasNext() { + return e1 != null; + } + + public Object next() { + Object e = e1; + e1 = e2; + e2 = null; + return e; + } + + public void remove() { + } + + // ------------------------------------------------------------------------- + // Utility methods + // ------------------------------------------------------------------------- + + Set union(SmallSet 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(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 r = new HashSet(4); + r.add(e1); + if (e2 != null) { + r.add(e2); + } + r.add(s.e1); + if (s.e2 != null) { + r.add(s.e2); + } + return r; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Subroutine.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Subroutine.java new file mode 100644 index 000000000..5ae010905 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Subroutine.java @@ -0,0 +1,96 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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.Label; +import org.objectweb.asm.tree.JumpInsnNode; + +/** + * A method subroutine (corresponds to a JSR instruction). + * + * @author Eric Bruneton + */ +class Subroutine { + + Label start; + + boolean[] access; + + List callers; + + private Subroutine() { + } + + public Subroutine( + final Label start, + final int maxLocals, + final JumpInsnNode caller) + { + this.start = start; + this.access = new boolean[maxLocals]; + this.callers = new ArrayList(); + 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(callers); + return result; + } + + public boolean merge(final Subroutine subroutine, boolean checkOverlap) + throws AnalyzerException + { + if (checkOverlap && subroutine.start != start) { + throw new AnalyzerException("Overlapping sub routines"); + } + boolean changes = false; + for (int i = 0; i < access.length; ++i) { + if (subroutine.access[i] && !access[i]) { + access[i] = true; + changes = true; + } + } + for (int i = 0; i < subroutine.callers.size(); ++i) { + Object caller = subroutine.callers.get(i); + if (!callers.contains(caller)) { + callers.add(caller); + changes = true; + } + } + return changes; + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Value.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Value.java new file mode 100644 index 000000000..4baf1b4b3 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/tree/analysis/Value.java @@ -0,0 +1,45 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 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(); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAbstractVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAbstractVisitor.java new file mode 100644 index 000000000..940bc112c --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAbstractVisitor.java @@ -0,0 +1,226 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.util.HashMap; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.Type; +import org.objectweb.asm.util.attrs.ASMifiable; + +/** + * An abstract ASMifier visitor. + * + * @author Eric Bruneton + */ +public class ASMifierAbstractVisitor extends AbstractVisitor { + + /** + * The name of the variable for this visitor in the produced code. + */ + protected String name; + + /** + * The label names. This map associates String values to Label keys. It is + * used only in ASMifierMethodVisitor. + */ + HashMap labelNames; + + /** + * Constructs a new {@link ASMifierAbstractVisitor}. + * + * @param name the name of the variable for this visitor in the produced + * code. + */ + protected ASMifierAbstractVisitor(final String name) { + this.name = name; + } + + /** + * Prints the ASM code that generates the given annotation. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values. + */ + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append("{\n") + .append("av0 = ") + .append(name) + .append(".visitAnnotation("); + appendConstant(desc); + buf.append(", ").append(visible).append(");\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + /** + * Prints the ASM code that generates the given attribute. + * + * @param attr an attribute. + */ + public void visitAttribute(final Attribute attr) { + buf.setLength(0); + if (attr instanceof ASMifiable) { + buf.append("{\n"); + buf.append("// ATTRIBUTE\n"); + ((ASMifiable) attr).asmify(buf, "attr", labelNames); + buf.append(name).append(".visitAttribute(attr);\n"); + buf.append("}\n"); + } else { + buf.append("// WARNING! skipped a non standard attribute of type \""); + buf.append(attr.type).append("\"\n"); + } + text.add(buf.toString()); + } + + /** + * Prints the ASM code to end the visit. + */ + public void visitEnd() { + buf.setLength(0); + buf.append(name).append(".visitEnd();\n"); + text.add(buf.toString()); + } + + /** + * Appends a string representation of the given constant to the given + * buffer. + * + * @param cst an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. + */ + void appendConstant(final Object cst) { + appendConstant(buf, cst); + } + + /** + * Appends a string representation of the given constant to the given + * buffer. + * + * @param buf a string buffer. + * @param cst an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. + */ + static void appendConstant(final StringBuffer buf, final Object cst) { + if (cst == null) { + buf.append("null"); + } else if (cst instanceof String) { + appendString(buf, (String) cst); + } else if (cst instanceof Type) { + buf.append("Type.getType(\""); + buf.append(((Type) cst).getDescriptor()); + buf.append("\")"); + } else if (cst instanceof Byte) { + buf.append("new Byte((byte)").append(cst).append(")"); + } else if (cst instanceof Boolean) { + buf.append("new Boolean(").append(cst).append(")"); + } else if (cst instanceof Short) { + buf.append("new Short((short)").append(cst).append(")"); + } else if (cst instanceof Character) { + int c = ((Character) cst).charValue(); + buf.append("new Character((char)").append(c).append(")"); + } else if (cst instanceof Integer) { + buf.append("new Integer(").append(cst).append(")"); + } else if (cst instanceof Float) { + buf.append("new Float(\"").append(cst).append("\")"); + } else if (cst instanceof Long) { + buf.append("new Long(").append(cst).append("L)"); + } else if (cst instanceof Double) { + buf.append("new Double(\"").append(cst).append("\")"); + } else if (cst instanceof byte[]) { + byte[] v = (byte[]) cst; + buf.append("new byte[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append("}"); + } else if (cst instanceof boolean[]) { + boolean[] v = (boolean[]) cst; + buf.append("new boolean[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append("}"); + } else if (cst instanceof short[]) { + short[] v = (short[]) cst; + buf.append("new short[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]); + } + buf.append("}"); + } else if (cst instanceof char[]) { + char[] v = (char[]) cst; + buf.append("new char[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",") + .append("(char)") + .append((int) v[i]); + } + buf.append("}"); + } else if (cst instanceof int[]) { + int[] v = (int[]) cst; + buf.append("new int[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append("}"); + } else if (cst instanceof long[]) { + long[] v = (long[]) cst; + buf.append("new long[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append("L"); + } + buf.append("}"); + } else if (cst instanceof float[]) { + float[] v = (float[]) cst; + buf.append("new float[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append("f"); + } + buf.append("}"); + } else if (cst instanceof double[]) { + double[] v = (double[]) cst; + buf.append("new double[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append("d"); + } + buf.append("}"); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAnnotationVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAnnotationVisitor.java new file mode 100644 index 000000000..0f766b32e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierAnnotationVisitor.java @@ -0,0 +1,127 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; + +/** + * An {@link AnnotationVisitor} that prints the ASM code that generates the + * annotations it visits. + * + * @author Eric Bruneton + */ +public class ASMifierAnnotationVisitor extends AbstractVisitor implements + AnnotationVisitor +{ + + /** + * Identifier of the annotation visitor variable in the produced code. + */ + protected final int id; + + /** + * Constructs a new {@link ASMifierAnnotationVisitor}. + * + * @param id identifier of the annotation visitor variable in the produced + * code. + */ + public ASMifierAnnotationVisitor(final int id) { + this.id = id; + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor interface + // ------------------------------------------------------------------------ + + public void visit(final String name, final Object value) { + buf.setLength(0); + buf.append("av").append(id).append(".visit("); + ASMifierAbstractVisitor.appendConstant(buf, name); + buf.append(", "); + ASMifierAbstractVisitor.appendConstant(buf, value); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + buf.setLength(0); + buf.append("av").append(id).append(".visitEnum("); + ASMifierAbstractVisitor.appendConstant(buf, name); + buf.append(", "); + ASMifierAbstractVisitor.appendConstant(buf, desc); + buf.append(", "); + ASMifierAbstractVisitor.appendConstant(buf, value); + buf.append(");\n"); + text.add(buf.toString()); + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + buf.setLength(0); + buf.append("{\n"); + buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); + buf.append(id).append(".visitAnnotation("); + ASMifierAbstractVisitor.appendConstant(buf, name); + buf.append(", "); + ASMifierAbstractVisitor.appendConstant(buf, desc); + buf.append(");\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(id + 1); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + public AnnotationVisitor visitArray(final String name) { + buf.setLength(0); + buf.append("{\n"); + buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); + buf.append(id).append(".visitArray("); + ASMifierAbstractVisitor.appendConstant(buf, name); + buf.append(");\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(id + 1); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + public void visitEnd() { + buf.setLength(0); + buf.append("av").append(id).append(".visitEnd();\n"); + text.add(buf.toString()); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierClassVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierClassVisitor.java new file mode 100644 index 000000000..d7b73fb75 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierClassVisitor.java @@ -0,0 +1,607 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * A {@link ClassVisitor} that prints the ASM code that generates the classes it + * visits. This class visitor can be used to quickly write ASM code to generate + * some given bytecode: <ul> <li>write the Java source code equivalent to the + * bytecode you want to generate;</li> <li>compile it with <tt>javac</tt>;</li> + * <li>make a {@link ASMifierClassVisitor} visit this compiled class (see the + * {@link #main main} method);</li> <li>edit the generated source code, if + * necessary.</li> </ul> The source code printed when visiting the + * <tt>Hello</tt> class is the following: <p> <blockquote> + * + * <pre> + * import org.objectweb.asm.*; + * + * public class HelloDump implements Opcodes { + * + * public static byte[] dump() throws Exception { + * + * ClassWriter cw = new ClassWriter(false); + * FieldVisitor fv; + * MethodVisitor mv; + * AnnotationVisitor av0; + * + * cw.visit(49, + * ACC_PUBLIC + ACC_SUPER, + * "Hello", + * null, + * "java/lang/Object", + * null); + * + * cw.visitSource("Hello.java", null); + * + * { + * mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + * mv.visitVarInsn(ALOAD, 0); + * mv.visitMethodInsn(INVOKESPECIAL, + * "java/lang/Object", + * "<init>", + * "()V"); + * mv.visitInsn(RETURN); + * mv.visitMaxs(1, 1); + * mv.visitEnd(); + * } + * { + * mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, + * "main", + * "([Ljava/lang/String;)V", + * null, + * null); + * mv.visitFieldInsn(GETSTATIC, + * "java/lang/System", + * "out", + * "Ljava/io/PrintStream;"); + * mv.visitLdcInsn("hello"); + * mv.visitMethodInsn(INVOKEVIRTUAL, + * "java/io/PrintStream", + * "println", + * "(Ljava/lang/String;)V"); + * mv.visitInsn(RETURN); + * mv.visitMaxs(2, 1); + * mv.visitEnd(); + * } + * cw.visitEnd(); + * + * return cw.toByteArray(); + * } + * } + * + * </pre> + * + * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote> + * + * <pre> + * public class Hello { + * + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + * </pre> + * + * </blockquote> + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements + ClassVisitor +{ + + /** + * Pseudo access flag used to distinguish class access flags. + */ + private final static int ACCESS_CLASS = 262144; + + /** + * Pseudo access flag used to distinguish field access flags. + */ + private final static int ACCESS_FIELD = 524288; + + /** + * Pseudo access flag used to distinguish inner class flags. + */ + private static final int ACCESS_INNER = 1048576; + + /** + * The print writer to be used to print the class. + */ + protected final PrintWriter pw; + + /** + * Prints the ASM source code to generate the given class to the standard + * output. <p> Usage: ASMifierClassVisitor [-debug] <fully qualified + * class name or class file name> + * + * @param args the command line arguments. + * + * @throws Exception if the class cannot be found, or if an IO exception + * occurs. + */ + public static void main(final String[] args) throws Exception { + int i = 0; + boolean skipDebug = true; + + boolean ok = true; + if (args.length < 1 || args.length > 2) { + ok = false; + } + if (ok && args[0].equals("-debug")) { + i = 1; + skipDebug = false; + if (args.length != 2) { + ok = false; + } + } + if (!ok) { + System.err.println("Prints the ASM code to generate the given class."); + System.err.println("Usage: ASMifierClassVisitor [-debug] " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 + || args[i].indexOf('/') > -1) { + cr = new ClassReader(new FileInputStream(args[i])); + } else { + cr = new ClassReader(args[i]); + } + cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), + getDefaultAttributes(), + skipDebug); + } + + /** + * Constructs a new {@link ASMifierClassVisitor} object. + * + * @param pw the print writer to be used to print the class. + */ + public ASMifierClassVisitor(final PrintWriter pw) { + super("cw"); + this.pw = pw; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + String simpleName; + int n = name.lastIndexOf('/'); + if (n != -1) { + text.add("package asm." + name.substring(0, n).replace('/', '.') + + ";\n"); + simpleName = name.substring(n + 1); + } else { + simpleName = name; + } + text.add("import java.util.*;\n"); + text.add("import org.objectweb.asm.*;\n"); + text.add("import org.objectweb.asm.attrs.*;\n"); + text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); + text.add("public static byte[] dump () throws Exception {\n\n"); + text.add("ClassWriter cw = new ClassWriter(false);\n"); + text.add("FieldVisitor fv;\n"); + text.add("MethodVisitor mv;\n"); + text.add("AnnotationVisitor av0;\n\n"); + + buf.setLength(0); + buf.append("cw.visit("); + switch (version) { + case Opcodes.V1_1: + buf.append("V1_1"); + break; + case Opcodes.V1_2: + buf.append("V1_2"); + break; + case Opcodes.V1_3: + buf.append("V1_3"); + break; + case Opcodes.V1_4: + buf.append("V1_4"); + break; + case Opcodes.V1_5: + buf.append("V1_5"); + break; + case Opcodes.V1_6: + buf.append("V1_6"); + break; + default: + buf.append(version); + break; + } + buf.append(", "); + appendAccess(access | ACCESS_CLASS); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendConstant(superName); + buf.append(", "); + if (interfaces != null && interfaces.length > 0) { + buf.append("new String[] {"); + for (int i = 0; i < interfaces.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(interfaces[i]); + } + buf.append(" }"); + } else { + buf.append("null"); + } + buf.append(");\n\n"); + text.add(buf.toString()); + } + + public void visitSource(final String file, final String debug) { + buf.setLength(0); + buf.append("cw.visitSource("); + appendConstant(file); + buf.append(", "); + appendConstant(debug); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append("cw.visitOuterClass("); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + buf.setLength(0); + buf.append("cw.visitInnerClass("); + appendConstant(name); + buf.append(", "); + appendConstant(outerName); + buf.append(", "); + appendConstant(innerName); + buf.append(", "); + appendAccess(access | ACCESS_INNER); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + buf.setLength(0); + buf.append("{\n"); + buf.append("fv = cw.visitField("); + appendAccess(access | ACCESS_FIELD); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendConstant(value); + buf.append(");\n"); + text.add(buf.toString()); + ASMifierFieldVisitor aav = new ASMifierFieldVisitor(); + text.add(aav.getText()); + text.add("}\n"); + return aav; + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + buf.setLength(0); + buf.append("{\n"); + buf.append("mv = cw.visitMethod("); + appendAccess(access); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + if (exceptions != null && exceptions.length > 0) { + buf.append("new String[] {"); + for (int i = 0; i < exceptions.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(exceptions[i]); + } + buf.append(" }"); + } else { + buf.append("null"); + } + buf.append(");\n"); + text.add(buf.toString()); + ASMifierMethodVisitor acv = new ASMifierMethodVisitor(); + text.add(acv.getText()); + text.add("}\n"); + return acv; + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append("{\n"); + buf.append("av0 = cw.visitAnnotation("); + appendConstant(desc); + buf.append(", "); + buf.append(visible); + buf.append(");\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + public void visitEnd() { + text.add("cw.visitEnd();\n\n"); + text.add("return cw.toByteArray();\n"); + text.add("}\n"); + text.add("}\n"); + printList(pw, text); + pw.flush(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Appends a string representation of the given access modifiers to {@link + * #buf buf}. + * + * @param access some access modifiers. + */ + void appendAccess(final int access) { + boolean first = true; + if ((access & Opcodes.ACC_PUBLIC) != 0) { + buf.append("ACC_PUBLIC"); + first = false; + } + if ((access & Opcodes.ACC_PRIVATE) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_PRIVATE"); + first = false; + } + if ((access & Opcodes.ACC_PROTECTED) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_PROTECTED"); + first = false; + } + if ((access & Opcodes.ACC_FINAL) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_FINAL"); + first = false; + } + if ((access & Opcodes.ACC_STATIC) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_STATIC"); + first = false; + } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + if (!first) { + buf.append(" + "); + } + if ((access & ACCESS_CLASS) != 0) { + buf.append("ACC_SUPER"); + } else { + buf.append("ACC_SYNCHRONIZED"); + } + first = false; + } + if ((access & Opcodes.ACC_VOLATILE) != 0 + && (access & ACCESS_FIELD) != 0) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_VOLATILE"); + first = false; + } + if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_BRIDGE"); + first = false; + } + if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_VARARGS"); + first = false; + } + if ((access & Opcodes.ACC_TRANSIENT) != 0 + && (access & ACCESS_FIELD) != 0) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_TRANSIENT"); + first = false; + } + if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_NATIVE"); + first = false; + } + if ((access & Opcodes.ACC_ENUM) != 0 + && ((access & ACCESS_CLASS) != 0 + || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ENUM"); + first = false; + } + if ((access & Opcodes.ACC_ANNOTATION) != 0 + && ((access & ACCESS_CLASS) != 0)) + { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ANNOTATION"); + first = false; + } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ABSTRACT"); + first = false; + } + if ((access & Opcodes.ACC_INTERFACE) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_INTERFACE"); + first = false; + } + if ((access & Opcodes.ACC_STRICT) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_STRICT"); + first = false; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_SYNTHETIC"); + first = false; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_DEPRECATED"); + first = false; + } + if (first) { + buf.append("0"); + } + } + + /** + * Appends a string representation of the given constant to the given + * buffer. + * + * @param buf a string buffer. + * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float + * Float}, {@link java.lang.Long Long}, + * {@link java.lang.Double Double} or {@link String String} object. + * May be <tt>null</tt>. + */ + static void appendConstant(final StringBuffer buf, final Object cst) { + if (cst == null) { + buf.append("null"); + } else if (cst instanceof String) { + AbstractVisitor.appendString(buf, (String) cst); + } else if (cst instanceof Type) { + buf.append("Type.getType(\"") + .append(((Type) cst).getDescriptor()) + .append("\")"); + } else if (cst instanceof Integer) { + buf.append("new Integer(").append(cst).append(")"); + } else if (cst instanceof Float) { + buf.append("new Float(\"").append(cst).append("\")"); + } else if (cst instanceof Long) { + buf.append("new Long(").append(cst).append("L)"); + } else if (cst instanceof Double) { + buf.append("new Double(\"").append(cst).append("\")"); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierFieldVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierFieldVisitor.java new file mode 100644 index 000000000..673217909 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierFieldVisitor.java @@ -0,0 +1,50 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.FieldVisitor; + +/** + * A {@link FieldVisitor} that prints the ASM code that generates the fields it + * visits. + * + * @author Eric Bruneton + */ +public class ASMifierFieldVisitor extends ASMifierAbstractVisitor implements + FieldVisitor +{ + + /** + * Constructs a new {@link ASMifierFieldVisitor}. + */ + public ASMifierFieldVisitor() { + super("fv"); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierMethodVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierMethodVisitor.java new file mode 100644 index 000000000..57c55ee21 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/ASMifierMethodVisitor.java @@ -0,0 +1,347 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.HashMap; + +/** + * A {@link MethodVisitor} that prints the ASM code that generates the methods + * it visits. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ASMifierMethodVisitor extends ASMifierAbstractVisitor implements + MethodVisitor +{ + + /** + * Constructs a new {@link ASMifierMethodVisitor} object. + */ + public ASMifierMethodVisitor() { + super("mv"); + this.labelNames = new HashMap(); + } + + public AnnotationVisitor visitAnnotationDefault() { + buf.setLength(0); + buf.append("{\n").append("av0 = mv.visitAnnotationDefault();\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append("{\n") + .append("av0 = mv.visitParameterAnnotation(") + .append(parameter) + .append(", "); + appendConstant(desc); + buf.append(", ").append(visible).append(");\n"); + text.add(buf.toString()); + ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); + text.add(av.getText()); + text.add("}\n"); + return av; + } + + public void visitCode() { + text.add("mv.visitCode();\n"); + } + + public void visitInsn(final int opcode) { + buf.setLength(0); + buf.append("mv.visitInsn(").append(OPCODES[opcode]).append(");\n"); + text.add(buf.toString()); + } + + public void visitIntInsn(final int opcode, final int operand) { + buf.setLength(0); + buf.append("mv.visitIntInsn(") + .append(OPCODES[opcode]) + .append(", ") + .append(opcode == Opcodes.NEWARRAY + ? TYPES[operand] + : Integer.toString(operand)) + .append(");\n"); + text.add(buf.toString()); + } + + public void visitVarInsn(final int opcode, final int var) { + buf.setLength(0); + buf.append("mv.visitVarInsn(") + .append(OPCODES[opcode]) + .append(", ") + .append(var) + .append(");\n"); + text.add(buf.toString()); + } + + public void visitTypeInsn(final int opcode, final String desc) { + buf.setLength(0); + buf.append("mv.visitTypeInsn(").append(OPCODES[opcode]).append(", "); + appendConstant(desc); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append("mv.visitFieldInsn(").append(OPCODES[opcode]).append(", "); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append("mv.visitMethodInsn(").append(OPCODES[opcode]).append(", "); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitJumpInsn(final int opcode, final Label label) { + buf.setLength(0); + declareLabel(label); + buf.append("mv.visitJumpInsn(").append(OPCODES[opcode]).append(", "); + appendLabel(label); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitLabel(final Label label) { + buf.setLength(0); + declareLabel(label); + buf.append("mv.visitLabel("); + appendLabel(label); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitLdcInsn(final Object cst) { + buf.setLength(0); + buf.append("mv.visitLdcInsn("); + appendConstant(cst); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitIincInsn(final int var, final int increment) { + buf.setLength(0); + buf.append("mv.visitIincInsn(") + .append(var) + .append(", ") + .append(increment) + .append(");\n"); + text.add(buf.toString()); + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label labels[]) + { + buf.setLength(0); + for (int i = 0; i < labels.length; ++i) { + declareLabel(labels[i]); + } + declareLabel(dflt); + + buf.append("mv.visitTableSwitchInsn(") + .append(min) + .append(", ") + .append(max) + .append(", "); + appendLabel(dflt); + buf.append(", new Label[] {"); + for (int i = 0; i < labels.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendLabel(labels[i]); + } + buf.append(" });\n"); + text.add(buf.toString()); + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int keys[], + final Label labels[]) + { + buf.setLength(0); + for (int i = 0; i < labels.length; ++i) { + declareLabel(labels[i]); + } + declareLabel(dflt); + + buf.append("mv.visitLookupSwitchInsn("); + appendLabel(dflt); + buf.append(", new int[] {"); + for (int i = 0; i < keys.length; ++i) { + buf.append(i == 0 ? " " : ", ").append(keys[i]); + } + buf.append(" }, new Label[] {"); + for (int i = 0; i < labels.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendLabel(labels[i]); + } + buf.append(" });\n"); + text.add(buf.toString()); + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + buf.setLength(0); + buf.append("mv.visitMultiANewArrayInsn("); + appendConstant(desc); + buf.append(", ").append(dims).append(");\n"); + text.add(buf.toString()); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + buf.setLength(0); + declareLabel(start); + declareLabel(end); + declareLabel(handler); + buf.append("mv.visitTryCatchBlock("); + appendLabel(start); + buf.append(", "); + appendLabel(end); + buf.append(", "); + appendLabel(handler); + buf.append(", "); + appendConstant(type); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + buf.setLength(0); + buf.append("mv.visitLocalVariable("); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendLabel(start); + buf.append(", "); + appendLabel(end); + buf.append(", ").append(index).append(");\n"); + text.add(buf.toString()); + } + + public void visitLineNumber(final int line, final Label start) { + buf.setLength(0); + buf.append("mv.visitLineNumber(").append(line).append(", "); + appendLabel(start); + buf.append(");\n"); + text.add(buf.toString()); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + buf.setLength(0); + buf.append("mv.visitMaxs(") + .append(maxStack) + .append(", ") + .append(maxLocals) + .append(");\n"); + text.add(buf.toString()); + } + + /** + * Appends a declaration of the given label to {@link #buf buf}. This + * declaration is of the form "Label lXXX = new Label();". Does nothing if + * the given label has already been declared. + * + * @param l a label. + */ + private void declareLabel(final Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "l" + labelNames.size(); + labelNames.put(l, name); + buf.append("Label ").append(name).append(" = new Label();\n"); + } + } + + /** + * Appends the name of the given label to {@link #buf buf}. The given label + * <i>must</i> already have a name. One way to ensure this is to always + * call {@link #declareLabel declared} before calling this method. + * + * @param l a label. + */ + private void appendLabel(final Label l) { + buf.append((String) labelNames.get(l)); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/AbstractVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/AbstractVisitor.java new file mode 100644 index 000000000..557d5c82f --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/AbstractVisitor.java @@ -0,0 +1,201 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.util.attrs.ASMStackMapAttribute; +import org.objectweb.asm.util.attrs.ASMStackMapTableAttribute; + +/** + * An abstract visitor. + * + * @author Eric Bruneton + */ +public abstract class AbstractVisitor { + + /** + * The names of the Java Virtual Machine opcodes. + */ + public final static String[] OPCODES; + /** + * Types for <code>operand</code> parameter of the + * {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when + * <code>opcode</code> is <code>NEWARRAY</code>. + */ + public final static String[] TYPES; + + static { + String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2," + + "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0," + + "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,," + + "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD," + + "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE," + + "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE," + + "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP," + + "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD," + + "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV," + + "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL," + + "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L," + + "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP," + + "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE," + + "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE," + + "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH," + + "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC," + + "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL," + + "INVOKESTATIC,INVOKEINTERFACE,,NEW,NEWARRAY,ANEWARRAY," + + "ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF,MONITORENTER," + + "MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,"; + OPCODES = new String[200]; + int i = 0; + int j = 0; + int l; + while ((l = s.indexOf(',', j)) > 0) { + OPCODES[i++] = j + 1 == l ? null : s.substring(j, l); + j = l + 1; + } + + s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,"; + TYPES = new String[12]; + j = 0; + i = 4; + while ((l = s.indexOf(',', j)) > 0) { + TYPES[i++] = s.substring(j, l); + j = l + 1; + } + } + + /** + * The text to be printed. Since the code of methods is not necessarily + * visited in sequential order, one method after the other, but can be + * interlaced (some instructions from method one, then some instructions + * from method two, then some instructions from method one again...), it is + * not possible to print the visited instructions directly to a sequential + * stream. A class is therefore printed in a two steps process: a string + * tree is constructed during the visit, and printed to a sequential stream + * at the end of the visit. This string tree is stored in this field, as a + * string list that can contain other string lists, which can themselves + * contain other string lists, and so on. + */ + public final List text; + + /** + * A buffer that can be used to create strings. + */ + protected final StringBuffer buf; + + /** + * Constructs a new {@link AbstractVisitor}. + */ + protected AbstractVisitor() { + this.text = new ArrayList(); + this.buf = new StringBuffer(); + } + + /** + * Returns the text printed by this visitor. + * + * @return the text printed by this visitor. + */ + public List getText() { + return text; + } + + /** + * Appends a quoted string to a given buffer. + * + * @param buf the buffer where the string must be added. + * @param s the string to be added. + */ + public static void appendString(final StringBuffer buf, final String s) { + buf.append("\""); + for (int i = 0; i < s.length(); ++i) { + char c = s.charAt(i); + if (c == '\n') { + buf.append("\\n"); + } else if (c == '\r') { + buf.append("\\r"); + } else if (c == '\\') { + buf.append("\\\\"); + } else if (c == '"') { + buf.append("\\\""); + } else if (c < 0x20 || c > 0x7f) { + buf.append("\\u"); + if (c < 0x10) { + buf.append("000"); + } else if (c < 0x100) { + buf.append("00"); + } else if (c < 0x1000) { + buf.append("0"); + } + buf.append(Integer.toString(c, 16)); + } else { + buf.append(c); + } + } + buf.append("\""); + } + + /** + * Prints the given string tree. + * + * @param pw the writer to be used to print the tree. + * @param l a string tree, i.e., a string list that can contain other string + * lists, and so on recursively. + */ + void printList(final PrintWriter pw, final List l) { + for (int i = 0; i < l.size(); ++i) { + Object o = l.get(i); + if (o instanceof List) { + printList(pw, (List) o); + } else { + pw.print(o.toString()); + } + } + } + + /** + * Returns the default {@link ASMifiable} prototypes. + * + * @return the default {@link ASMifiable} prototypes. + */ + public static Attribute[] getDefaultAttributes() { + try { + return new Attribute[] { + new ASMStackMapAttribute(), + new ASMStackMapTableAttribute() }; + } catch (Exception e) { + return new Attribute[0]; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckAnnotationAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckAnnotationAdapter.java new file mode 100644 index 000000000..228ff04ca --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckAnnotationAdapter.java @@ -0,0 +1,125 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +/** + * An {@link AnnotationVisitor} that checks that its methods are properly used. + * + * @author Eric Bruneton + */ +public class CheckAnnotationAdapter implements AnnotationVisitor { + + private AnnotationVisitor av; + + private boolean named; + + private boolean end; + + public CheckAnnotationAdapter(final AnnotationVisitor av) { + this(av, true); + } + + CheckAnnotationAdapter( + final AnnotationVisitor av, + final boolean named) + { + this.av = av; + this.named = named; + } + + public void visit(final String name, final Object value) { + checkEnd(); + checkName(name); + if (!(value instanceof Byte || value instanceof Boolean + || value instanceof Character || value instanceof Short + || value instanceof Integer || value instanceof Long + || value instanceof Float || value instanceof Double + || value instanceof String || value instanceof Type + || value instanceof byte[] || value instanceof boolean[] + || value instanceof char[] || value instanceof short[] + || value instanceof int[] || value instanceof long[] + || value instanceof float[] || value instanceof double[])) + { + throw new IllegalArgumentException("Invalid annotation value"); + } + av.visit(name, value); + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + checkEnd(); + checkName(name); + CheckMethodAdapter.checkDesc(desc, false); + if (value == null) { + throw new IllegalArgumentException("Invalid enum value"); + } + av.visitEnum(name, desc, value); + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + checkEnd(); + checkName(name); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(av.visitAnnotation(name, desc)); + } + + public AnnotationVisitor visitArray(final String name) { + checkEnd(); + checkName(name); + return new CheckAnnotationAdapter(av.visitArray(name), false); + } + + public void visitEnd() { + checkEnd(); + end = true; + av.visitEnd(); + } + + private void checkEnd() { + if (end) { + throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); + } + } + + private void checkName(final String name) { + if (named && name == null) { + throw new IllegalArgumentException("Annotation value name must not be null"); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckClassAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckClassAdapter.java new file mode 100644 index 000000000..1ca97ad6e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckClassAdapter.java @@ -0,0 +1,416 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; +import java.util.List; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.TryCatchBlockNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.SimpleVerifier; +import org.objectweb.asm.tree.analysis.Frame; + +/** + * A {@link ClassAdapter} that checks that its methods are properly used. More + * precisely this class adapter checks each method call individually, based + * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i> + * of method calls. For example, the invalid sequence + * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, + * "i", "D", null)</tt> + * will <i>not</i> be detected by this class adapter. + * + * @author Eric Bruneton + */ +public class CheckClassAdapter extends ClassAdapter { + + /** + * <tt>true</tt> if the visit method has been called. + */ + private boolean start; + + /** + * <tt>true</tt> if the visitSource method has been called. + */ + private boolean source; + + /** + * <tt>true</tt> if the visitOuterClass method has been called. + */ + private boolean outer; + + /** + * <tt>true</tt> if the visitEnd method has been called. + */ + private boolean end; + + /** + * Checks a given class. <p> Usage: CheckClassAdapter <fully qualified + * class name or class file name> + * + * @param args the command line arguments. + * + * @throws Exception if the class cannot be found, or if an IO exception + * occurs. + */ + public static void main(final String[] args) throws Exception { + if (args.length != 1) { + System.err.println("Verifies the given class."); + System.err.println("Usage: CheckClassAdapter " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[0].endsWith(".class")) { + cr = new ClassReader(new FileInputStream(args[0])); + } else { + cr = new ClassReader(args[0]); + } + + verify(cr, false, new PrintWriter(System.err)); + } + + /** + * Checks a given class + * + * @param cr a <code>ClassReader</code> that contains bytecode for the analysis. + * @param dump true if bytecode should be printed out not only when errors are found. + * @param pw write where results going to be printed + */ + public static void verify(ClassReader cr, boolean dump, PrintWriter pw) { + ClassNode cn = new ClassNode(); + cr.accept(new CheckClassAdapter(cn), true); + + 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 SimpleVerifier(Type.getType("L" + + cn.name + ";"), + Type.getType("L" + cn.superName + ";"), + (cn.access & Opcodes.ACC_INTERFACE) != 0)); + try { + a.analyze(cn.name, method); + if (!dump) { + continue; + } + } catch (Exception e) { + e.printStackTrace(); + } + Frame[] frames = a.getFrames(); + + TraceMethodVisitor mv = new TraceMethodVisitor(); + + pw.println(method.name + method.desc); + for (int j = 0; j < method.instructions.size(); ++j) { + ((AbstractInsnNode) method.instructions.get(j)).accept(mv); + + StringBuffer s = new StringBuffer(); + Frame f = frames[j]; + if (f == null) { + s.append('?'); + } else { + for (int k = 0; k < f.getLocals(); ++k) { + s.append(getShortName(f.getLocal(k).toString())) + .append(' '); + } + s.append(" : "); + for (int k = 0; k < f.getStackSize(); ++k) { + s.append(getShortName(f.getStack(k).toString())) + .append(' '); + } + } + while (s.length() < method.maxStack + method.maxLocals + 1) + { + s.append(' '); + } + pw.print(Integer.toString(j + 100000).substring(1)); + pw.print(" " + s + " : " + mv.buf); // mv.text.get(j)); + } + for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { + ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); + pw.print(" " + mv.buf); + } + pw.println(); + } + } + } + + private static String getShortName(String name) { + int n = name.lastIndexOf('/'); + int k = name.length(); + if(name.charAt(k-1)==';') k--; + return n==-1 ? name : name.substring(n+1, k); + } + + /** + * Constructs a new {@link CheckClassAdapter}. + * + * @param cv the class visitor to which this adapter must delegate calls. + */ + public CheckClassAdapter(final ClassVisitor cv) { + super(cv); + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + if (start) { + throw new IllegalStateException("visit must be called only once"); + } else { + start = true; + } + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM + + Opcodes.ACC_DEPRECATED); + CheckMethodAdapter.checkInternalName(name, "class name"); + if ("java/lang/Object".equals(name)) { + if (superName != null) { + throw new IllegalArgumentException("The super class name of the Object class must be 'null'"); + } + } else { + CheckMethodAdapter.checkInternalName(superName, "super class name"); + } + if (signature != null) { + // TODO + } + if ((access & Opcodes.ACC_INTERFACE) != 0) { + if (!"java/lang/Object".equals(superName)) { + throw new IllegalArgumentException("The super class name of interfaces must be 'java/lang/Object'"); + } + } + if (interfaces != null) { + for (int i = 0; i < interfaces.length; ++i) { + CheckMethodAdapter.checkInternalName(interfaces[i], + "interface name at index " + i); + } + } + cv.visit(version, access, name, signature, superName, interfaces); + } + + public void visitSource(final String file, final String debug) { + checkState(); + if (source) { + throw new IllegalStateException("visitSource can be called only once."); + } + source = true; + cv.visitSource(file, debug); + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + checkState(); + if (outer) { + throw new IllegalStateException("visitSource can be called only once."); + } + outer = true; + if (owner == null) { + throw new IllegalArgumentException("Illegal outer class owner"); + } + if (desc != null) { + CheckMethodAdapter.checkMethodDesc(desc); + } + cv.visitOuterClass(owner, name, desc); + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + checkState(); + CheckMethodAdapter.checkInternalName(name, "class name"); + if (outerName != null) { + CheckMethodAdapter.checkInternalName(outerName, "outer class name"); + } + if (innerName != null) { + CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); + } + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); + cv.visitInnerClass(name, outerName, innerName, access); + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE + + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED); + CheckMethodAdapter.checkIdentifier(name, "field name"); + CheckMethodAdapter.checkDesc(desc, false); + if (signature != null) { + // TODO + } + if (value != null) { + CheckMethodAdapter.checkConstant(value); + } + FieldVisitor av = cv.visitField(access, name, desc, signature, value); + return new CheckFieldAdapter(av); + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED + + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT + + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED); + CheckMethodAdapter.checkMethodIdentifier(name, "method name"); + CheckMethodAdapter.checkMethodDesc(desc); + if (signature != null) { + // TODO + } + if (exceptions != null) { + for (int i = 0; i < exceptions.length; ++i) { + CheckMethodAdapter.checkInternalName(exceptions[i], + "exception name at index " + i); + } + } + return new CheckMethodAdapter(cv.visitMethod(access, + name, + desc, + signature, + exceptions)); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + checkState(); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(cv.visitAnnotation(desc, visible)); + } + + public void visitAttribute(final Attribute attr) { + checkState(); + if (attr == null) { + throw new IllegalArgumentException("Invalid attribute (must not be null)"); + } + cv.visitAttribute(attr); + } + + public void visitEnd() { + checkState(); + end = true; + cv.visitEnd(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Checks that the visit method has been called and that visitEnd has not + * been called. + */ + private void checkState() { + if (!start) { + throw new IllegalStateException("Cannot visit member before visit has been called."); + } + if (end) { + throw new IllegalStateException("Cannot visit member after visitEnd has been called."); + } + } + + /** + * Checks that the given access flags do not contain invalid flags. This + * method also checks that mutually incompatible flags are not set + * simultaneously. + * + * @param access the access flags to be checked + * @param possibleAccess the valid access flags. + */ + static void checkAccess(final int access, final int possibleAccess) { + if ((access & ~possibleAccess) != 0) { + throw new IllegalArgumentException("Invalid access flags: " + + access); + } + int pub = ((access & Opcodes.ACC_PUBLIC) != 0 ? 1 : 0); + int pri = ((access & Opcodes.ACC_PRIVATE) != 0 ? 1 : 0); + int pro = ((access & Opcodes.ACC_PROTECTED) != 0 ? 1 : 0); + if (pub + pri + pro > 1) { + throw new IllegalArgumentException("public private and protected are mutually exclusive: " + + access); + } + int fin = ((access & Opcodes.ACC_FINAL) != 0 ? 1 : 0); + int abs = ((access & Opcodes.ACC_ABSTRACT) != 0 ? 1 : 0); + if (fin + abs > 1) { + throw new IllegalArgumentException("final and abstract are mutually exclusive: " + + access); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckFieldAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckFieldAdapter.java new file mode 100644 index 000000000..3e7c113b8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckFieldAdapter.java @@ -0,0 +1,75 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; + +/** + * A {@link FieldVisitor} that checks that its methods are properly used. + */ +public class CheckFieldAdapter implements FieldVisitor { + + private FieldVisitor fv; + + private boolean end; + + public CheckFieldAdapter(final FieldVisitor fv) { + this.fv = fv; + } + + public AnnotationVisitor visitAnnotation(final String desc, boolean visible) + { + checkEnd(); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(fv.visitAnnotation(desc, visible)); + } + + public void visitAttribute(final Attribute attr) { + checkEnd(); + if (attr == null) { + throw new IllegalArgumentException("Invalid attribute (must not be null)"); + } + fv.visitAttribute(attr); + } + + public void visitEnd() { + checkEnd(); + end = true; + fv.visitEnd(); + } + + private void checkEnd() { + if (end) { + throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckMethodAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckMethodAdapter.java new file mode 100644 index 000000000..0123eeeb8 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/CheckMethodAdapter.java @@ -0,0 +1,942 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.Type; + +import java.util.HashMap; + +/** + * A {@link MethodAdapter} that checks that its methods are properly used. More + * precisely this code adapter checks each instruction individually (i.e., each + * visit method checks some preconditions based <i>only</i> on its arguments - + * such as the fact that the given opcode is correct for a given visit method), + * but does <i>not</i> check the <i>sequence</i> of instructions. For example, + * in a method whose signature is <tt>void m ()</tt>, the invalid instruction + * IRETURN, or the invalid sequence IADD L2I will <i>not</i> be detected by + * this code adapter. + * + * @author Eric Bruneton + */ +public class CheckMethodAdapter extends MethodAdapter { + + /** + * <tt>true</tt> if the visitCode method has been called. + */ + private boolean startCode; + + /** + * <tt>true</tt> if the visitMaxs method has been called. + */ + private boolean endCode; + + /** + * <tt>true</tt> if the visitEnd method has been called. + */ + private boolean endMethod; + + /** + * The already visited labels. This map associate Integer values to Label + * keys. + */ + private HashMap labels; + + /** + * Code of the visit method to be used for each opcode. + */ + private final static int[] TYPE; + + static { + String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD" + + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD" + + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA"; + TYPE = new int[s.length()]; + for (int i = 0; i < TYPE.length; ++i) { + TYPE[i] = (s.charAt(i) - 'A' - 1); + } + } + + // code to generate the above string + // public static void main (String[] args) { + // int[] TYPE = new int[] { + // 0, //NOP + // 0, //ACONST_NULL + // 0, //ICONST_M1 + // 0, //ICONST_0 + // 0, //ICONST_1 + // 0, //ICONST_2 + // 0, //ICONST_3 + // 0, //ICONST_4 + // 0, //ICONST_5 + // 0, //LCONST_0 + // 0, //LCONST_1 + // 0, //FCONST_0 + // 0, //FCONST_1 + // 0, //FCONST_2 + // 0, //DCONST_0 + // 0, //DCONST_1 + // 1, //BIPUSH + // 1, //SIPUSH + // 7, //LDC + // -1, //LDC_W + // -1, //LDC2_W + // 2, //ILOAD + // 2, //LLOAD + // 2, //FLOAD + // 2, //DLOAD + // 2, //ALOAD + // -1, //ILOAD_0 + // -1, //ILOAD_1 + // -1, //ILOAD_2 + // -1, //ILOAD_3 + // -1, //LLOAD_0 + // -1, //LLOAD_1 + // -1, //LLOAD_2 + // -1, //LLOAD_3 + // -1, //FLOAD_0 + // -1, //FLOAD_1 + // -1, //FLOAD_2 + // -1, //FLOAD_3 + // -1, //DLOAD_0 + // -1, //DLOAD_1 + // -1, //DLOAD_2 + // -1, //DLOAD_3 + // -1, //ALOAD_0 + // -1, //ALOAD_1 + // -1, //ALOAD_2 + // -1, //ALOAD_3 + // 0, //IALOAD + // 0, //LALOAD + // 0, //FALOAD + // 0, //DALOAD + // 0, //AALOAD + // 0, //BALOAD + // 0, //CALOAD + // 0, //SALOAD + // 2, //ISTORE + // 2, //LSTORE + // 2, //FSTORE + // 2, //DSTORE + // 2, //ASTORE + // -1, //ISTORE_0 + // -1, //ISTORE_1 + // -1, //ISTORE_2 + // -1, //ISTORE_3 + // -1, //LSTORE_0 + // -1, //LSTORE_1 + // -1, //LSTORE_2 + // -1, //LSTORE_3 + // -1, //FSTORE_0 + // -1, //FSTORE_1 + // -1, //FSTORE_2 + // -1, //FSTORE_3 + // -1, //DSTORE_0 + // -1, //DSTORE_1 + // -1, //DSTORE_2 + // -1, //DSTORE_3 + // -1, //ASTORE_0 + // -1, //ASTORE_1 + // -1, //ASTORE_2 + // -1, //ASTORE_3 + // 0, //IASTORE + // 0, //LASTORE + // 0, //FASTORE + // 0, //DASTORE + // 0, //AASTORE + // 0, //BASTORE + // 0, //CASTORE + // 0, //SASTORE + // 0, //POP + // 0, //POP2 + // 0, //DUP + // 0, //DUP_X1 + // 0, //DUP_X2 + // 0, //DUP2 + // 0, //DUP2_X1 + // 0, //DUP2_X2 + // 0, //SWAP + // 0, //IADD + // 0, //LADD + // 0, //FADD + // 0, //DADD + // 0, //ISUB + // 0, //LSUB + // 0, //FSUB + // 0, //DSUB + // 0, //IMUL + // 0, //LMUL + // 0, //FMUL + // 0, //DMUL + // 0, //IDIV + // 0, //LDIV + // 0, //FDIV + // 0, //DDIV + // 0, //IREM + // 0, //LREM + // 0, //FREM + // 0, //DREM + // 0, //INEG + // 0, //LNEG + // 0, //FNEG + // 0, //DNEG + // 0, //ISHL + // 0, //LSHL + // 0, //ISHR + // 0, //LSHR + // 0, //IUSHR + // 0, //LUSHR + // 0, //IAND + // 0, //LAND + // 0, //IOR + // 0, //LOR + // 0, //IXOR + // 0, //LXOR + // 8, //IINC + // 0, //I2L + // 0, //I2F + // 0, //I2D + // 0, //L2I + // 0, //L2F + // 0, //L2D + // 0, //F2I + // 0, //F2L + // 0, //F2D + // 0, //D2I + // 0, //D2L + // 0, //D2F + // 0, //I2B + // 0, //I2C + // 0, //I2S + // 0, //LCMP + // 0, //FCMPL + // 0, //FCMPG + // 0, //DCMPL + // 0, //DCMPG + // 6, //IFEQ + // 6, //IFNE + // 6, //IFLT + // 6, //IFGE + // 6, //IFGT + // 6, //IFLE + // 6, //IF_ICMPEQ + // 6, //IF_ICMPNE + // 6, //IF_ICMPLT + // 6, //IF_ICMPGE + // 6, //IF_ICMPGT + // 6, //IF_ICMPLE + // 6, //IF_ACMPEQ + // 6, //IF_ACMPNE + // 6, //GOTO + // 6, //JSR + // 2, //RET + // 9, //TABLESWITCH + // 10, //LOOKUPSWITCH + // 0, //IRETURN + // 0, //LRETURN + // 0, //FRETURN + // 0, //DRETURN + // 0, //ARETURN + // 0, //RETURN + // 4, //GETSTATIC + // 4, //PUTSTATIC + // 4, //GETFIELD + // 4, //PUTFIELD + // 5, //INVOKEVIRTUAL + // 5, //INVOKESPECIAL + // 5, //INVOKESTATIC + // 5, //INVOKEINTERFACE + // -1, //UNUSED + // 3, //NEW + // 1, //NEWARRAY + // 3, //ANEWARRAY + // 0, //ARRAYLENGTH + // 0, //ATHROW + // 3, //CHECKCAST + // 3, //INSTANCEOF + // 0, //MONITORENTER + // 0, //MONITOREXIT + // -1, //WIDE + // 11, //MULTIANEWARRAY + // 6, //IFNULL + // 6, //IFNONNULL + // -1, //GOTO_W + // -1 //JSR_W + // }; + // for (int i = 0; i < TYPE.length; ++i) { + // System.out.print((char)(TYPE[i] + 1 + 'A')); + // } + // System.out.println(); + // } + + /** + * Constructs a new {@link CheckMethodAdapter} object. + * + * @param cv the code visitor to which this adapter must delegate calls. + */ + public CheckMethodAdapter(final MethodVisitor cv) { + super(cv); + this.labels = new HashMap(); + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + checkEndMethod(); + checkDesc(desc, false); + return new CheckAnnotationAdapter(mv.visitAnnotation(desc, visible)); + } + + public AnnotationVisitor visitAnnotationDefault() { + checkEndMethod(); + return new CheckAnnotationAdapter(mv.visitAnnotationDefault(), false); + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + checkEndMethod(); + checkDesc(desc, false); + return new CheckAnnotationAdapter(mv.visitParameterAnnotation(parameter, + desc, + visible)); + } + + public void visitAttribute(final Attribute attr) { + checkEndMethod(); + if (attr == null) { + throw new IllegalArgumentException("Invalid attribute (must not be null)"); + } + mv.visitAttribute(attr); + } + + public void visitCode() { + startCode = true; + mv.visitCode(); + } + + public void visitInsn(final int opcode) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 0); + mv.visitInsn(opcode); + } + + public void visitIntInsn(final int opcode, final int operand) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 1); + switch (opcode) { + case Opcodes.BIPUSH: + checkSignedByte(operand, "Invalid operand"); + break; + case Opcodes.SIPUSH: + checkSignedShort(operand, "Invalid operand"); + break; + // case Constants.NEWARRAY: + default: + if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { + throw new IllegalArgumentException("Invalid operand (must be an array type code T_...): " + + operand); + } + } + mv.visitIntInsn(opcode, operand); + } + + public void visitVarInsn(final int opcode, final int var) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 2); + checkUnsignedShort(var, "Invalid variable index"); + mv.visitVarInsn(opcode, var); + } + + public void visitTypeInsn(final int opcode, final String desc) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 3); + if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') { + checkDesc(desc, false); + } else { + checkInternalName(desc, "type"); + } + if (opcode == Opcodes.NEW && desc.charAt(0) == '[') { + throw new IllegalArgumentException("NEW cannot be used to create arrays: " + + desc); + } + mv.visitTypeInsn(opcode, desc); + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 4); + checkInternalName(owner, "owner"); + checkIdentifier(name, "name"); + checkDesc(desc, false); + mv.visitFieldInsn(opcode, owner, name, desc); + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 5); + checkMethodIdentifier(name, "name"); + if (!name.equals("clone")) { + // In JDK1.5, clone method can be called on array class descriptors + checkInternalName(owner, "owner"); + } + checkMethodDesc(desc); + mv.visitMethodInsn(opcode, owner, name, desc); + } + + public void visitJumpInsn(final int opcode, final Label label) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 6); + checkLabel(label, false, "label"); + mv.visitJumpInsn(opcode, label); + } + + public void visitLabel(final Label label) { + checkStartCode(); + checkEndCode(); + checkLabel(label, false, "label"); + if (labels.get(label) != null) { + throw new IllegalArgumentException("Already visited label"); + } else { + labels.put(label, new Integer(labels.size())); + } + mv.visitLabel(label); + } + + public void visitLdcInsn(final Object cst) { + checkStartCode(); + checkEndCode(); + if (!(cst instanceof Type)) { + checkConstant(cst); + } + mv.visitLdcInsn(cst); + } + + public void visitIincInsn(final int var, final int increment) { + checkStartCode(); + checkEndCode(); + checkUnsignedShort(var, "Invalid variable index"); + checkSignedShort(increment, "Invalid increment"); + mv.visitIincInsn(var, increment); + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label labels[]) + { + checkStartCode(); + checkEndCode(); + if (max < min) { + throw new IllegalArgumentException("Max = " + max + + " must be greater than or equal to min = " + min); + } + checkLabel(dflt, false, "default label"); + if (labels == null || labels.length != max - min + 1) { + throw new IllegalArgumentException("There must be max - min + 1 labels"); + } + for (int i = 0; i < labels.length; ++i) { + checkLabel(labels[i], false, "label at index " + i); + } + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int keys[], + final Label labels[]) + { + checkEndCode(); + checkStartCode(); + checkLabel(dflt, false, "default label"); + if (keys == null || labels == null || keys.length != labels.length) { + throw new IllegalArgumentException("There must be the same number of keys and labels"); + } + for (int i = 0; i < labels.length; ++i) { + checkLabel(labels[i], false, "label at index " + i); + } + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + checkStartCode(); + checkEndCode(); + checkDesc(desc, false); + if (desc.charAt(0) != '[') { + throw new IllegalArgumentException("Invalid descriptor (must be an array type descriptor): " + + desc); + } + if (dims < 1) { + throw new IllegalArgumentException("Invalid dimensions (must be greater than 0): " + + dims); + } + if (dims > desc.lastIndexOf('[') + 1) { + throw new IllegalArgumentException("Invalid dimensions (must not be greater than dims(desc)): " + + dims); + } + mv.visitMultiANewArrayInsn(desc, dims); + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + checkStartCode(); + checkEndCode(); + if (type != null) { + checkInternalName(type, "type"); + } + mv.visitTryCatchBlock(start, end, handler, type); + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + checkStartCode(); + checkEndCode(); + checkIdentifier(name, "name"); + checkDesc(desc, false); + checkLabel(start, true, "start label"); + checkLabel(end, true, "end label"); + checkUnsignedShort(index, "Invalid variable index"); + int s = ((Integer) labels.get(start)).intValue(); + int e = ((Integer) labels.get(end)).intValue(); + if (e < s) { + throw new IllegalArgumentException("Invalid start and end labels (end must be greater than start)"); + } + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + + public void visitLineNumber(final int line, final Label start) { + checkStartCode(); + checkEndCode(); + checkUnsignedShort(line, "Invalid line number"); + checkLabel(start, true, "start label"); + mv.visitLineNumber(line, start); + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + checkStartCode(); + checkEndCode(); + endCode = true; + checkUnsignedShort(maxStack, "Invalid max stack"); + checkUnsignedShort(maxLocals, "Invalid max locals"); + mv.visitMaxs(maxStack, maxLocals); + } + + public void visitEnd() { + checkEndMethod(); + endMethod = true; + mv.visitEnd(); + } + + // ------------------------------------------------------------------------- + + /** + * Checks that the visitCode method has been called. + */ + void checkStartCode() { + if (!startCode) { + throw new IllegalStateException("Cannot visit instructions before visitCode has been called."); + } + } + + /** + * Checks that the visitMaxs method has not been called. + */ + void checkEndCode() { + if (endCode) { + throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called."); + } + } + + /** + * Checks that the visitEnd method has not been called. + */ + void checkEndMethod() { + if (endMethod) { + throw new IllegalStateException("Cannot visit elements after visitEnd has been called."); + } + } + + /** + * Checks that the type of the given opcode is equal to the given type. + * + * @param opcode the opcode to be checked. + * @param type the expected opcode type. + */ + static void checkOpcode(final int opcode, final int type) { + if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { + throw new IllegalArgumentException("Invalid opcode: " + opcode); + } + } + + /** + * Checks that the given value is a signed byte. + * + * @param value the value to be checked. + * @param msg an message to be used in case of error. + */ + static void checkSignedByte(final int value, final String msg) { + if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { + throw new IllegalArgumentException(msg + + " (must be a signed byte): " + value); + } + } + + /** + * Checks that the given value is a signed short. + * + * @param value the value to be checked. + * @param msg an message to be used in case of error. + */ + static void checkSignedShort(final int value, final String msg) { + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + throw new IllegalArgumentException(msg + + " (must be a signed short): " + value); + } + } + + /** + * Checks that the given value is an unsigned short. + * + * @param value the value to be checked. + * @param msg an message to be used in case of error. + */ + static void checkUnsignedShort(final int value, final String msg) { + if (value < 0 || value > 65535) { + throw new IllegalArgumentException(msg + + " (must be an unsigned short): " + value); + } + } + + /** + * Checks that the given value is an {@link Integer}, a{@link Float}, a + * {@link Long}, a {@link Double} or a {@link String}. + * + * @param cst the value to be checked. + */ + static void checkConstant(final Object cst) { + if (!(cst instanceof Integer) && !(cst instanceof Float) + && !(cst instanceof Long) && !(cst instanceof Double) + && !(cst instanceof String)) + { + throw new IllegalArgumentException("Invalid constant: " + cst); + } + } + + /** + * Checks that the given string is a valid Java identifier. + * + * @param name the string to be checked. + * @param msg a message to be used in case of error. + */ + static void checkIdentifier(final String name, final String msg) { + checkIdentifier(name, 0, -1, msg); + } + + /** + * Checks that the given substring is a valid Java identifier. + * + * @param name the string to be checked. + * @param start index of the first character of the identifier (inclusive). + * @param end index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg a message to be used in case of error. + */ + static void checkIdentifier( + final String name, + final int start, + final int end, + final String msg) + { + if (name == null || (end == -1 ? name.length() <= start : end <= start)) + { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + if (!Character.isJavaIdentifierStart(name.charAt(start))) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid Java identifier): " + name); + } + int max = (end == -1 ? name.length() : end); + for (int i = start + 1; i < max; ++i) { + if (!Character.isJavaIdentifierPart(name.charAt(i))) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid Java identifier): " + name); + } + } + } + + /** + * Checks that the given string is a valid Java identifier or is equal to + * '<init>' or '<clinit>'. + * + * @param name the string to be checked. + * @param msg a message to be used in case of error. + */ + static void checkMethodIdentifier(final String name, final String msg) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + if (name.equals("<init>") || name.equals("<clinit>")) { + return; + } + if (!Character.isJavaIdentifierStart(name.charAt(0))) { + throw new IllegalArgumentException("Invalid " + + msg + + " (must be a '<init>', '<clinit>' or a valid Java identifier): " + + name); + } + for (int i = 1; i < name.length(); ++i) { + if (!Character.isJavaIdentifierPart(name.charAt(i))) { + throw new IllegalArgumentException("Invalid " + + msg + + " (must be '<init>' or '<clinit>' or a valid Java identifier): " + + name); + } + } + } + + /** + * Checks that the given string is a valid internal class name. + * + * @param name the string to be checked. + * @param msg a message to be used in case of error. + */ + static void checkInternalName(final String name, final String msg) { + checkInternalName(name, 0, -1, msg); + } + + /** + * Checks that the given substring is a valid internal class name. + * + * @param name the string to be checked. + * @param start index of the first character of the identifier (inclusive). + * @param end index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg a message to be used in case of error. + */ + static void checkInternalName( + final String name, + final int start, + final int end, + final String msg) + { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + int max = (end == -1 ? name.length() : end); + try { + int begin = start; + int slash; + do { + slash = name.indexOf('/', begin + 1); + if (slash == -1 || slash > max) { + slash = max; + } + checkIdentifier(name, begin, slash, null); + begin = slash + 1; + } while (slash != max); + } catch (IllegalArgumentException _) { + throw new IllegalArgumentException("Invalid " + + msg + + " (must be a fully qualified class name in internal form): " + + name); + } + } + + /** + * Checks that the given string is a valid type descriptor. + * + * @param desc the string to be checked. + * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. + */ + static void checkDesc(final String desc, final boolean canBeVoid) { + int end = checkDesc(desc, 0, canBeVoid); + if (end != desc.length()) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + } + + /** + * Checks that a the given substring is a valid type descriptor. + * + * @param desc the string to be checked. + * @param start index of the first character of the identifier (inclusive). + * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. + * @return the index of the last character of the type decriptor, plus one. + */ + static int checkDesc( + final String desc, + final int start, + final boolean canBeVoid) + { + if (desc == null || start >= desc.length()) { + throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)"); + } + int index; + switch (desc.charAt(start)) { + case 'V': + if (canBeVoid) { + return start + 1; + } else { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + return start + 1; + case '[': + index = start + 1; + while (index < desc.length() && desc.charAt(index) == '[') { + ++index; + } + if (index < desc.length()) { + return checkDesc(desc, index, false); + } else { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + case 'L': + index = desc.indexOf(';', start); + if (index == -1 || index - start < 2) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + try { + checkInternalName(desc, start + 1, index, null); + } catch (IllegalArgumentException _) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + return index + 1; + default: + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + } + + /** + * Checks that the given string is a valid method descriptor. + * + * @param desc the string to be checked. + */ + static void checkMethodDesc(final String desc) { + if (desc == null || desc.length() == 0) { + throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)"); + } + if (desc.charAt(0) != '(' || desc.length() < 3) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + int start = 1; + if (desc.charAt(start) != ')') { + do { + if (desc.charAt(start) == 'V') { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + start = checkDesc(desc, start, false); + } while (start < desc.length() && desc.charAt(start) != ')'); + } + start = checkDesc(desc, start + 1, true); + if (start != desc.length()) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + } + + /** + * Checks that the given label is not null. This method can also check that + * the label has been visited. + * + * @param label the label to be checked. + * @param checkVisited <tt>true</tt> to check that the label has been + * visited. + * @param msg a message to be used in case of error. + */ + void checkLabel( + final Label label, + final boolean checkVisited, + final String msg) + { + if (label == null) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null)"); + } + if (checkVisited && labels.get(label) == null) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be visited first)"); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAbstractVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAbstractVisitor.java new file mode 100644 index 000000000..8a3d4d022 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAbstractVisitor.java @@ -0,0 +1,180 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.util.attrs.Traceable; + +/** + * An abstract trace visitor. + * + * @author Eric Bruneton + */ +public abstract class TraceAbstractVisitor extends AbstractVisitor { + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for internal + * type names in bytecode notation. + */ + public final static int INTERNAL_NAME = 0; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for field + * descriptors, formatted in bytecode notation + */ + public final static int FIELD_DESCRIPTOR = 1; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for field + * signatures, formatted in bytecode notation + */ + public final static int FIELD_SIGNATURE = 2; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for method + * descriptors, formatted in bytecode notation + */ + public final static int METHOD_DESCRIPTOR = 3; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for method + * signatures, formatted in bytecode notation + */ + public final static int METHOD_SIGNATURE = 4; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for class + * signatures, formatted in bytecode notation + */ + public final static int CLASS_SIGNATURE = 5; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for field or + * method return value signatures, formatted in default Java notation + * (non-bytecode) + */ + public final static int TYPE_DECLARATION = 6; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for class + * signatures, formatted in default Java notation (non-bytecode) + */ + public final static int CLASS_DECLARATION = 7; + + /** + * Constant used in {@link #appendDescriptor appendDescriptor} for method + * parameter signatures, formatted in default Java notation (non-bytecode) + */ + public final static int PARAMETERS_DECLARATION = 8; + + /** + * Tab for class members. + */ + protected String tab = " "; + + /** + * Prints a disassembled view of the given annotation. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values. + */ + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append(tab).append('@'); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('('); + text.add(buf.toString()); + TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); + text.add(tav.getText()); + text.add(visible ? ")\n" : ") // invisible\n"); + return tav; + } + + /** + * Prints a disassembled view of the given attribute. + * + * @param attr an attribute. + */ + public void visitAttribute(final Attribute attr) { + buf.setLength(0); + buf.append(tab).append("ATTRIBUTE "); + appendDescriptor(-1, attr.type); + + if (attr instanceof Traceable) { + ((Traceable) attr).trace(buf, null); + } else { + buf.append(" : ").append(attr.toString()).append("\n"); + } + + text.add(buf.toString()); + } + + /** + * Does nothing. + */ + public void visitEnd() { + // does nothing + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected TraceAnnotationVisitor createTraceAnnotationVisitor() { + return new TraceAnnotationVisitor(); + } + + /** + * Appends an internal name, a type descriptor or a type signature to + * {@link #buf buf}. + * + * @param type indicates if desc is an internal name, a field descriptor, a + * method descriptor, a class signature, ... + * @param desc an internal name, type descriptor, or type signature. May be + * <tt>null</tt>. + */ + protected void appendDescriptor(final int type, final String desc) { + if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE + || type == METHOD_SIGNATURE) + { + if (desc != null) { + buf.append("// signature ").append(desc).append('\n'); + } + } else { + buf.append(desc); + } + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAnnotationVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAnnotationVisitor.java new file mode 100644 index 000000000..ae812d896 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceAnnotationVisitor.java @@ -0,0 +1,272 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +/** + * An {@link AnnotationVisitor} that prints a disassembled view of the + * annotations it visits. + * + * @author Eric Bruneton + */ +public class TraceAnnotationVisitor extends TraceAbstractVisitor implements + AnnotationVisitor +{ + + /** + * The {@link AnnotationVisitor} to which this visitor delegates calls. May + * be <tt>null</tt>. + */ + protected AnnotationVisitor av; + + private int valueNumber = 0; + + /** + * Constructs a new {@link TraceAnnotationVisitor}. + */ + public TraceAnnotationVisitor() { + // ignore + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor interface + // ------------------------------------------------------------------------ + + public void visit(final String name, final Object value) { + buf.setLength(0); + appendComa(valueNumber++); + + if (name != null) { + buf.append(name).append('='); + } + + if (value instanceof String) { + visitString((String) value); + } else if (value instanceof Type) { + visitType((Type) value); + } else if (value instanceof Byte) { + visitByte(((Byte) value).byteValue()); + } else if (value instanceof Boolean) { + visitBoolean(((Boolean) value).booleanValue()); + } else if (value instanceof Short) { + visitShort(((Short) value).shortValue()); + } else if (value instanceof Character) { + visitChar(((Character) value).charValue()); + } else if (value instanceof Integer) { + visitInt(((Integer) value).intValue()); + } else if (value instanceof Float) { + visitFloat(((Float) value).floatValue()); + } else if (value instanceof Long) { + visitLong(((Long) value).longValue()); + } else if (value instanceof Double) { + visitDouble(((Double) value).doubleValue()); + } else if (value.getClass().isArray()) { + buf.append('{'); + if (value instanceof byte[]) { + byte[] v = (byte[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitByte(v[i]); + } + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitBoolean(v[i]); + } + } else if (value instanceof short[]) { + short[] v = (short[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitShort(v[i]); + } + } else if (value instanceof char[]) { + char[] v = (char[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitChar(v[i]); + } + } else if (value instanceof int[]) { + int[] v = (int[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitInt(v[i]); + } + } else if (value instanceof long[]) { + long[] v = (long[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitLong(v[i]); + } + } else if (value instanceof float[]) { + float[] v = (float[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitFloat(v[i]); + } + } else if (value instanceof double[]) { + double[] v = (double[]) value; + for (int i = 0; i < v.length; i++) { + appendComa(i); + visitDouble(v[i]); + } + } + buf.append('}'); + } else { + buf.append(value); + } + + text.add(buf.toString()); + + if (av != null) { + av.visit(name, value); + } + } + + private void visitInt(int value) { + buf.append(value); + } + + private void visitLong(long value) { + buf.append(value).append('L'); + } + + private void visitFloat(float value) { + buf.append(value).append('F'); + } + + private void visitDouble(double value) { + buf.append(value).append('D'); + } + + private void visitChar(char value) { + buf.append("(char)").append((int) value); + } + + private void visitShort(short value) { + buf.append("(short)").append(value); + } + + private void visitByte(byte value) { + buf.append("(byte)").append(value); + } + + private void visitBoolean(boolean value) { + buf.append(value); + } + + private void visitString(String value) { + appendString(buf, value); + } + + private void visitType(Type value) { + buf.append(value.getClassName()).append(".class"); + } + + public void visitEnum( + final String name, + final String desc, + final String value) + { + buf.setLength(0); + appendComa(valueNumber++); + if (name != null) { + buf.append(name).append('='); + } + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('.').append(value); + text.add(buf.toString()); + + if (av != null) { + av.visitEnum(name, desc, value); + } + } + + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + buf.setLength(0); + appendComa(valueNumber++); + if (name != null) { + buf.append(name).append('='); + } + buf.append('@'); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('('); + text.add(buf.toString()); + TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); + text.add(tav.getText()); + text.add(")"); + if (av != null) { + tav.av = av.visitAnnotation(name, desc); + } + return tav; + } + + public AnnotationVisitor visitArray(final String name) { + buf.setLength(0); + appendComa(valueNumber++); + if (name != null) { + buf.append(name).append('='); + } + buf.append('{'); + text.add(buf.toString()); + TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); + text.add(tav.getText()); + text.add("}"); + if (av != null) { + tav.av = av.visitArray(name); + } + return tav; + } + + public void visitEnd() { + if (av != null) { + av.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected TraceAnnotationVisitor createTraceAnnotationVisitor() { + return new TraceAnnotationVisitor(); + } + + private void appendComa(int i) { + if (i != 0) { + buf.append(", "); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java new file mode 100644 index 000000000..bbadc911d --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceClassVisitor.java @@ -0,0 +1,534 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.signature.SignatureReader; + +/** + * A {@link ClassVisitor} that prints a disassembled view of the classes it + * visits. This class visitor can be used alone (see the {@link #main main} + * method) to disassemble a class. It can also be used in the middle of class + * visitor chain to trace the class that is visited at a given point in this + * chain. This may be uselful for debugging purposes. <p> The trace printed when + * visiting the <tt>Hello</tt> class is the following: <p> <blockquote> + * + * <pre> + * // class version 49.0 (49) + * // access flags 33 + * public class Hello { + * + * // compiled from: Hello.java + * + * // access flags 1 + * public <init> ()V + * ALOAD 0 + * INVOKESPECIAL java/lang/Object <init> ()V + * RETURN + * MAXSTACK = 1 + * MAXLOCALS = 1 + * + * // access flags 9 + * public static main ([Ljava/lang/String;)V + * GETSTATIC java/lang/System out Ljava/io/PrintStream; + * LDC "hello" + * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V + * RETURN + * MAXSTACK = 2 + * MAXLOCALS = 1 + * } + * </pre> + * + * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote> + * + * <pre> + * public class Hello { + * + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + * </pre> + * + * </blockquote> + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class TraceClassVisitor extends TraceAbstractVisitor implements + ClassVisitor +{ + + /** + * The {@link ClassVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected final ClassVisitor cv; + + /** + * The print writer to be used to print the class. + */ + protected final PrintWriter pw; + + /** + * Prints a disassembled view of the given class to the standard output. <p> + * Usage: TraceClassVisitor [-debug] <fully qualified class name or class + * file name > + * + * @param args the command line arguments. + * + * @throws Exception if the class cannot be found, or if an IO exception + * occurs. + */ + public static void main(final String[] args) throws Exception { + int i = 0; + boolean skipDebug = true; + + boolean ok = true; + if (args.length < 1 || args.length > 2) { + ok = false; + } + if (ok && args[0].equals("-debug")) { + i = 1; + skipDebug = false; + if (args.length != 2) { + ok = false; + } + } + if (!ok) { + System.err.println("Prints a disassembled view of the given class."); + System.err.println("Usage: TraceClassVisitor [-debug] " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 + || args[i].indexOf('/') > -1) + { + cr = new ClassReader(new FileInputStream(args[i])); + } else { + cr = new ClassReader(args[i]); + } + cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), + getDefaultAttributes(), + skipDebug); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final PrintWriter pw) { + this(null, pw); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param cv the {@link ClassVisitor} to which this visitor delegates calls. + * May be <tt>null</tt>. + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) { + this.cv = cv; + this.pw = pw; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + int major = version & 0xFFFF; + int minor = version >>> 16; + buf.setLength(0); + buf.append("// class version ") + .append(major) + .append('.') + .append(minor) + .append(" (") + .append(version) + .append(")\n"); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append("// DEPRECATED\n"); + } + buf.append("// access flags ").append(access).append('\n'); + + appendDescriptor(CLASS_SIGNATURE, signature); + if (signature != null) { + TraceSignatureVisitor sv = new TraceSignatureVisitor(access); + SignatureReader r = new SignatureReader(signature); + r.accept(sv); + buf.append("// declaration: ") + .append(name) + .append(sv.getDeclaration()) + .append('\n'); + } + + appendAccess(access & ~Opcodes.ACC_SUPER); + if ((access & Opcodes.ACC_ANNOTATION) != 0) { + buf.append("@interface "); + } else if ((access & Opcodes.ACC_INTERFACE) != 0) { + buf.append("interface "); + } else if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } else { + buf.append("class "); + } + appendDescriptor(INTERNAL_NAME, name); + + if (superName != null && !superName.equals("java/lang/Object")) { + buf.append(" extends "); + appendDescriptor(INTERNAL_NAME, superName); + buf.append(' '); + } + if (interfaces != null && interfaces.length > 0) { + buf.append(" implements "); + for (int i = 0; i < interfaces.length; ++i) { + appendDescriptor(INTERNAL_NAME, interfaces[i]); + buf.append(' '); + } + } + buf.append(" {\n\n"); + + text.add(buf.toString()); + + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + public void visitSource(final String file, final String debug) { + buf.setLength(0); + if (file != null) { + buf.append(tab) + .append("// compiled from: ") + .append(file) + .append('\n'); + } + if (debug != null) { + buf.append(tab) + .append("// debug info: ") + .append(debug) + .append('\n'); + } + if (buf.length() > 0) { + text.add(buf.toString()); + } + + if (cv != null) { + cv.visitSource(file, debug); + } + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab).append("OUTERCLASS "); + appendDescriptor(INTERNAL_NAME, owner); + // if enclosing name is null, so why should we show this info? + if (name != null) { + buf.append(' ').append(name).append(' '); + } else { + buf.append(' '); + } + appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitOuterClass(owner, name, desc); + } + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + text.add("\n"); + AnnotationVisitor tav = super.visitAnnotation(desc, visible); + if (cv != null) { + ((TraceAnnotationVisitor) tav).av = cv.visitAnnotation(desc, + visible); + } + return tav; + } + + public void visitAttribute(final Attribute attr) { + text.add("\n"); + super.visitAttribute(attr); + + if (cv != null) { + cv.visitAttribute(attr); + } + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + buf.setLength(0); + buf.append(tab).append("// access flags ").append(access + & ~Opcodes.ACC_SUPER).append('\n'); + buf.append(tab); + appendAccess(access); + buf.append("INNERCLASS "); + if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } + appendDescriptor(INTERNAL_NAME, name); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, outerName); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, innerName); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags ").append(access).append('\n'); + if (signature != null) { + buf.append(tab); + appendDescriptor(FIELD_SIGNATURE, signature); + + TraceSignatureVisitor sv = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.acceptType(sv); + buf.append(tab) + .append("// declaration: ") + .append(sv.getDeclaration()) + .append('\n'); + } + + buf.append(tab); + appendAccess(access); + if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } + + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' ').append(name); + if (value != null) { + buf.append(" = "); + if (value instanceof String) { + buf.append("\"").append(value).append("\""); + } else { + buf.append(value); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceFieldVisitor tav = createTraceFieldVisitor(); + text.add(tav.getText()); + + if (cv != null) { + tav.fv = cv.visitField(access, name, desc, signature, value); + } + + return tav; + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags ").append(access).append('\n'); + buf.append(tab); + appendDescriptor(METHOD_SIGNATURE, signature); + + if (signature != null) { + TraceSignatureVisitor v = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.accept(v); + String genericDecl = v.getDeclaration(); + String genericReturn = v.getReturnType(); + String genericExceptions = v.getExceptions(); + + buf.append(tab) + .append("// declaration: ") + .append(genericReturn) + .append(' ') + .append(name) + .append(genericDecl); + if (genericExceptions != null) { + buf.append(" throws ").append(genericExceptions); + } + buf.append('\n'); + } + + appendAccess(access); + if ((access & Opcodes.ACC_NATIVE) != 0) { + buf.append("native "); + } + if ((access & Opcodes.ACC_VARARGS) != 0) { + buf.append("varargs "); + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + buf.append("bridge "); + } + + buf.append(name); + appendDescriptor(METHOD_DESCRIPTOR, desc); + if (exceptions != null && exceptions.length > 0) { + buf.append(" throws "); + for (int i = 0; i < exceptions.length; ++i) { + appendDescriptor(INTERNAL_NAME, exceptions[i]); + buf.append(' '); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceMethodVisitor tcv = createTraceMethodVisitor(); + text.add(tcv.getText()); + + if (cv != null) { + tcv.mv = cv.visitMethod(access, name, desc, signature, exceptions); + } + + return tcv; + } + + public void visitEnd() { + text.add("}\n"); + + printList(pw, text); + pw.flush(); + + if (cv != null) { + cv.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected TraceFieldVisitor createTraceFieldVisitor() { + return new TraceFieldVisitor(); + } + + protected TraceMethodVisitor createTraceMethodVisitor() { + return new TraceMethodVisitor(); + } + + /** + * Appends a string representation of the given access modifiers to {@link + * #buf buf}. + * + * @param access some access modifiers. + */ + private void appendAccess(final int access) { + if ((access & Opcodes.ACC_PUBLIC) != 0) { + buf.append("public "); + } + if ((access & Opcodes.ACC_PRIVATE) != 0) { + buf.append("private "); + } + if ((access & Opcodes.ACC_PROTECTED) != 0) { + buf.append("protected "); + } + if ((access & Opcodes.ACC_FINAL) != 0) { + buf.append("final "); + } + if ((access & Opcodes.ACC_STATIC) != 0) { + buf.append("static "); + } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + buf.append("synchronized "); + } + if ((access & Opcodes.ACC_VOLATILE) != 0) { + buf.append("volatile "); + } + if ((access & Opcodes.ACC_TRANSIENT) != 0) { + buf.append("transient "); + } + // if ((access & Constants.ACC_NATIVE) != 0) { + // buf.append("native "); + // } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + buf.append("abstract "); + } + if ((access & Opcodes.ACC_STRICT) != 0) { + buf.append("strictfp "); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + buf.append("synthetic "); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceFieldVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceFieldVisitor.java new file mode 100644 index 000000000..4d20efd8b --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceFieldVisitor.java @@ -0,0 +1,78 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; + +/** + * A {@link FieldVisitor} that prints a disassembled view of the fields it + * visits. + * + * @author Eric Bruneton + */ +public class TraceFieldVisitor extends TraceAbstractVisitor implements + FieldVisitor +{ + + /** + * The {@link FieldVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected FieldVisitor fv; + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationVisitor av = super.visitAnnotation(desc, visible); + if (fv != null) { + ((TraceAnnotationVisitor) av).av = fv.visitAnnotation(desc, visible); + } + return av; + } + + public void visitAttribute(final Attribute attr) { + super.visitAttribute(attr); + + if (fv != null) { + fv.visitAttribute(attr); + } + } + + public void visitEnd() { + super.visitEnd(); + + if (fv != null) { + fv.visitEnd(); + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceMethodVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceMethodVisitor.java new file mode 100644 index 000000000..73a511bc3 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceMethodVisitor.java @@ -0,0 +1,486 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.util.attrs.Traceable; + +import java.util.HashMap; + +/** + * A {@link MethodVisitor} that prints a disassembled view of the methods it + * visits. + * + * @author Eric Bruneton + */ +public class TraceMethodVisitor extends TraceAbstractVisitor implements + MethodVisitor +{ + + /** + * The {@link MethodVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected MethodVisitor mv; + + /** + * Tab for bytecode instructions. + */ + protected String tab2 = " "; + + /** + * Tab for table and lookup switch instructions. + */ + protected String tab3 = " "; + + /** + * Tab for labels. + */ + protected String ltab = " "; + + /** + * The label names. This map associate String values to Label keys. + */ + protected final HashMap labelNames; + + /** + * Constructs a new {@link TraceMethodVisitor}. + */ + public TraceMethodVisitor() { + this(null); + } + + /** + * Constructs a new {@link TraceMethodVisitor}. + * + * @param mv the {@link MethodVisitor} to which this visitor delegates + * calls. May be <tt>null</tt>. + */ + public TraceMethodVisitor(final MethodVisitor mv) { + this.labelNames = new HashMap(); + this.mv = mv; + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor interface + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationVisitor av = super.visitAnnotation(desc, visible); + if (mv != null) { + ((TraceAnnotationVisitor) av).av = mv.visitAnnotation(desc, visible); + } + return av; + } + + public void visitAttribute(final Attribute attr) { + buf.setLength(0); + buf.append(tab).append("ATTRIBUTE "); + appendDescriptor(-1, attr.type); + + if (attr instanceof Traceable) { + ((Traceable) attr).trace(buf, labelNames); + } else { + buf.append(" : ").append(attr.toString()).append("\n"); + } + + text.add(buf.toString()); + if (mv != null) { + mv.visitAttribute(attr); + } + } + + public AnnotationVisitor visitAnnotationDefault() { + text.add(tab2 + "default="); + TraceAnnotationVisitor tav = new TraceAnnotationVisitor(); + text.add(tav.getText()); + text.add("\n"); + if (mv != null) { + tav.av = mv.visitAnnotationDefault(); + } + return tav; + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append(tab2).append('@'); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('('); + text.add(buf.toString()); + TraceAnnotationVisitor tav = new TraceAnnotationVisitor(); + text.add(tav.getText()); + text.add(visible ? ") // parameter " : ") // invisible, parameter "); + text.add(new Integer(parameter)); + text.add("\n"); + if (mv != null) { + tav.av = mv.visitParameterAnnotation(parameter, desc, visible); + } + return tav; + } + + public void visitCode() { + if (mv != null) { + mv.visitCode(); + } + } + + public void visitInsn(final int opcode) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitInsn(opcode); + } + } + + public void visitIntInsn(final int opcode, final int operand) { + buf.setLength(0); + buf.append(tab2) + .append(OPCODES[opcode]) + .append(' ') + .append(opcode == Opcodes.NEWARRAY + ? TYPES[operand] + : Integer.toString(operand)) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitIntInsn(opcode, operand); + } + } + + public void visitVarInsn(final int opcode, final int var) { + buf.setLength(0); + buf.append(tab2) + .append(OPCODES[opcode]) + .append(' ') + .append(var) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitVarInsn(opcode, var); + } + } + + public void visitTypeInsn(final int opcode, final String desc) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + if (desc.startsWith("[")) { + appendDescriptor(FIELD_DESCRIPTOR, desc); + } else { + appendDescriptor(INTERNAL_NAME, desc); + } + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTypeInsn(opcode, desc); + } + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendDescriptor(INTERNAL_NAME, owner); + buf.append('.').append(name).append(" : "); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitFieldInsn(opcode, owner, name, desc); + } + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendDescriptor(INTERNAL_NAME, owner); + buf.append('.').append(name).append(' '); + appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc); + } + } + + public void visitJumpInsn(final int opcode, final Label label) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendLabel(label); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitJumpInsn(opcode, label); + } + } + + public void visitLabel(final Label label) { + buf.setLength(0); + buf.append(ltab); + appendLabel(label); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLabel(label); + } + } + + public void visitLdcInsn(final Object cst) { + buf.setLength(0); + buf.append(tab2).append("LDC "); + if (cst instanceof String) { + AbstractVisitor.appendString(buf, (String) cst); + } else if (cst instanceof Type) { + buf.append(((Type) cst).getDescriptor() + ".class"); + } else { + buf.append(cst); + } + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLdcInsn(cst); + } + } + + public void visitIincInsn(final int var, final int increment) { + buf.setLength(0); + buf.append(tab2) + .append("IINC ") + .append(var) + .append(' ') + .append(increment) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitIincInsn(var, increment); + } + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label labels[]) + { + buf.setLength(0); + buf.append(tab2).append("TABLESWITCH\n"); + for (int i = 0; i < labels.length; ++i) { + buf.append(tab3).append(min + i).append(": "); + appendLabel(labels[i]); + buf.append('\n'); + } + buf.append(tab3).append("default: "); + appendLabel(dflt); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int keys[], + final Label labels[]) + { + buf.setLength(0); + buf.append(tab2).append("LOOKUPSWITCH\n"); + for (int i = 0; i < labels.length; ++i) { + buf.append(tab3).append(keys[i]).append(": "); + appendLabel(labels[i]); + buf.append('\n'); + } + buf.append(tab3).append("default: "); + appendLabel(dflt); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + buf.setLength(0); + buf.append(tab2).append("MULTIANEWARRAY "); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' ').append(dims).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMultiANewArrayInsn(desc, dims); + } + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + buf.setLength(0); + buf.append(tab2).append("TRYCATCHBLOCK "); + appendLabel(start); + buf.append(' '); + appendLabel(end); + buf.append(' '); + appendLabel(handler); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, type); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTryCatchBlock(start, end, handler, type); + } + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + buf.setLength(0); + buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' '); + appendLabel(start); + buf.append(' '); + appendLabel(end); + buf.append(' ').append(index).append('\n'); + + if (signature != null) { + buf.append(tab2); + appendDescriptor(FIELD_SIGNATURE, signature); + + TraceSignatureVisitor sv = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.acceptType(sv); + buf.append(tab2) + .append("// declaration: ") + .append(sv.getDeclaration()) + .append('\n'); + } + text.add(buf.toString()); + + if (mv != null) { + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + } + + public void visitLineNumber(final int line, final Label start) { + buf.setLength(0); + buf.append(tab2).append("LINENUMBER ").append(line).append(' '); + appendLabel(start); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLineNumber(line, start); + } + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + buf.setLength(0); + buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); + text.add(buf.toString()); + + buf.setLength(0); + buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMaxs(maxStack, maxLocals); + } + } + + public void visitEnd() { + super.visitEnd(); + + if (mv != null) { + mv.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Appends the name of the given label to {@link #buf buf}. Creates a new + * label name if the given label does not yet have one. + * + * @param l a label. + */ + public void appendLabel(final Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "L" + labelNames.size(); + labelNames.put(l, name); + } + buf.append(name); + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceSignatureVisitor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceSignatureVisitor.java new file mode 100644 index 000000000..e8346c633 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/TraceSignatureVisitor.java @@ -0,0 +1,300 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} that prints a disassembled view of the signature + * it visits. + * + * @author Eugene Kuleshov + * @author Eric Bruneton + */ +public class TraceSignatureVisitor implements SignatureVisitor { + + private StringBuffer declaration; + + private boolean isInterface; + + private boolean seenFormalParameter; + + private boolean seenInterfaceBound; + + private boolean seenParameter; + + private boolean seenInterface; + + private StringBuffer returnType; + + private StringBuffer exceptions; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Stack used to keep track of array class types. Each element of this stack + * is a boolean encoded in one bit. The top of the stack is the lowest order + * bit. Pushing false = *2, pushing true = *2+1, popping = /2. + */ + private int arrayStack; + + private String separator = ""; + + public TraceSignatureVisitor(int access) { + isInterface = (access & Opcodes.ACC_INTERFACE) != 0; + this.declaration = new StringBuffer(); + } + + private TraceSignatureVisitor(StringBuffer buf) { + this.declaration = buf; + } + + public void visitFormalTypeParameter(String name) { + declaration.append(seenFormalParameter ? ", " : "<").append(name); + seenFormalParameter = true; + seenInterfaceBound = false; + } + + public SignatureVisitor visitClassBound() { + separator = " extends "; + startType(); + return this; + } + + public SignatureVisitor visitInterfaceBound() { + separator = seenInterfaceBound ? ", " : " extends "; + seenInterfaceBound = true; + startType(); + return this; + } + + public SignatureVisitor visitSuperclass() { + endFormals(); + separator = " extends "; + startType(); + return this; + } + + public SignatureVisitor visitInterface() { + separator = seenInterface ? ", " : (isInterface + ? " extends " + : " implements "); + seenInterface = true; + startType(); + return this; + } + + public SignatureVisitor visitParameterType() { + endFormals(); + if (!seenParameter) { + seenParameter = true; + declaration.append('('); + } else { + declaration.append(", "); + } + startType(); + return this; + } + + public SignatureVisitor visitReturnType() { + endFormals(); + if (!seenParameter) { + declaration.append('('); + } else { + seenParameter = false; + } + declaration.append(')'); + returnType = new StringBuffer(); + return new TraceSignatureVisitor(returnType); + } + + public SignatureVisitor visitExceptionType() { + if (exceptions == null) { + exceptions = new StringBuffer(); + } else { + exceptions.append(", "); + } + // startType(); + return new TraceSignatureVisitor(exceptions); + } + + public void visitBaseType(char descriptor) { + switch (descriptor) { + case 'V': + declaration.append("void"); + break; + case 'B': + declaration.append("byte"); + break; + case 'J': + declaration.append("long"); + break; + case 'Z': + declaration.append("boolean"); + break; + case 'I': + declaration.append("int"); + break; + case 'S': + declaration.append("short"); + break; + case 'C': + declaration.append("char"); + break; + case 'F': + declaration.append("float"); + break; + // case 'D': + default: + declaration.append("double"); + break; + } + endType(); + } + + public void visitTypeVariable(String name) { + declaration.append(name); + endType(); + } + + public SignatureVisitor visitArrayType() { + startType(); + arrayStack |= 1; + return this; + } + + public void visitClassType(String name) { + if (!"java/lang/Object".equals(name)) { + declaration.append(separator).append(name.replace('/', '.')); + } else { + // Map<java.lang.Object,java.util.List> + // or + // abstract public V get(Object key); (seen in Dictionary.class) + // should have Object + // but java.lang.String extends java.lang.Object is unnecessary + boolean needObjectClass = argumentStack % 2 == 1 || seenParameter; + if (needObjectClass) { + declaration.append(separator).append(name.replace('/', '.')); + } + } + separator = ""; + argumentStack *= 2; + } + + public void visitInnerClassType(String name) { + if (argumentStack % 2 == 1) { + declaration.append('>'); + } + argumentStack /= 2; + declaration.append('.'); + declaration.append(separator).append(name.replace('/', '.')); + separator = ""; + argumentStack *= 2; + } + + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + declaration.append('<'); + } else { + declaration.append(", "); + } + declaration.append('?'); + } + + public SignatureVisitor visitTypeArgument(char tag) { + if (argumentStack % 2 == 0) { + ++argumentStack; + declaration.append('<'); + } else { + declaration.append(", "); + } + + if (tag == SignatureVisitor.EXTENDS) { + declaration.append("? extends "); + } else if (tag == SignatureVisitor.SUPER) { + declaration.append("? super "); + } + + startType(); + return this; + } + + public void visitEnd() { + if (argumentStack % 2 == 1) { + declaration.append('>'); + } + argumentStack /= 2; + endType(); + } + + public String getDeclaration() { + return declaration.toString(); + } + + public String getReturnType() { + return returnType == null ? null : returnType.toString(); + } + + public String getExceptions() { + return exceptions == null ? null : exceptions.toString(); + } + + // ----------------------------------------------- + + private void endFormals() { + if (seenFormalParameter) { + declaration.append('>'); + seenFormalParameter = false; + } + } + + private void startType() { + arrayStack *= 2; + } + + private void endType() { + if (arrayStack % 2 == 1) { + while (arrayStack % 2 == 1) { + arrayStack /= 2; + declaration.append("[]"); + } + } else { + arrayStack /= 2; + } + } +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapAttribute.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapAttribute.java new file mode 100644 index 000000000..e71e116fe --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapAttribute.java @@ -0,0 +1,223 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util.attrs; + +import java.util.List; +import java.util.Map; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Label; +import org.objectweb.asm.attrs.StackMapAttribute; +import org.objectweb.asm.attrs.StackMapFrame; +import org.objectweb.asm.attrs.StackMapType; + +/** + * An {@link ASMifiable} {@link StackMapAttribute} sub class. + * + * @author Eugene Kuleshov + */ +public class ASMStackMapAttribute extends StackMapAttribute implements + ASMifiable, + Traceable +{ + /** + * Length of the attribute used for comparison + */ + private int len; + + public ASMStackMapAttribute() { + super(); + } + + public ASMStackMapAttribute(List frames, int len) { + super(frames); + this.len = len; + } + + protected Attribute read( + ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + StackMapAttribute attr = (StackMapAttribute) super.read(cr, + off, + len, + buf, + codeOff, + labels); + + return new ASMStackMapAttribute(attr.getFrames(), len); + } + + public void asmify(StringBuffer buf, String varName, Map labelNames) { + List frames = getFrames(); + buf.append("{\n"); + buf.append("StackMapAttribute ").append(varName).append("Attr"); + buf.append(" = new StackMapAttribute();\n"); + if (frames.size() > 0) { + for (int i = 0; i < frames.size(); i++) { + asmify((StackMapFrame) frames.get(i), buf, varName + "frame" + + i, labelNames); + } + } + buf.append(varName).append(".visitAttribute(").append(varName); + buf.append("Attr);\n}\n"); + } + + void asmify( + StackMapFrame f, + StringBuffer buf, + String varName, + Map labelNames) + { + declareLabel(buf, labelNames, f.label); + buf.append("{\n"); + + buf.append("StackMapFrame ") + .append(varName) + .append(" = new StackMapFrame();\n"); + + buf.append(varName) + .append(".label = ") + .append(labelNames.get(f.label)) + .append(";\n"); + + asmifyTypeInfo(buf, varName, labelNames, f.locals, "locals"); + asmifyTypeInfo(buf, varName, labelNames, f.stack, "stack"); + + buf.append("cvAttr.frames.add(").append(varName).append(");\n"); + buf.append("}\n"); + } + + void asmifyTypeInfo( + StringBuffer buf, + String varName, + Map labelNames, + List infos, + String field) + { + if (infos.size() > 0) { + buf.append("{\n"); + for (int i = 0; i < infos.size(); i++) { + StackMapType typeInfo = (StackMapType) infos.get(i); + String localName = varName + "Info" + i; + int type = typeInfo.getType(); + buf.append("StackMapType ") + .append(localName) + .append(" = StackMapType.getTypeInfo( StackMapType.ITEM_") + .append(StackMapType.ITEM_NAMES[type]) + .append(");\n"); + + switch (type) { + case StackMapType.ITEM_Object: // + buf.append(localName) + .append(".setObject(\"") + .append(typeInfo.getObject()) + .append("\");\n"); + break; + + case StackMapType.ITEM_Uninitialized: // + declareLabel(buf, labelNames, typeInfo.getLabel()); + buf.append(localName) + .append(".setLabel(") + .append(labelNames.get(typeInfo.getLabel())) + .append(");\n"); + break; + } + buf.append(varName) + .append(".") + .append(field) + .append(".add(") + .append(localName) + .append(");\n"); + } + buf.append("}\n"); + } + } + + static void declareLabel(StringBuffer buf, Map labelNames, Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "l" + labelNames.size(); + labelNames.put(l, name); + buf.append("Label ").append(name).append(" = new Label();\n"); + } + } + + public void trace(StringBuffer buf, Map labelNames) { + List frames = getFrames(); + buf.append("[\n"); + for (int i = 0; i < frames.size(); i++) { + StackMapFrame f = (StackMapFrame) frames.get(i); + + buf.append(" Frame:"); + appendLabel(buf, labelNames, f.label); + + buf.append(" locals["); + traceTypeInfo(buf, labelNames, f.locals); + buf.append("]"); + buf.append(" stack["); + traceTypeInfo(buf, labelNames, f.stack); + buf.append("]\n"); + } + buf.append(" ] length:").append(len).append("\n"); + } + + private void traceTypeInfo(StringBuffer buf, Map labelNames, List infos) { + String sep = ""; + for (int i = 0; i < infos.size(); i++) { + StackMapType t = (StackMapType) infos.get(i); + + buf.append(sep).append(StackMapType.ITEM_NAMES[t.getType()]); + sep = ", "; + if (t.getType() == StackMapType.ITEM_Object) { + buf.append(":").append(t.getObject()); + } + if (t.getType() == StackMapType.ITEM_Uninitialized) { + buf.append(":"); + appendLabel(buf, labelNames, t.getLabel()); + } + } + } + + protected void appendLabel(StringBuffer buf, Map labelNames, Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "L" + labelNames.size(); + labelNames.put(l, name); + } + buf.append(name); + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapTableAttribute.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapTableAttribute.java new file mode 100644 index 000000000..e591cb935 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMStackMapTableAttribute.java @@ -0,0 +1,214 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util.attrs; + +import java.util.List; +import java.util.Map; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Label; +import org.objectweb.asm.attrs.StackMapTableAttribute; +import org.objectweb.asm.attrs.StackMapFrame; +import org.objectweb.asm.attrs.StackMapType; + +/** + * An {@link ASMifiable} {@link StackMapTableAttribute} sub class. + * + * @author Eugene Kuleshov + */ +public class ASMStackMapTableAttribute extends StackMapTableAttribute implements + ASMifiable, + Traceable +{ + /** + * Length of the attribute used for comparison + */ + private int len; + + public ASMStackMapTableAttribute() { + super(); + } + + public ASMStackMapTableAttribute(List frames, int len) { + super(frames); + this.len = len; + } + + protected Attribute read( + ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + StackMapTableAttribute attr = (StackMapTableAttribute) super.read(cr, + off, + len, + buf, + codeOff, + labels); + + return new ASMStackMapTableAttribute(attr.getFrames(), len); + } + + public void asmify(StringBuffer buf, String varName, Map labelNames) { + List frames = getFrames(); + if (frames.size() == 0) { + buf.append("List frames = Collections.EMPTY_LIST;\n"); + } else { + buf.append("List frames = new ArrayList();\n"); + for (int i = 0; i < frames.size(); i++) { + buf.append("{\n"); + StackMapFrame f = (StackMapFrame) frames.get(i); + declareLabel(buf, labelNames, f.label); + + String frameVar = varName + "frame" + i; + asmifyTypeInfo(buf, frameVar, labelNames, f.locals, "locals"); + asmifyTypeInfo(buf, frameVar, labelNames, f.stack, "stack"); + + buf.append("StackMapFrame ") + .append(frameVar) + .append(" = new StackMapFrame(") + .append(labelNames.get(f.label)) + .append(", locals, stack);\n"); + buf.append("frames.add(").append(frameVar).append(");\n"); + buf.append("}\n"); + } + } + buf.append("StackMapTableAttribute ").append(varName); + buf.append(" = new StackMapTableAttribute(frames);\n"); + } + + void asmifyTypeInfo( + StringBuffer buf, + String varName, + Map labelNames, + List infos, + String field) + { + if (infos.size() == 0) { + buf.append("List ") + .append(field) + .append(" = Collections.EMPTY_LIST;\n"); + } else { + buf.append("List ").append(field).append(" = new ArrayList();\n"); + buf.append("{\n"); + for (int i = 0; i < infos.size(); i++) { + StackMapType typeInfo = (StackMapType) infos.get(i); + String localName = varName + "Info" + i; + int type = typeInfo.getType(); + buf.append("StackMapType ") + .append(localName) + .append(" = StackMapType.getTypeInfo( StackMapType.ITEM_") + .append(StackMapType.ITEM_NAMES[type]) + .append(");\n"); + + switch (type) { + case StackMapType.ITEM_Object: // + buf.append(localName) + .append(".setObject(\"") + .append(typeInfo.getObject()) + .append("\");\n"); + break; + + case StackMapType.ITEM_Uninitialized: // + declareLabel(buf, labelNames, typeInfo.getLabel()); + buf.append(localName) + .append(".setLabel(") + .append(labelNames.get(typeInfo.getLabel())) + .append(");\n"); + break; + } + buf.append(field) + .append(".add(") + .append(localName) + .append(");\n"); + } + buf.append("}\n"); + } + } + + static void declareLabel(StringBuffer buf, Map labelNames, Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "l" + labelNames.size(); + labelNames.put(l, name); + buf.append("Label ").append(name).append(" = new Label();\n"); + } + } + + public void trace(StringBuffer buf, Map labelNames) { + List frames = getFrames(); + buf.append("[\n"); + for (int i = 0; i < frames.size(); i++) { + StackMapFrame f = (StackMapFrame) frames.get(i); + + buf.append(" Frame:"); + appendLabel(buf, labelNames, f.label); + + buf.append(" locals["); + traceTypeInfo(buf, labelNames, f.locals); + buf.append("]"); + buf.append(" stack["); + traceTypeInfo(buf, labelNames, f.stack); + buf.append("]\n"); + } + buf.append(" ] length:").append(len).append("\n"); + } + + private void traceTypeInfo(StringBuffer buf, Map labelNames, List infos) { + String sep = ""; + for (int i = 0; i < infos.size(); i++) { + StackMapType t = (StackMapType) infos.get(i); + + buf.append(sep).append(StackMapType.ITEM_NAMES[t.getType()]); + sep = ", "; + if (t.getType() == StackMapType.ITEM_Object) { + buf.append(":").append(t.getObject()); + } + if (t.getType() == StackMapType.ITEM_Uninitialized) { + buf.append(":"); + appendLabel(buf, labelNames, t.getLabel()); + } + } + } + + protected void appendLabel(StringBuffer buf, Map labelNames, Label l) { + String name = (String) labelNames.get(l); + if (name == null) { + name = "L" + labelNames.size(); + labelNames.put(l, name); + } + buf.append(name); + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMifiable.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMifiable.java new file mode 100644 index 000000000..f9067bfe1 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/ASMifiable.java @@ -0,0 +1,53 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util.attrs; + +import java.util.Map; + +/** + * An attribute that can print the ASM code to create an equivalent attribute. + * + * Implementation should print the ASM code that generates attribute data + * structures for current attribute state. + * + * @author Eugene Kuleshov + */ +public interface ASMifiable { + + /** + * Prints the ASM code to create an attribute equal to this attribute. + * + * @param buf A buffer used for printing Java code. + * @param varName name of the variable in a printed code used to store + * attribute instance. + * @param labelNames map of label instances to their names. + */ + void asmify(StringBuffer buf, String varName, Map labelNames); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/Traceable.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/Traceable.java new file mode 100644 index 000000000..44680b57e --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/util/attrs/Traceable.java @@ -0,0 +1,52 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.util.attrs; + +import java.util.Map; + +/** + * An attribute that can print eadable representation of the attribute. + * + * Implementation should construct readable output from an attribute data + * structures for current attribute state. Such representation could be used in + * unit test assertions. + * + * @author Eugene Kuleshov + */ +public interface Traceable { + + /** + * Build a human readable representation of the attribute. + * + * @param buf A buffer used for printing Java code. + * @param labelNames map of label instances to their names. + */ + void trace(StringBuffer buf, Map labelNames); +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/ASMContentHandler.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/ASMContentHandler.java new file mode 100644 index 000000000..826a7fe7f --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/ASMContentHandler.java @@ -0,0 +1,1215 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A {@link org.xml.sax.ContentHandler ContentHandler} that transforms XML + * document into Java class file. This class can be feeded by any kind of SAX + * 2.0 event producers, e.g. XML parser, XSLT or XPath engines, or custom code. + * + * @see org.objectweb.asm.xml.SAXClassAdapter + * @see org.objectweb.asm.xml.Processor + * + * @author Eugene Kuleshov + */ +public class ASMContentHandler extends DefaultHandler implements Opcodes { + /** + * Stack of the intermediate processing contexts. + */ + private List stack = new ArrayList(); + + /** + * Complete name of the current element. + */ + private String match = ""; + + /** + * <tt>true</tt> if the maximum stack size and number of local variables + * must be automatically computed. + */ + protected boolean computeMax; + + /** + * Output stream to write result bytecode. + */ + protected OutputStream os; + + /** + * Current instance of the {@link ClassWriter ClassWriter} used to write + * class bytecode. + */ + protected ClassWriter cw; + + /** + * Map of the active {@link Label Label} instances for current method. + */ + protected Map labels; + + private static final String BASE = "class"; + + private final RuleSet RULES = new RuleSet(); + { + RULES.add(BASE, new ClassRule()); + RULES.add(BASE + "/interfaces/interface", new InterfaceRule()); + RULES.add(BASE + "/interfaces", new InterfacesRule()); + RULES.add(BASE + "/outerclass", new OuterClassRule()); + RULES.add(BASE + "/innerclass", new InnerClassRule()); + RULES.add(BASE + "/source", new SourceRule()); + RULES.add(BASE + "/field", new FieldRule()); + + RULES.add(BASE + "/method", new MethodRule()); + RULES.add(BASE + "/method/exceptions/exception", new ExceptionRule()); + RULES.add(BASE + "/method/exceptions", new ExceptionsRule()); + + RULES.add(BASE + "/method/annotationDefault", + new AnnotationDefaultRule()); + + RULES.add(BASE + "/method/code/*", new OpcodesRule()); // opcodes + + RULES.add(BASE + "/method/code/TABLESWITCH", new TableSwitchRule()); + RULES.add(BASE + "/method/code/TABLESWITCH/label", + new TableSwitchLabelRule()); + RULES.add(BASE + "/method/code/LOOKUPSWITCH", new LookupSwitchRule()); + RULES.add(BASE + "/method/code/LOOKUPSWITCH/label", + new LookupSwitchLabelRule()); + + RULES.add(BASE + "/method/code/Label", new LabelRule()); + RULES.add(BASE + "/method/code/TryCatch", new TryCatchRule()); + RULES.add(BASE + "/method/code/LineNumber", new LineNumberRule()); + RULES.add(BASE + "/method/code/LocalVar", new LocalVarRule()); + RULES.add(BASE + "/method/code/Max", new MaxRule()); + + RULES.add("*/annotation", new AnnotationRule()); + RULES.add("*/parameterAnnotation", new AnnotationParameterRule()); + RULES.add("*/annotationValue", new AnnotationValueRule()); + RULES.add("*/annotationValueAnnotation", + new AnnotationValueAnnotationRule()); + RULES.add("*/annotationValueEnum", new AnnotationValueEnumRule()); + RULES.add("*/annotationValueArray", new AnnotationValueArrayRule()); + } + + private static interface OpcodeGroup { + public static final int INSN = 0; + public static final int INSN_INT = 1; + public static final int INSN_VAR = 2; + public static final int INSN_TYPE = 3; + public static final int INSN_FIELD = 4; + public static final int INSN_METHOD = 5; + public static final int INSN_JUMP = 6; + public static final int INSN_LDC = 7; + public static final int INSN_IINC = 8; + public static final int INSN_MULTIANEWARRAY = 9; + } + + /** + * Map of the opcode names to opcode and opcode group + */ + static final Map OPCODES = new HashMap(); + static { + OPCODES.put("NOP", new Opcode(NOP, OpcodeGroup.INSN)); + OPCODES.put("ACONST_NULL", new Opcode(ACONST_NULL, OpcodeGroup.INSN)); + OPCODES.put("ICONST_M1", new Opcode(ICONST_M1, OpcodeGroup.INSN)); + OPCODES.put("ICONST_0", new Opcode(ICONST_0, OpcodeGroup.INSN)); + OPCODES.put("ICONST_1", new Opcode(ICONST_1, OpcodeGroup.INSN)); + OPCODES.put("ICONST_2", new Opcode(ICONST_2, OpcodeGroup.INSN)); + OPCODES.put("ICONST_3", new Opcode(ICONST_3, OpcodeGroup.INSN)); + OPCODES.put("ICONST_4", new Opcode(ICONST_4, OpcodeGroup.INSN)); + OPCODES.put("ICONST_5", new Opcode(ICONST_5, OpcodeGroup.INSN)); + OPCODES.put("LCONST_0", new Opcode(LCONST_0, OpcodeGroup.INSN)); + OPCODES.put("LCONST_1", new Opcode(LCONST_1, OpcodeGroup.INSN)); + OPCODES.put("FCONST_0", new Opcode(FCONST_0, OpcodeGroup.INSN)); + OPCODES.put("FCONST_1", new Opcode(FCONST_1, OpcodeGroup.INSN)); + OPCODES.put("FCONST_2", new Opcode(FCONST_2, OpcodeGroup.INSN)); + OPCODES.put("DCONST_0", new Opcode(DCONST_0, OpcodeGroup.INSN)); + OPCODES.put("DCONST_1", new Opcode(DCONST_1, OpcodeGroup.INSN)); + OPCODES.put("BIPUSH", new Opcode(BIPUSH, OpcodeGroup.INSN_INT)); + OPCODES.put("SIPUSH", new Opcode(SIPUSH, OpcodeGroup.INSN_INT)); + OPCODES.put("LDC", new Opcode(LDC, OpcodeGroup.INSN_LDC)); + OPCODES.put("ILOAD", new Opcode(ILOAD, OpcodeGroup.INSN_VAR)); + OPCODES.put("LLOAD", new Opcode(LLOAD, OpcodeGroup.INSN_VAR)); + OPCODES.put("FLOAD", new Opcode(FLOAD, OpcodeGroup.INSN_VAR)); + OPCODES.put("DLOAD", new Opcode(DLOAD, OpcodeGroup.INSN_VAR)); + OPCODES.put("ALOAD", new Opcode(ALOAD, OpcodeGroup.INSN_VAR)); + OPCODES.put("IALOAD", new Opcode(IALOAD, OpcodeGroup.INSN)); + OPCODES.put("LALOAD", new Opcode(LALOAD, OpcodeGroup.INSN)); + OPCODES.put("FALOAD", new Opcode(FALOAD, OpcodeGroup.INSN)); + OPCODES.put("DALOAD", new Opcode(DALOAD, OpcodeGroup.INSN)); + OPCODES.put("AALOAD", new Opcode(AALOAD, OpcodeGroup.INSN)); + OPCODES.put("BALOAD", new Opcode(BALOAD, OpcodeGroup.INSN)); + OPCODES.put("CALOAD", new Opcode(CALOAD, OpcodeGroup.INSN)); + OPCODES.put("SALOAD", new Opcode(SALOAD, OpcodeGroup.INSN)); + OPCODES.put("ISTORE", new Opcode(ISTORE, OpcodeGroup.INSN_VAR)); + OPCODES.put("LSTORE", new Opcode(LSTORE, OpcodeGroup.INSN_VAR)); + OPCODES.put("FSTORE", new Opcode(FSTORE, OpcodeGroup.INSN_VAR)); + OPCODES.put("DSTORE", new Opcode(DSTORE, OpcodeGroup.INSN_VAR)); + OPCODES.put("ASTORE", new Opcode(ASTORE, OpcodeGroup.INSN_VAR)); + OPCODES.put("IASTORE", new Opcode(IASTORE, OpcodeGroup.INSN)); + OPCODES.put("LASTORE", new Opcode(LASTORE, OpcodeGroup.INSN)); + OPCODES.put("FASTORE", new Opcode(FASTORE, OpcodeGroup.INSN)); + OPCODES.put("DASTORE", new Opcode(DASTORE, OpcodeGroup.INSN)); + OPCODES.put("AASTORE", new Opcode(AASTORE, OpcodeGroup.INSN)); + OPCODES.put("BASTORE", new Opcode(BASTORE, OpcodeGroup.INSN)); + OPCODES.put("CASTORE", new Opcode(CASTORE, OpcodeGroup.INSN)); + OPCODES.put("SASTORE", new Opcode(SASTORE, OpcodeGroup.INSN)); + OPCODES.put("POP", new Opcode(POP, OpcodeGroup.INSN)); + OPCODES.put("POP2", new Opcode(POP2, OpcodeGroup.INSN)); + OPCODES.put("DUP", new Opcode(DUP, OpcodeGroup.INSN)); + OPCODES.put("DUP_X1", new Opcode(DUP_X1, OpcodeGroup.INSN)); + OPCODES.put("DUP_X2", new Opcode(DUP_X2, OpcodeGroup.INSN)); + OPCODES.put("DUP2", new Opcode(DUP2, OpcodeGroup.INSN)); + OPCODES.put("DUP2_X1", new Opcode(DUP2_X1, OpcodeGroup.INSN)); + OPCODES.put("DUP2_X2", new Opcode(DUP2_X2, OpcodeGroup.INSN)); + OPCODES.put("SWAP", new Opcode(SWAP, OpcodeGroup.INSN)); + OPCODES.put("IADD", new Opcode(IADD, OpcodeGroup.INSN)); + OPCODES.put("LADD", new Opcode(LADD, OpcodeGroup.INSN)); + OPCODES.put("FADD", new Opcode(FADD, OpcodeGroup.INSN)); + OPCODES.put("DADD", new Opcode(DADD, OpcodeGroup.INSN)); + OPCODES.put("ISUB", new Opcode(ISUB, OpcodeGroup.INSN)); + OPCODES.put("LSUB", new Opcode(LSUB, OpcodeGroup.INSN)); + OPCODES.put("FSUB", new Opcode(FSUB, OpcodeGroup.INSN)); + OPCODES.put("DSUB", new Opcode(DSUB, OpcodeGroup.INSN)); + OPCODES.put("IMUL", new Opcode(IMUL, OpcodeGroup.INSN)); + OPCODES.put("LMUL", new Opcode(LMUL, OpcodeGroup.INSN)); + OPCODES.put("FMUL", new Opcode(FMUL, OpcodeGroup.INSN)); + OPCODES.put("DMUL", new Opcode(DMUL, OpcodeGroup.INSN)); + OPCODES.put("IDIV", new Opcode(IDIV, OpcodeGroup.INSN)); + OPCODES.put("LDIV", new Opcode(LDIV, OpcodeGroup.INSN)); + OPCODES.put("FDIV", new Opcode(FDIV, OpcodeGroup.INSN)); + OPCODES.put("DDIV", new Opcode(DDIV, OpcodeGroup.INSN)); + OPCODES.put("IREM", new Opcode(IREM, OpcodeGroup.INSN)); + OPCODES.put("LREM", new Opcode(LREM, OpcodeGroup.INSN)); + OPCODES.put("FREM", new Opcode(FREM, OpcodeGroup.INSN)); + OPCODES.put("DREM", new Opcode(DREM, OpcodeGroup.INSN)); + OPCODES.put("INEG", new Opcode(INEG, OpcodeGroup.INSN)); + OPCODES.put("LNEG", new Opcode(LNEG, OpcodeGroup.INSN)); + OPCODES.put("FNEG", new Opcode(FNEG, OpcodeGroup.INSN)); + OPCODES.put("DNEG", new Opcode(DNEG, OpcodeGroup.INSN)); + OPCODES.put("ISHL", new Opcode(ISHL, OpcodeGroup.INSN)); + OPCODES.put("LSHL", new Opcode(LSHL, OpcodeGroup.INSN)); + OPCODES.put("ISHR", new Opcode(ISHR, OpcodeGroup.INSN)); + OPCODES.put("LSHR", new Opcode(LSHR, OpcodeGroup.INSN)); + OPCODES.put("IUSHR", new Opcode(IUSHR, OpcodeGroup.INSN)); + OPCODES.put("LUSHR", new Opcode(LUSHR, OpcodeGroup.INSN)); + OPCODES.put("IAND", new Opcode(IAND, OpcodeGroup.INSN)); + OPCODES.put("LAND", new Opcode(LAND, OpcodeGroup.INSN)); + OPCODES.put("IOR", new Opcode(IOR, OpcodeGroup.INSN)); + OPCODES.put("LOR", new Opcode(LOR, OpcodeGroup.INSN)); + OPCODES.put("IXOR", new Opcode(IXOR, OpcodeGroup.INSN)); + OPCODES.put("LXOR", new Opcode(LXOR, OpcodeGroup.INSN)); + OPCODES.put("IINC", new Opcode(IINC, OpcodeGroup.INSN_IINC)); + OPCODES.put("I2L", new Opcode(I2L, OpcodeGroup.INSN)); + OPCODES.put("I2F", new Opcode(I2F, OpcodeGroup.INSN)); + OPCODES.put("I2D", new Opcode(I2D, OpcodeGroup.INSN)); + OPCODES.put("L2I", new Opcode(L2I, OpcodeGroup.INSN)); + OPCODES.put("L2F", new Opcode(L2F, OpcodeGroup.INSN)); + OPCODES.put("L2D", new Opcode(L2D, OpcodeGroup.INSN)); + OPCODES.put("F2I", new Opcode(F2I, OpcodeGroup.INSN)); + OPCODES.put("F2L", new Opcode(F2L, OpcodeGroup.INSN)); + OPCODES.put("F2D", new Opcode(F2D, OpcodeGroup.INSN)); + OPCODES.put("D2I", new Opcode(D2I, OpcodeGroup.INSN)); + OPCODES.put("D2L", new Opcode(D2L, OpcodeGroup.INSN)); + OPCODES.put("D2F", new Opcode(D2F, OpcodeGroup.INSN)); + OPCODES.put("I2B", new Opcode(I2B, OpcodeGroup.INSN)); + OPCODES.put("I2C", new Opcode(I2C, OpcodeGroup.INSN)); + OPCODES.put("I2S", new Opcode(I2S, OpcodeGroup.INSN)); + OPCODES.put("LCMP", new Opcode(LCMP, OpcodeGroup.INSN)); + OPCODES.put("FCMPL", new Opcode(FCMPL, OpcodeGroup.INSN)); + OPCODES.put("FCMPG", new Opcode(FCMPG, OpcodeGroup.INSN)); + OPCODES.put("DCMPL", new Opcode(DCMPL, OpcodeGroup.INSN)); + OPCODES.put("DCMPG", new Opcode(DCMPG, OpcodeGroup.INSN)); + OPCODES.put("IFEQ", new Opcode(IFEQ, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFNE", new Opcode(IFNE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFLT", new Opcode(IFLT, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFGE", new Opcode(IFGE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFGT", new Opcode(IFGT, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFLE", new Opcode(IFLE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPEQ", new Opcode(IF_ICMPEQ, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPNE", new Opcode(IF_ICMPNE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPLT", new Opcode(IF_ICMPLT, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPGE", new Opcode(IF_ICMPGE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPGT", new Opcode(IF_ICMPGT, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ICMPLE", new Opcode(IF_ICMPLE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ACMPEQ", new Opcode(IF_ACMPEQ, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IF_ACMPNE", new Opcode(IF_ACMPNE, OpcodeGroup.INSN_JUMP)); + OPCODES.put("GOTO", new Opcode(GOTO, OpcodeGroup.INSN_JUMP)); + OPCODES.put("JSR", new Opcode(JSR, OpcodeGroup.INSN_JUMP)); + OPCODES.put("RET", new Opcode(RET, OpcodeGroup.INSN_VAR)); + // OPCODES.put( "TABLESWITCH", new Opcode( TABLESWITCH, + // "visiTableSwitchInsn")); + // OPCODES.put( "LOOKUPSWITCH", new Opcode( LOOKUPSWITCH, + // "visitLookupSwitch")); + OPCODES.put("IRETURN", new Opcode(IRETURN, OpcodeGroup.INSN)); + OPCODES.put("LRETURN", new Opcode(LRETURN, OpcodeGroup.INSN)); + OPCODES.put("FRETURN", new Opcode(FRETURN, OpcodeGroup.INSN)); + OPCODES.put("DRETURN", new Opcode(DRETURN, OpcodeGroup.INSN)); + OPCODES.put("ARETURN", new Opcode(ARETURN, OpcodeGroup.INSN)); + OPCODES.put("RETURN", new Opcode(RETURN, OpcodeGroup.INSN)); + OPCODES.put("GETSTATIC", new Opcode(GETSTATIC, OpcodeGroup.INSN_FIELD)); + OPCODES.put("PUTSTATIC", new Opcode(PUTSTATIC, OpcodeGroup.INSN_FIELD)); + OPCODES.put("GETFIELD", new Opcode(GETFIELD, OpcodeGroup.INSN_FIELD)); + OPCODES.put("PUTFIELD", new Opcode(PUTFIELD, OpcodeGroup.INSN_FIELD)); + OPCODES.put("INVOKEVIRTUAL", new Opcode(INVOKEVIRTUAL, + OpcodeGroup.INSN_METHOD)); + OPCODES.put("INVOKESPECIAL", new Opcode(INVOKESPECIAL, + OpcodeGroup.INSN_METHOD)); + OPCODES.put("INVOKESTATIC", new Opcode(INVOKESTATIC, + OpcodeGroup.INSN_METHOD)); + OPCODES.put("INVOKEINTERFACE", new Opcode(INVOKEINTERFACE, + OpcodeGroup.INSN_METHOD)); + OPCODES.put("NEW", new Opcode(NEW, OpcodeGroup.INSN_TYPE)); + OPCODES.put("NEWARRAY", new Opcode(NEWARRAY, OpcodeGroup.INSN_INT)); + OPCODES.put("ANEWARRAY", new Opcode(ANEWARRAY, OpcodeGroup.INSN_TYPE)); + OPCODES.put("ARRAYLENGTH", new Opcode(ARRAYLENGTH, OpcodeGroup.INSN)); + OPCODES.put("ATHROW", new Opcode(ATHROW, OpcodeGroup.INSN)); + OPCODES.put("CHECKCAST", new Opcode(CHECKCAST, OpcodeGroup.INSN_TYPE)); + OPCODES.put("INSTANCEOF", new Opcode(INSTANCEOF, OpcodeGroup.INSN_TYPE)); + OPCODES.put("MONITORENTER", new Opcode(MONITORENTER, OpcodeGroup.INSN)); + OPCODES.put("MONITOREXIT", new Opcode(MONITOREXIT, OpcodeGroup.INSN)); + OPCODES.put("MULTIANEWARRAY", new Opcode(MULTIANEWARRAY, + OpcodeGroup.INSN_MULTIANEWARRAY)); + OPCODES.put("IFNULL", new Opcode(IFNULL, OpcodeGroup.INSN_JUMP)); + OPCODES.put("IFNONNULL", new Opcode(IFNONNULL, OpcodeGroup.INSN_JUMP)); + } + + /** + * Constructs a new {@link ASMContentHandler ASMContentHandler} object. + * + * @param os output stream to write generated class. + * @param computeMax <tt>true</tt> if the maximum stack size and the + * maximum number of local variables must be automatically computed. + * This value is passed to {@link ClassWriter ClassWriter} instance. + */ + public ASMContentHandler(OutputStream os, boolean computeMax) { + this.os = os; + this.computeMax = computeMax; + } + + /** + * Returns the bytecode of the class that was build with underneath class + * writer. + * + * @return the bytecode of the class that was build with underneath class + * writer or null if there are no classwriter created. + */ + public byte[] toByteArray() { + return cw == null ? null : cw.toByteArray(); + } + + /** + * Process notification of the start of an XML element being reached. + * + * @param ns - The Namespace URI, or the empty string if the element has no + * Namespace URI or if Namespace processing is not being performed. + * @param localName - The local name (without prefix), or the empty string + * if Namespace processing is not being performed. + * @param qName - The qualified name (with prefix), or the empty string if + * qualified names are not available. + * @param list - The attributes attached to the element. If there are no + * attributes, it shall be an empty Attributes object. + * @exception SAXException if a parsing error is to be reported + */ + public final void startElement( + String ns, + String localName, + String qName, + Attributes list) throws SAXException + { + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if (name == null || name.length() < 1) { + name = qName; + } + + // Compute the current matching rule + StringBuffer sb = new StringBuffer(match); + if (match.length() > 0) { + sb.append('/'); + } + sb.append(name); + match = sb.toString(); + + // Fire "begin" events for all relevant rules + Rule r = (Rule) RULES.match(match); + if (r != null) + r.begin(name, list); + } + + /** + * Process notification of the end of an XML element being reached. + * + * @param ns - The Namespace URI, or the empty string if the element has no + * Namespace URI or if Namespace processing is not being performed. + * @param localName - The local name (without prefix), or the empty string + * if Namespace processing is not being performed. + * @param qName - The qualified XML 1.0 name (with prefix), or the empty + * string if qualified names are not available. + * + * @exception SAXException if a parsing error is to be reported + */ + public final void endElement(String ns, String localName, String qName) + throws SAXException + { + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if (name == null || name.length() < 1) { + name = qName; + } + + // Fire "end" events for all relevant rules in reverse order + Rule r = (Rule) RULES.match(match); + if (r != null) + r.end(name); + + // Recover the previous match expression + int slash = match.lastIndexOf('/'); + if (slash >= 0) { + match = match.substring(0, slash); + } else { + match = ""; + } + } + + /** + * Process notification of the end of a document and write generated + * bytecode into output stream. + * + * @exception SAXException if parsing or writing error is to be reported. + */ + public final void endDocument() throws SAXException { + try { + os.write(cw.toByteArray()); + } catch (IOException ex) { + throw new SAXException(ex.toString(), ex); + } + } + + /** + * Return the top object on the stack without removing it. If there are no + * objects on the stack, return <code>null</code>. + * + * @return the top object on the stack without removing it. + */ + final Object peek() { + return stack.size() == 0 ? null : stack.get(stack.size() - 1); + } + + /** + * Return the n'th object down the stack, where 0 is the top element and + * [getCount()-1] is the bottom element. If the specified index is out of + * range, return <code>null</code>. + * + * @param n Index of the desired element, where 0 is the top of the stack, 1 + * is the next element down, and so on. + * @return the n'th object down the stack. + */ + final Object peek(int n) { + return stack.size() < (n + 1) ? null : stack.get(n); + } + + /** + * Pop the top object off of the stack, and return it. If there are no + * objects on the stack, return <code>null</code>. + * + * @return the top object off of the stack. + */ + final Object pop() { + return stack.size() == 0 ? null : stack.remove(stack.size() - 1); + } + + /** + * Push a new object onto the top of the object stack. + * + * @param object The new object + */ + final void push(Object object) { + stack.add(object); + } + + private static final class RuleSet { + private Map rules = new HashMap(); + + private List lpatterns = new ArrayList(); + + private List rpatterns = new ArrayList(); + + public void add(String path, Object rule) { + String pattern = path; + if (path.startsWith("*/")) { + pattern = path.substring(1); + lpatterns.add(pattern); + } else if (path.endsWith("/*")) { + pattern = path.substring(0, path.length() - 1); + rpatterns.add(pattern); + } + rules.put(pattern, rule); + } + + public Object match(String path) { + if (rules.containsKey(path)) { + return rules.get(path); + } + + int n = path.lastIndexOf('/'); + for (Iterator it = lpatterns.iterator(); it.hasNext();) { + String pattern = (String) it.next(); + if (path.substring(n).endsWith(pattern)) { + return rules.get(pattern); + } + } + + for (Iterator it = rpatterns.iterator(); it.hasNext();) { + String pattern = (String) it.next(); + if (path.startsWith(pattern)) { + return rules.get(pattern); + } + } + + return null; + } + + } + + /** + * Rule + */ + protected abstract class Rule { + + public void begin(String name, Attributes attrs) { + } + + public void end(String name) { + } + + protected final Object getValue(String desc, String val) { + Object value = null; + if (val != null) { + if (desc.equals("Ljava/lang/String;")) { + value = decode(val); + } else if ("Ljava/lang/Integer;".equals(desc) + || "I".equals(desc) || "S".equals(desc) + || "B".equals(desc) || "C".equals(desc) + || desc.equals("Z")) + { + value = new Integer(val); + + } else if ("Ljava/lang/Short;".equals(desc)) { + value = new Short(val); + + } else if ("Ljava/lang/Byte;".equals(desc)) { + value = new Byte(val); + + } else if ("Ljava/lang/Character;".equals(desc)) { + value = new Character(decode(val).charAt(0)); + + } else if ("Ljava/lang/Boolean;".equals(desc)) { + value = Boolean.valueOf(val); + + // } else if ("Ljava/lang/Integer;".equals(desc) + // || desc.equals("I")) + // { + // value = new Integer(val); + // } else if ("Ljava/lang/Character;".equals(desc) + // || desc.equals("C")) + // { + // value = new Character(decode(val).charAt(0)); + // } else if ("Ljava/lang/Short;".equals(desc) || + // desc.equals("S")) + // { + // value = Short.valueOf(val); + // } else if ("Ljava/lang/Byte;".equals(desc) || + // desc.equals("B")) + // { + // value = Byte.valueOf(val); + + } else if ("Ljava/lang/Long;".equals(desc) || desc.equals("J")) + { + value = new Long(val); + } else if ("Ljava/lang/Float;".equals(desc) || desc.equals("F")) + { + value = new Float(val); + } else if ("Ljava/lang/Double;".equals(desc) + || desc.equals("D")) + { + value = new Double(val); + } else if (Type.getDescriptor(Type.class).equals(desc)) { + value = Type.getType(val); + + // } else if ("[I".equals(desc)) { + // value = new int[0]; // TODO + // } else if ("[C".equals(desc)) { + // value = new char[0]; // TODO + // } else if ("[Z".equals(desc)) { + // value = new boolean[0]; // TODO + // } else if ("[S".equals(desc)) { + // value = new short[0]; // TODO + // } else if ("[B".equals(desc)) { + // value = new byte[0]; // TODO + // } else if ("[J".equals(desc)) { + // value = new long[0]; // TODO + // } else if ("[F".equals(desc)) { + // value = new float[0]; // TODO + // } else if ("[D".equals(desc)) { + // value = new double[0]; // TODO + + } else { + throw new RuntimeException("Invalid value:" + val + + " desc:" + desc + " ctx:" + this); + } + } + return value; + } + + private final String decode(String val) { + StringBuffer sb = new StringBuffer(val.length()); + try { + int n = 0; + while (n < val.length()) { + char c = val.charAt(n); + if (c == '\\') { + n++; + c = val.charAt(n); + if (c == '\\') { + sb.append('\\'); + } else { + n++; // skip 'u' + sb.append((char) Integer.parseInt(val.substring(n, + n + 4), 16)); + n += 3; + } + } else { + sb.append(c); + } + n++; + } + + } catch (RuntimeException ex) { + System.err.println(val + "\n" + ex.toString()); + ex.printStackTrace(); + throw ex; + } + return sb.toString(); + } + + protected final Label getLabel(Object label) { + Label lbl = (Label) labels.get(label); + if (lbl == null) { + lbl = new Label(); + labels.put(label, lbl); + } + return lbl; + } + + // TODO verify move to stack + protected final MethodVisitor getCodeVisitor() { + return (MethodVisitor) peek(); + } + + protected final int getAccess(String s) { + int access = 0; + if (s.indexOf("public") != -1) + access |= Opcodes.ACC_PUBLIC; + if (s.indexOf("private") != -1) + access |= Opcodes.ACC_PRIVATE; + if (s.indexOf("protected") != -1) + access |= Opcodes.ACC_PROTECTED; + if (s.indexOf("static") != -1) + access |= Opcodes.ACC_STATIC; + if (s.indexOf("final") != -1) + access |= Opcodes.ACC_FINAL; + if (s.indexOf("super") != -1) + access |= Opcodes.ACC_SUPER; + if (s.indexOf("synchronized") != -1) + access |= Opcodes.ACC_SYNCHRONIZED; + if (s.indexOf("volatile") != -1) + access |= Opcodes.ACC_VOLATILE; + if (s.indexOf("bridge") != -1) + access |= Opcodes.ACC_BRIDGE; + if (s.indexOf("varargs") != -1) + access |= Opcodes.ACC_VARARGS; + if (s.indexOf("transient") != -1) + access |= Opcodes.ACC_TRANSIENT; + if (s.indexOf("native") != -1) + access |= Opcodes.ACC_NATIVE; + if (s.indexOf("interface") != -1) + access |= Opcodes.ACC_INTERFACE; + if (s.indexOf("abstract") != -1) + access |= Opcodes.ACC_ABSTRACT; + if (s.indexOf("strict") != -1) + access |= Opcodes.ACC_STRICT; + if (s.indexOf("synthetic") != -1) + access |= Opcodes.ACC_SYNTHETIC; + if (s.indexOf("annotation") != -1) + access |= Opcodes.ACC_ANNOTATION; + if (s.indexOf("enum") != -1) + access |= Opcodes.ACC_ENUM; + if (s.indexOf("deprecated") != -1) + access |= Opcodes.ACC_DEPRECATED; + return access; + } + + } + + /** + * ClassRule + */ + private final class ClassRule extends Rule { + + public final void begin(String name, Attributes attrs) { + int major = Integer.parseInt(attrs.getValue("major")); + int minor = Integer.parseInt(attrs.getValue("minor")); + cw = new ClassWriter(computeMax); + Map vals = new HashMap(); + vals.put("version", new Integer(minor << 16 | major)); + vals.put("access", attrs.getValue("access")); + vals.put("name", attrs.getValue("name")); + vals.put("parent", attrs.getValue("parent")); + vals.put("source", attrs.getValue("source")); + vals.put("signature", attrs.getValue("signature")); + vals.put("interfaces", new ArrayList()); + push(vals); + // values will be extracted in InterfacesRule.end(); + } + + } + + private final class SourceRule extends Rule { + + public void begin(String name, Attributes attrs) { + String file = attrs.getValue("file"); + String debug = attrs.getValue("debug"); + cw.visitSource(file, debug); + } + + } + + /** + * InterfaceRule + */ + private final class InterfaceRule extends Rule { + + public final void begin(String name, Attributes attrs) { + ((List) ((Map) peek()).get("interfaces")).add(attrs.getValue("name")); + } + + } + + /** + * InterfacesRule + */ + private final class InterfacesRule extends Rule { + + public final void end(String element) { + Map vals = (Map) pop(); + int version = ((Integer) vals.get("version")).intValue(); + int access = getAccess((String) vals.get("access")); + String name = (String) vals.get("name"); + String signature = (String) vals.get("signature"); + String parent = (String) vals.get("parent"); + List infs = (List) vals.get("interfaces"); + String[] interfaces = (String[]) infs.toArray(new String[infs.size()]); + cw.visit(version, access, name, signature, parent, interfaces); + push(cw); + } + + } + + /** + * OuterClassRule + */ + private final class OuterClassRule extends Rule { + + public final void begin(String element, Attributes attrs) { + String owner = attrs.getValue("owner"); + String name = attrs.getValue("name"); + String desc = attrs.getValue("desc"); + cw.visitOuterClass(owner, name, desc); + } + + } + + /** + * InnerClassRule + */ + private final class InnerClassRule extends Rule { + + public final void begin(String element, Attributes attrs) { + int access = getAccess(attrs.getValue("access")); + String name = attrs.getValue("name"); + String outerName = attrs.getValue("outerName"); + String innerName = attrs.getValue("innerName"); + cw.visitInnerClass(name, outerName, innerName, access); + } + + } + + /** + * FieldRule + */ + private final class FieldRule extends Rule { + + public final void begin(String element, Attributes attrs) { + int access = getAccess(attrs.getValue("access")); + String name = attrs.getValue("name"); + String signature = attrs.getValue("signature"); + String desc = attrs.getValue("desc"); + Object value = getValue(desc, attrs.getValue("value")); + push(cw.visitField(access, name, desc, signature, value)); + } + + public void end(String name) { + ((FieldVisitor) pop()).visitEnd(); + } + + } + + /** + * MethodRule + */ + private final class MethodRule extends Rule { + + public final void begin(String name, Attributes attrs) { + labels = new HashMap(); + Map vals = new HashMap(); + vals.put("access", attrs.getValue("access")); + vals.put("name", attrs.getValue("name")); + vals.put("desc", attrs.getValue("desc")); + vals.put("signature", attrs.getValue("signature")); + vals.put("exceptions", new ArrayList()); + push(vals); + // values will be extracted in ExceptionsRule.end(); + } + + public final void end(String name) { + ((MethodVisitor) pop()).visitEnd(); + labels = null; + } + + } + + /** + * ExceptionRule + */ + private final class ExceptionRule extends Rule { + + public final void begin(String name, Attributes attrs) { + ((List) ((Map) peek()).get("exceptions")).add(attrs.getValue("name")); + } + + } + + /** + * ExceptionsRule + */ + private final class ExceptionsRule extends Rule { + + public final void end(String element) { + Map vals = (Map) pop(); + int access = getAccess((String) vals.get("access")); + String name = (String) vals.get("name"); + String desc = (String) vals.get("desc"); + String signature = (String) vals.get("signature"); + List excs = (List) vals.get("exceptions"); + String[] exceptions = (String[]) excs.toArray(new String[excs.size()]); + + push(cw.visitMethod(access, name, desc, signature, exceptions)); + } + + } + + /** + * TableSwitchRule + */ + private class TableSwitchRule extends Rule { + + public final void begin(String name, Attributes attrs) { + Map vals = new HashMap(); + vals.put("min", attrs.getValue("min")); + vals.put("max", attrs.getValue("max")); + vals.put("dflt", attrs.getValue("dflt")); + vals.put("labels", new ArrayList()); + push(vals); + } + + public final void end(String name) { + Map vals = (Map) pop(); + int min = Integer.parseInt((String) vals.get("min")); + int max = Integer.parseInt((String) vals.get("max")); + Label dflt = getLabel(vals.get("dflt")); + List lbls = (List) vals.get("labels"); + Label[] labels = (Label[]) lbls.toArray(new Label[lbls.size()]); + getCodeVisitor().visitTableSwitchInsn(min, max, dflt, labels); + } + + } + + /** + * TableSwitchLabelRule + */ + private final class TableSwitchLabelRule extends Rule { + + public final void begin(String name, Attributes attrs) { + ((List) ((Map) peek()).get("labels")).add(getLabel(attrs.getValue("name"))); + } + + } + + /** + * LookupSwitchRule + */ + private final class LookupSwitchRule extends Rule { + + public final void begin(String name, Attributes attrs) { + Map vals = new HashMap(); + vals.put("dflt", attrs.getValue("dflt")); + vals.put("labels", new ArrayList()); + vals.put("keys", new ArrayList()); + push(vals); + } + + public final void end(String name) { + Map vals = (Map) pop(); + Label dflt = getLabel(vals.get("dflt")); + List keyList = (List) vals.get("keys"); + List lbls = (List) vals.get("labels"); + Label[] labels = (Label[]) lbls.toArray(new Label[lbls.size()]); + int[] keys = new int[keyList.size()]; + for (int i = 0; i < keys.length; i++) { + keys[i] = Integer.parseInt((String) keyList.get(i)); + } + getCodeVisitor().visitLookupSwitchInsn(dflt, keys, labels); + } + + } + + /** + * LookupSwitchLabelRule + */ + private final class LookupSwitchLabelRule extends Rule { + + public final void begin(String name, Attributes attrs) { + Map vals = (Map) peek(); + ((List) vals.get("labels")).add(getLabel(attrs.getValue("name"))); + ((List) vals.get("keys")).add(attrs.getValue("key")); + } + + } + + /** + * LabelRule + */ + private final class LabelRule extends Rule { + + public final void begin(String name, Attributes attrs) { + getCodeVisitor().visitLabel(getLabel(attrs.getValue("name"))); + } + + } + + /** + * TryCatchRule + */ + private final class TryCatchRule extends Rule { + + public final void begin(String name, Attributes attrs) { + Label start = getLabel(attrs.getValue("start")); + Label end = getLabel(attrs.getValue("end")); + Label handler = getLabel(attrs.getValue("handler")); + String type = attrs.getValue("type"); + getCodeVisitor().visitTryCatchBlock(start, end, handler, type); + } + + } + + /** + * LineNumberRule + */ + private final class LineNumberRule extends Rule { + + public final void begin(String name, Attributes attrs) { + int line = Integer.parseInt(attrs.getValue("line")); + Label start = getLabel(attrs.getValue("start")); + getCodeVisitor().visitLineNumber(line, start); + } + + } + + /** + * LocalVarRule + */ + private final class LocalVarRule extends Rule { + + public final void begin(String element, Attributes attrs) { + String name = attrs.getValue("name"); + String desc = attrs.getValue("desc"); + String signature = attrs.getValue("signature"); + Label start = getLabel(attrs.getValue("start")); + Label end = getLabel(attrs.getValue("end")); + int var = Integer.parseInt(attrs.getValue("var")); + getCodeVisitor().visitLocalVariable(name, + desc, + signature, + start, + end, + var); + } + + } + + /** + * OpcodesRule + */ + private final class OpcodesRule extends Rule { + + // public boolean match( String match, String element) { + // return match.startsWith( path) && OPCODES.containsKey( element); + // } + + public final void begin(String element, Attributes attrs) { + Opcode o = ((Opcode) OPCODES.get(element)); + if (o == null) + return; + + switch (o.type) { + case OpcodeGroup.INSN: + getCodeVisitor().visitInsn(o.opcode); + break; + + case OpcodeGroup.INSN_FIELD: + getCodeVisitor().visitFieldInsn(o.opcode, + attrs.getValue("owner"), + attrs.getValue("name"), + attrs.getValue("desc")); + break; + + case OpcodeGroup.INSN_INT: + getCodeVisitor().visitIntInsn(o.opcode, + Integer.parseInt(attrs.getValue("value"))); + break; + + case OpcodeGroup.INSN_JUMP: + getCodeVisitor().visitJumpInsn(o.opcode, + getLabel(attrs.getValue("label"))); + break; + + case OpcodeGroup.INSN_METHOD: + getCodeVisitor().visitMethodInsn(o.opcode, + attrs.getValue("owner"), + attrs.getValue("name"), + attrs.getValue("desc")); + break; + + case OpcodeGroup.INSN_TYPE: + getCodeVisitor().visitTypeInsn(o.opcode, + attrs.getValue("desc")); + break; + + case OpcodeGroup.INSN_VAR: + getCodeVisitor().visitVarInsn(o.opcode, + Integer.parseInt(attrs.getValue("var"))); + break; + + case OpcodeGroup.INSN_IINC: + getCodeVisitor().visitIincInsn(Integer.parseInt(attrs.getValue("var")), + Integer.parseInt(attrs.getValue("inc"))); + break; + + case OpcodeGroup.INSN_LDC: + getCodeVisitor().visitLdcInsn(getValue(attrs.getValue("desc"), + attrs.getValue("cst"))); + break; + + case OpcodeGroup.INSN_MULTIANEWARRAY: + getCodeVisitor().visitMultiANewArrayInsn(attrs.getValue("desc"), + Integer.parseInt(attrs.getValue("dims"))); + break; + + default: + throw new RuntimeException("Invalid element: " + element + + " at " + match); + + } + } + } + + /** + * MaxRule + */ + private final class MaxRule extends Rule { + + public final void begin(String element, Attributes attrs) { + int maxStack = Integer.parseInt(attrs.getValue("maxStack")); + int maxLocals = Integer.parseInt(attrs.getValue("maxLocals")); + getCodeVisitor().visitMaxs(maxStack, maxLocals); + } + + } + + private final class AnnotationRule extends Rule { + + public void begin(String name, Attributes attrs) { + String desc = attrs.getValue("desc"); + boolean visible = Boolean.valueOf(attrs.getValue("visible")) + .booleanValue(); + + Object v = peek(); + if (v instanceof ClassVisitor) { + push(((ClassVisitor) v).visitAnnotation(desc, visible)); + } else if (v instanceof FieldVisitor) { + push(((FieldVisitor) v).visitAnnotation(desc, visible)); + } else if (v instanceof MethodVisitor) { + push(((MethodVisitor) v).visitAnnotation(desc, visible)); + } + } + + public void end(String name) { + ((AnnotationVisitor) pop()).visitEnd(); + } + + } + + private final class AnnotationParameterRule extends Rule { + + public void begin(String name, Attributes attrs) { + int parameter = Integer.parseInt(attrs.getValue("parameter")); + String desc = attrs.getValue("desc"); + boolean visible = Boolean.valueOf(attrs.getValue("visible")) + .booleanValue(); + + push(((MethodVisitor) peek()).visitParameterAnnotation(parameter, + desc, + visible)); + } + + public void end(String name) { + ((AnnotationVisitor) pop()).visitEnd(); + } + + } + + private final class AnnotationValueRule extends Rule { + + public void begin(String nm, Attributes attrs) { + String name = attrs.getValue("name"); + String desc = attrs.getValue("desc"); + String value = attrs.getValue("value"); + ((AnnotationVisitor) peek()).visit(name, getValue(desc, value)); + } + + } + + private final class AnnotationValueEnumRule extends Rule { + + public void begin(String nm, Attributes attrs) { + String name = attrs.getValue("name"); + String desc = attrs.getValue("desc"); + String value = attrs.getValue("value"); + ((AnnotationVisitor) peek()).visitEnum(name, desc, value); + } + + } + + private final class AnnotationValueAnnotationRule extends Rule { + + public void begin(String nm, Attributes attrs) { + String name = attrs.getValue("name"); + String desc = attrs.getValue("desc"); + push(((AnnotationVisitor) peek()).visitAnnotation(name, desc)); + } + + public void end(String name) { + ((AnnotationVisitor) pop()).visitEnd(); + } + + } + + private final class AnnotationValueArrayRule extends Rule { + + public void begin(String nm, Attributes attrs) { + String name = attrs.getValue("name"); + push(((AnnotationVisitor) peek()).visitArray(name)); + } + + public void end(String name) { + ((AnnotationVisitor) pop()).visitEnd(); + } + + } + + private final class AnnotationDefaultRule extends Rule { + + public void begin(String nm, Attributes attrs) { + push(((MethodVisitor) peek()).visitAnnotationDefault()); + } + + public void end(String name) { + ((AnnotationVisitor) pop()).visitEnd(); + } + + } + + /** + * Opcode + */ + private final static class Opcode { + public int opcode; + + public int type; + + public Opcode(int opcode, int type) { + this.opcode = opcode; + this.type = type; + } + + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/Processor.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/Processor.java new file mode 100644 index 000000000..28bf2ec95 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/Processor.java @@ -0,0 +1,1048 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamSource; + +import org.objectweb.asm.ClassReader; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * Processor is a command line tool that can be used for bytecode waving + * directed by XSL transformation. <p> In order to use a concrete XSLT engine, + * system property <tt>javax.xml.transform.TransformerFactory</tt> must be set + * to one of the following values. + * + * <blockquote> <table border="1" cellspacing="0" cellpadding="3"> <tr> <td>jd.xslt</td> + * <td>jd.xml.xslt.trax.TransformerFactoryImpl</td> </tr> + * + * <tr> <td>Saxon</td> <td>net.sf.saxon.TransformerFactoryImpl</td> </tr> + * + * <tr> <td>Caucho</td> <td>com.caucho.xsl.Xsl</td> </tr> + * + * <tr> <td>Xalan interpeter</td> <td>org.apache.xalan.processor.TransformerFactory</td> + * </tr> + * + * <tr> <td>Xalan xsltc</td> <td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td> + * </tr> </table> </blockquote> + * + * @author Eugene Kuleshov + */ +public class Processor { + + public static final int BYTECODE = 1; + + public static final int MULTI_XML = 2; + + public static final int SINGLE_XML = 3; + + private static final String SINGLE_XML_NAME = "classes.xml"; + + private int inRepresentation; + + private int outRepresentation; + + private InputStream input = null; + + private OutputStream output = null; + + private Source xslt = null; + + private boolean computeMax; + + private int n = 0; + + public Processor( + int inRepresenation, + int outRepresentation, + InputStream input, + OutputStream output, + Source xslt) + { + this.inRepresentation = inRepresenation; + this.outRepresentation = outRepresentation; + this.input = input; + this.output = output; + this.xslt = xslt; + this.computeMax = true; + } + + public int process() throws TransformerException, IOException, SAXException + { + ZipInputStream zis = new ZipInputStream(input); + final ZipOutputStream zos = new ZipOutputStream(output); + final OutputStreamWriter osw = new OutputStreamWriter(zos); + + Thread.currentThread() + .setContextClassLoader(getClass().getClassLoader()); + + TransformerFactory tf = TransformerFactory.newInstance(); + if (!tf.getFeature(SAXSource.FEATURE) + || !tf.getFeature(SAXResult.FEATURE)) + return 0; + + SAXTransformerFactory saxtf = (SAXTransformerFactory) tf; + Templates templates = null; + if (xslt != null) { + templates = saxtf.newTemplates(xslt); + } + + // configuring outHandlerFactory + // /////////////////////////////////////////////////////// + + EntryElement entryElement = getEntryElement(zos); + + ContentHandler outDocHandler = null; + switch (outRepresentation) { + case BYTECODE: + outDocHandler = new OutputSlicingHandler(new ASMContentHandlerFactory(zos, + computeMax), + entryElement, + false); + break; + + case MULTI_XML: + outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw, + true), + entryElement, + true); + break; + + case SINGLE_XML: + ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME); + zos.putNextEntry(outputEntry); + outDocHandler = new SAXWriter(osw, false); + break; + + } + + // configuring inputDocHandlerFactory + // ///////////////////////////////////////////////// + ContentHandler inDocHandler = null; + if (templates == null) { + inDocHandler = outDocHandler; + } else { + inDocHandler = new InputSlicingHandler("class", + outDocHandler, + new TransformerHandlerFactory(saxtf, + templates, + outDocHandler)); + } + ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(inDocHandler); + + if (inDocHandler != null && inRepresentation != SINGLE_XML) { + inDocHandler.startDocument(); + inDocHandler.startElement("", + "classes", + "classes", + new AttributesImpl()); + } + + int i = 0; + ZipEntry ze = null; + while ((ze = zis.getNextEntry()) != null) { + update(ze.getName(), n++); + if (isClassEntry(ze)) { + processEntry(zis, ze, inDocHandlerFactory); + } else { + OutputStream os = entryElement.openEntry(getName(ze)); + copyEntry(zis, os); + entryElement.closeEntry(); + } + + i++; + } + + if (inDocHandler != null && inRepresentation != SINGLE_XML) { + inDocHandler.endElement("", "classes", "classes"); + inDocHandler.endDocument(); + } + + if (outRepresentation == SINGLE_XML) { + zos.closeEntry(); + } + zos.flush(); + zos.close(); + + return i; + } + + private void copyEntry(InputStream is, OutputStream os) throws IOException { + if (outRepresentation == SINGLE_XML) + return; + + byte[] buff = new byte[2048]; + int i; + while ((i = is.read(buff)) != -1) { + os.write(buff, 0, i); + } + } + + private boolean isClassEntry(ZipEntry ze) { + String name = ze.getName(); + return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME) + || name.endsWith(".class") || name.endsWith(".class.xml"); + } + + private void processEntry( + final ZipInputStream zis, + ZipEntry ze, + ContentHandlerFactory handlerFactory) + { + ContentHandler handler = handlerFactory.createContentHandler(); + try { + + // if (CODE2ASM.equals(command)) { // read bytecode and process it + // // with TraceClassVisitor + // ClassReader cr = new ClassReader(readEntry(zis, ze)); + // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)), + // false); + // } + + boolean singleInputDocument = inRepresentation == SINGLE_XML; + if (inRepresentation == BYTECODE) { // read bytecode and process it + // with handler + ClassReader cr = new ClassReader(readEntry(zis, ze)); + cr.accept(new SAXClassAdapter(handler, singleInputDocument), + false); + + } else { // read XML and process it with handler + XMLReader reader = XMLReaderFactory.createXMLReader(); + reader.setContentHandler(handler); + reader.parse(new InputSource(singleInputDocument + ? (InputStream) new ProtectedInputStream(zis) + : new ByteArrayInputStream(readEntry(zis, ze)))); + + } + } catch (Exception ex) { + update(ze.getName(), 0); + update(ex, 0); + } + } + + private EntryElement getEntryElement(ZipOutputStream zos) { + if (outRepresentation == SINGLE_XML) { + return new SingleDocElement(zos); + } + return new ZipEntryElement(zos); + } + + // private ContentHandlerFactory getHandlerFactory( + // OutputStream os, + // SAXTransformerFactory saxtf, + // Templates templates) + // { + // ContentHandlerFactory factory = null; + // if (templates == null) { + // if (outputRepresentation == BYTECODE) { // factory used to write + // // bytecode + // factory = new ASMContentHandlerFactory(os, computeMax); + // } else { // factory used to write XML + // factory = new SAXWriterFactory(os, true); + // } + // } else { + // if (outputRepresentation == BYTECODE) { // factory used to transform + // // and then write bytecode + // factory = new ASMTransformerHandlerFactory(saxtf, + // templates, + // os, + // computeMax); + // } else { // factory used to transformand then write XML + // factory = new TransformerHandlerFactory(saxtf, + // templates, + // os, + // outputRepresentation == SINGLE_XML); + // } + // } + // return factory; + // } + + private String getName(ZipEntry ze) { + String name = ze.getName(); + if (isClassEntry(ze)) { + if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) { + name = name.substring(0, name.length() - 4); // .class.xml to + // .class + } else if (inRepresentation == BYTECODE + && outRepresentation != BYTECODE) + { + name = name.concat(".xml"); // .class to .class.xml + } + // } else if( CODE2ASM.equals( command)) { + // name = name.substring( 0, name.length()-6).concat( ".asm"); + } + return name; + } + + private byte[] readEntry(ZipInputStream zis, ZipEntry ze) + throws IOException + { + long size = ze.getSize(); + if (size > -1) { + byte[] buff = new byte[(int) size]; + int k = 0; + int n; + while(( n = zis.read(buff, k, buff.length-k)) > 0) { + k += n; + } + return buff; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buff = new byte[4096]; + int i; + while ((i = zis.read(buff)) != -1) { + bos.write(buff, 0, i); + } + return bos.toByteArray(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + protected void update(Object arg, int n) { + if (arg instanceof Throwable) { + ((Throwable) arg).printStackTrace(); + } else { + if ((n % 100) == 0) { + System.err.println(n + " " + arg); + } + } + } + + public static void main(String[] args) throws Exception { + if (args.length < 2) { + showUsage(); + return; + } + + int inRepresentation = getRepresentation(args[0]); + int outRepresentation = getRepresentation(args[1]); + + InputStream is = System.in; + OutputStream os = new BufferedOutputStream(System.out); + + Source xslt = null; + // boolean computeMax = true; + + for (int i = 2; i < args.length; i++) { + if ("-in".equals(args[i])) { + is = new FileInputStream(args[++i]); + + } else if ("-out".equals(args[i])) { + os = new BufferedOutputStream(new FileOutputStream(args[++i])); + + } else if ("-xslt".equals(args[i])) { + xslt = new StreamSource(new FileInputStream(args[++i])); + + // } else if( "-computemax".equals( args[ i].toLowerCase())) { + // computeMax = true; + + } else { + showUsage(); + return; + + } + } + + if (inRepresentation == 0 || outRepresentation == 0) { + showUsage(); + return; + } + + Processor m = new Processor(inRepresentation, + outRepresentation, + is, + os, + xslt); + + long l1 = System.currentTimeMillis(); + int n = m.process(); + long l2 = System.currentTimeMillis(); + System.err.println(n); + System.err.println("" + (l2 - l1) + "ms " + (1000f * n / (l2 - l1)) + + " resources/sec"); + } + + private static int getRepresentation(String s) { + if ("code".equals(s)) { + return BYTECODE; + } else if ("xml".equals(s)) { + return MULTI_XML; + } else if ("singlexml".equals(s)) { + return SINGLE_XML; + } + return 0; + } + + private static void showUsage() { + System.err.println("Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt file>]"); + System.err.println(" when -in or -out is omitted sysin and sysout would be used"); + System.err.println(" <in format> and <out format> - code | xml | singlexml"); + } + + /** + * IputStream wrapper class used to protect input streams from being closed + * by some stupid XML parsers. + */ + private static final class ProtectedInputStream extends InputStream { + private final InputStream is; + + private ProtectedInputStream(InputStream is) { + super(); + this.is = is; + } + + public final void close() throws IOException { + } + + public final int read() throws IOException { + return is.read(); + } + + public final int read(byte[] b, int off, int len) throws IOException { + return is.read(b, off, len); + } + + public final int available() throws IOException { + return is.available(); + } + } + + /** + * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create + * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete + * context. + */ + private static interface ContentHandlerFactory { + + /** + * Creates an instance of the content handler. + * + * @return content handler + */ + ContentHandler createContentHandler(); + + } + + /** + * SAXWriterFactory + */ + private static final class SAXWriterFactory implements + ContentHandlerFactory + { + private Writer w; + + private boolean optimizeEmptyElements; + + public SAXWriterFactory(Writer w, boolean optimizeEmptyElements) { + this.w = w; + this.optimizeEmptyElements = optimizeEmptyElements; + } + + public final ContentHandler createContentHandler() { + return new SAXWriter(w, optimizeEmptyElements); + } + + } + + /** + * ASMContentHandlerFactory + */ + private static final class ASMContentHandlerFactory implements + ContentHandlerFactory + { + private OutputStream os; + + private boolean computeMax; + + public ASMContentHandlerFactory(OutputStream os, boolean computeMax) { + this.os = os; + this.computeMax = computeMax; + } + + public final ContentHandler createContentHandler() { + return new ASMContentHandler(os, computeMax); + } + + } + + /** + * TransformerHandlerFactory + */ + private static final class TransformerHandlerFactory implements + ContentHandlerFactory + { + private SAXTransformerFactory saxtf; + + private Templates templates; + + private ContentHandler outputHandler; + + public TransformerHandlerFactory( + SAXTransformerFactory saxtf, + Templates templates, + ContentHandler outputHandler) + { + this.saxtf = saxtf; + this.templates = templates; + this.outputHandler = outputHandler; + } + + public final ContentHandler createContentHandler() { + try { + TransformerHandler handler = saxtf.newTransformerHandler(templates); + handler.setResult(new SAXResult(outputHandler)); + return handler; + } catch (TransformerConfigurationException ex) { + throw new RuntimeException(ex.toString()); + } + } + } + + /** + * SubdocumentHandlerFactory + */ + private final static class SubdocumentHandlerFactory implements + ContentHandlerFactory + { + private ContentHandler subdocumentHandler; + + public SubdocumentHandlerFactory(ContentHandler subdocumentHandler) { + this.subdocumentHandler = subdocumentHandler; + } + + public final ContentHandler createContentHandler() { + return subdocumentHandler; + } + + } + + /** + * A {@link org.xml.sax.ContentHandler ContentHandler} and + * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML + * from SAX 2.0 events into {@link java.io.Writer Writer}. + * + * <i><blockquote> This implementation does not support namespaces, entity + * definitions (uncluding DTD), CDATA and text elements. </blockquote></i> + */ + private final static class SAXWriter extends DefaultHandler implements + LexicalHandler + { + private static final char[] OFF = " ".toCharArray(); + + private Writer w; + + private boolean optimizeEmptyElements; + + private boolean openElement = false; + + private int ident = 0; + + /** + * Creates <code>SAXWriter</code>. + * + * @param w writer + * @param optimizeEmptyElements if set to <code>true</code>, short + * XML syntax will be used for empty elements + */ + public SAXWriter(Writer w, boolean optimizeEmptyElements) { + this.w = w; + this.optimizeEmptyElements = optimizeEmptyElements; + } + + public final void startElement( + String ns, + String localName, + String qName, + Attributes atts) throws SAXException + { + try { + closeElement(); + + writeIdent(); + w.write("<".concat(qName)); + if (atts != null && atts.getLength() > 0) + writeAttributes(atts); + + if (!optimizeEmptyElements) { + w.write(">\n"); + } else { + openElement = true; + } + ident += 2; + + } catch (IOException ex) { + throw new SAXException(ex); + + } + } + + public final void endElement(String ns, String localName, String qName) + throws SAXException + { + ident -= 2; + try { + if (openElement) { + w.write("/>\n"); + openElement = false; + } else { + writeIdent(); + w.write("</" + qName + ">\n"); + } + + } catch (IOException ex) { + throw new SAXException(ex); + + } + } + + public final void endDocument() throws SAXException { + try { + w.flush(); + + } catch (IOException ex) { + throw new SAXException(ex); + + } + } + + public final void comment(char[] ch, int off, int len) + throws SAXException + { + try { + closeElement(); + + writeIdent(); + w.write("<!-- "); + w.write(ch, off, len); + w.write(" -->\n"); + + } catch (IOException ex) { + throw new SAXException(ex); + + } + } + + public final void startDTD(String arg0, String arg1, String arg2) + throws SAXException + { + } + + public final void endDTD() throws SAXException { + } + + public final void startEntity(String arg0) throws SAXException { + } + + public final void endEntity(String arg0) throws SAXException { + } + + public final void startCDATA() throws SAXException { + } + + public final void endCDATA() throws SAXException { + } + + private final void writeAttributes(Attributes atts) throws IOException { + StringBuffer sb = new StringBuffer(); + int len = atts.getLength(); + for (int i = 0; i < len; i++) { + sb.append(" ") + .append(atts.getLocalName(i)) + .append("=\"") + .append(esc(atts.getValue(i))) + .append("\""); + } + w.write(sb.toString()); + } + + /** + * Encode string with escaping. + * + * @param str string to encode. + * @return encoded string + */ + private final String esc(String str) { + StringBuffer sb = new StringBuffer(str.length()); + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + switch (ch) { + case '&': + sb.append("&"); + break; + + case '<': + sb.append("<"); + break; + + case '>': + sb.append(">"); + break; + + case '\"': + sb.append("""); + break; + + default: + if (ch > 0x7f) { + sb.append("&#") + .append(Integer.toString(ch)) + .append(';'); + } else { + sb.append(ch); + } + + } + } + return sb.toString(); + } + + private final void writeIdent() throws IOException { + int n = ident; + while (n > 0) { + if (n > OFF.length) { + w.write(OFF); + n -= OFF.length; + } else { + w.write(OFF, 0, n); + n = 0; + } + } + } + + private final void closeElement() throws IOException { + if (openElement) { + w.write(">\n"); + } + openElement = false; + } + + } + + /** + * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML + * documents into smaller chunks. Each chunk is processed by the nested + * {@link org.xml.sax.ContentHandler ContentHandler} obtained from + * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is + * useful for running XSLT engine against large XML document that will + * hardly fit into the memory all together. <p> TODO use complete path for + * subdocumentRoot + */ + private final static class InputSlicingHandler extends DefaultHandler { + private String subdocumentRoot; + + private ContentHandler rootHandler; + + private ContentHandlerFactory subdocumentHandlerFactory; + + private boolean subdocument = false; + + private ContentHandler subdocumentHandler; + + /** + * Constructs a new {@link InputSlicingHandler SubdocumentHandler} + * object. + * + * @param subdocumentRoot name/path to the root element of the + * subdocument + * @param rootHandler content handler for the entire document + * (subdocument envelope). + * @param subdocumentHandlerFactory a + * {@link ContentHandlerFactory ContentHandlerFactory} used to + * create {@link ContentHandler ContentHandler} instances for + * subdocuments. + */ + public InputSlicingHandler( + String subdocumentRoot, + ContentHandler rootHandler, + ContentHandlerFactory subdocumentHandlerFactory) + { + this.subdocumentRoot = subdocumentRoot; + this.rootHandler = rootHandler; + this.subdocumentHandlerFactory = subdocumentHandlerFactory; + } + + public final void startElement( + String namespaceURI, + String localName, + String qName, + Attributes list) throws SAXException + { + if (subdocument) { + subdocumentHandler.startElement(namespaceURI, + localName, + qName, + list); + } else if (localName.equals(subdocumentRoot)) { + subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); + subdocumentHandler.startDocument(); + subdocumentHandler.startElement(namespaceURI, + localName, + qName, + list); + subdocument = true; + } else if (rootHandler != null) { + rootHandler.startElement(namespaceURI, localName, qName, list); + } + } + + public final void endElement( + String namespaceURI, + String localName, + String qName) throws SAXException + { + if (subdocument) { + subdocumentHandler.endElement(namespaceURI, localName, qName); + if (localName.equals(subdocumentRoot)) { + subdocumentHandler.endDocument(); + subdocument = false; + } + } else if (rootHandler != null) { + rootHandler.endElement(namespaceURI, localName, qName); + } + } + + public final void startDocument() throws SAXException { + if (rootHandler != null) { + rootHandler.startDocument(); + } + } + + public final void endDocument() throws SAXException { + if (rootHandler != null) { + rootHandler.endDocument(); + + } + } + + public final void characters(char[] buff, int offset, int size) + throws SAXException + { + if (subdocument) { + subdocumentHandler.characters(buff, offset, size); + } else if (rootHandler != null) { + rootHandler.characters(buff, offset, size); + } + } + + } + + /** + * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML + * documents into smaller chunks. Each chunk is processed by the nested + * {@link org.xml.sax.ContentHandler ContentHandler} obtained from + * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is + * useful for running XSLT engine against large XML document that will + * hardly fit into the memory all together. <p> TODO use complete path for + * subdocumentRoot + */ + private static final class OutputSlicingHandler extends DefaultHandler { + private String subdocumentRoot; + + private ContentHandlerFactory subdocumentHandlerFactory; + + private EntryElement entryElement; + + private boolean isXml; + + private boolean subdocument = false; + + private ContentHandler subdocumentHandler; + + /** + * Constructs a new {@link OutputSlicingHandler SubdocumentHandler} + * object. + * + * @param subdocumentHandlerFactory a + * {@link ContentHandlerFactory ContentHandlerFactory} used to + * create {@link ContentHandler ContentHandler} instances for + * subdocuments. + * @param entryElement TODO. + * @param isXml TODO. + */ + public OutputSlicingHandler( + ContentHandlerFactory subdocumentHandlerFactory, + EntryElement entryElement, + boolean isXml) + { + this.subdocumentRoot = "class"; + this.subdocumentHandlerFactory = subdocumentHandlerFactory; + this.entryElement = entryElement; + this.isXml = isXml; + } + + public final void startElement( + String namespaceURI, + String localName, + String qName, + Attributes list) throws SAXException + { + if (subdocument) { + subdocumentHandler.startElement(namespaceURI, + localName, + qName, + list); + } else if (localName.equals(subdocumentRoot)) { + String name = list.getValue("name"); + if (name == null || name.length() == 0) + throw new SAXException("Class element without name attribute."); + try { + entryElement.openEntry(isXml + ? name.concat(".class.xml") + : name.concat(".class")); + } catch (IOException ex) { + throw new SAXException(ex.toString(), ex); + } + subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); + subdocumentHandler.startDocument(); + subdocumentHandler.startElement(namespaceURI, + localName, + qName, + list); + subdocument = true; + } + } + + public final void endElement( + String namespaceURI, + String localName, + String qName) throws SAXException + { + if (subdocument) { + subdocumentHandler.endElement(namespaceURI, localName, qName); + if (localName.equals(subdocumentRoot)) { + subdocumentHandler.endDocument(); + subdocument = false; + try { + entryElement.closeEntry(); + } catch (IOException ex) { + throw new SAXException(ex.toString(), ex); + } + } + } + } + + public final void startDocument() throws SAXException { + } + + public final void endDocument() throws SAXException { + } + + public final void characters(char[] buff, int offset, int size) + throws SAXException + { + if (subdocument) { + subdocumentHandler.characters(buff, offset, size); + } + } + + } + + private static interface EntryElement { + + OutputStream openEntry(String name) throws IOException; + + void closeEntry() throws IOException; + + } + + private static final class SingleDocElement implements EntryElement { + private OutputStream os; + + public SingleDocElement(OutputStream os) { + this.os = os; + } + + public OutputStream openEntry(String name) throws IOException { + return os; + } + + public void closeEntry() throws IOException { + os.flush(); + } + + } + + private static final class ZipEntryElement implements EntryElement { + private ZipOutputStream zos; + + public ZipEntryElement(ZipOutputStream zos) { + this.zos = zos; + } + + public OutputStream openEntry(String name) throws IOException { + ZipEntry entry = new ZipEntry(name); + zos.putNextEntry(entry); + return zos; + } + + public void closeEntry() throws IOException { + zos.flush(); + zos.closeEntry(); + } + + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAdapter.java new file mode 100644 index 000000000..5168fb574 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAdapter.java @@ -0,0 +1,91 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * SAXAdapter + * + * @author Eugene Kuleshov + */ +public abstract class SAXAdapter { + private final ContentHandler h; + + public SAXAdapter(ContentHandler h) { + this.h = h; + } + + protected ContentHandler getContentHandler() { + return h; + } + + protected final void addEnd(String name) { + try { + h.endElement("", name, name); + } catch (SAXException ex) { + throw new RuntimeException(ex.toString()); + } + } + + protected final void addStart(String name, Attributes attrs) { + try { + h.startElement("", name, name, attrs); + } catch (SAXException ex) { + throw new RuntimeException(ex.toString()); + } + } + + protected final void addElement(String name, Attributes attrs) { + addStart(name, attrs); + addEnd(name); + } + + protected void addDocumentStart() { + try { + h.startDocument(); + } catch (SAXException ex) { + throw new RuntimeException(ex.getException()); + } + } + + protected void addDocumentEnd() { + try { + h.endDocument(); + } catch (SAXException ex) { + // ex.getException().printStackTrace(); + // ex.printStackTrace(); + throw new RuntimeException(ex.toString()); + } + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAnnotationAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAnnotationAdapter.java new file mode 100644 index 000000000..6e9605c93 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXAnnotationAdapter.java @@ -0,0 +1,191 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; +import org.xml.sax.ContentHandler; +import org.xml.sax.helpers.AttributesImpl; + +/** + * SAXAnnotationAdapter + * + * @author Eugene Kuleshov + */ +public class SAXAnnotationAdapter extends SAXAdapter implements + AnnotationVisitor +{ + private final String elementName; + + public SAXAnnotationAdapter( + ContentHandler h, + String elementName, + int visible, + String name, + String desc) + { + this(h, elementName, visible, desc, name, -1); + } + + public SAXAnnotationAdapter( + ContentHandler h, + String elementName, + int visible, + int parameter, + String desc) + { + this(h, elementName, visible, desc, null, parameter); + } + + private SAXAnnotationAdapter( + ContentHandler h, + String elementName, + int visible, + String desc, + String name, + int parameter) + { + super(h); + this.elementName = elementName; + + AttributesImpl att = new AttributesImpl(); + if (name != null) + att.addAttribute("", "name", "name", "", name); + if (visible != 0) + att.addAttribute("", "visible", "visible", "", visible > 0 + ? "true" + : "false"); + if (parameter != -1) + att.addAttribute("", + "parameter", + "parameter", + "", + Integer.toString(parameter)); + if (desc != null) + att.addAttribute("", "desc", "desc", "", desc); + + addStart(elementName, att); + } + + public void visit(String name, Object value) { + Class c = value.getClass(); + if (c.isArray()) { + AnnotationVisitor av = visitArray(name); + if (value instanceof byte[]) { + byte[] b = (byte[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Byte(b[i])); + + } else if (value instanceof char[]) { + char[] b = (char[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Character(b[i])); + + } else if (value instanceof boolean[]) { + boolean[] b = (boolean[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, Boolean.valueOf(b[i])); + + } else if (value instanceof int[]) { + int[] b = (int[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Integer(b[i])); + + } else if (value instanceof long[]) { + long[] b = (long[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Long(b[i])); + + } else if (value instanceof float[]) { + float[] b = (float[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Float(b[i])); + + } else if (value instanceof double[]) { + double[] b = (double[]) value; + for (int i = 0; i < b.length; i++) + av.visit(null, new Double(b[i])); + + } + av.visitEnd(); + } else { + addValueElement("annotationValue", + name, + Type.getDescriptor(c), + value.toString()); + } + } + + public void visitEnum(String name, String desc, String value) { + addValueElement("annotationValueEnum", name, desc, value); + } + + public AnnotationVisitor visitAnnotation(String name, String desc) { + return new SAXAnnotationAdapter(getContentHandler(), + "annotationValueAnnotation", + 0, + name, + desc); + } + + public AnnotationVisitor visitArray(String name) { + return new SAXAnnotationAdapter(getContentHandler(), + "annotationValueArray", + 0, + name, + null); + } + + public void visitEnd() { + addEnd(elementName); + } + + private void addValueElement( + String element, + String name, + String desc, + String value) + { + AttributesImpl att = new AttributesImpl(); + if (name != null) + att.addAttribute("", "name", "name", "", name); + if (desc != null) + att.addAttribute("", "desc", "desc", "", desc); + if (value != null) + att.addAttribute("", + "value", + "value", + "", + SAXClassAdapter.encode(value)); + + addElement(element, att); + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXClassAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXClassAdapter.java new file mode 100644 index 000000000..55b9effe7 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXClassAdapter.java @@ -0,0 +1,351 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +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.xml.sax.ContentHandler; +import org.xml.sax.helpers.AttributesImpl; + +/** + * A {@link org.objectweb.asm.ClassVisitor ClassVisitor} that generates SAX 2.0 + * events from the visited class. It can feed any kind of + * {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT + * or XQuery engines. + * + * @see org.objectweb.asm.xml.Processor + * @see org.objectweb.asm.xml.ASMContentHandler + * + * @author Eugene Kuleshov + */ +public final class SAXClassAdapter extends SAXAdapter implements ClassVisitor { + private boolean singleDocument; + + /** + * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object. + * + * @param h content handler that will be used to send SAX 2.0 events. + * @param singleDocument if <tt>true</tt> adapter will not produce + * {@link ContentHandler#startDocument() startDocument()} and + * {@link ContentHandler#endDocument() endDocument()} events. + */ + public SAXClassAdapter(ContentHandler h, boolean singleDocument) { + super(h); + this.singleDocument = singleDocument; + if (!singleDocument) { + addDocumentStart(); + } + } + + public void visitSource(String source, String debug) { + if (source == null && debug == null) { + return; + } + + AttributesImpl att = new AttributesImpl(); + if (source != null) + att.addAttribute("", "file", "file", "", encode(source)); + if (debug != null) + att.addAttribute("", "debug", "debug", "", encode(debug)); + + addElement("source", att); + } + + public void visitOuterClass(String owner, String name, String desc) { + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "owner", "owner", "", owner); + if (name != null) + att.addAttribute("", "name", "name", "", name); + if (desc != null) + att.addAttribute("", "desc", "desc", "", desc); + + addElement("outerclass", att); + } + + public final void visitAttribute(Attribute attr) { + // TODO Auto-generated SAXClassAdapter.visitAttribute + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new SAXAnnotationAdapter(getContentHandler(), + "annotation", + visible ? 1 : -1, + null, + desc); + } + + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) + { + StringBuffer sb = new StringBuffer(); + if ((access & Opcodes.ACC_PUBLIC) != 0) + sb.append("public "); + if ((access & Opcodes.ACC_PRIVATE) != 0) + sb.append("private "); + if ((access & Opcodes.ACC_PROTECTED) != 0) + sb.append("protected "); + if ((access & Opcodes.ACC_FINAL) != 0) + sb.append("final "); + if ((access & Opcodes.ACC_SUPER) != 0) + sb.append("super "); + if ((access & Opcodes.ACC_INTERFACE) != 0) + sb.append("interface "); + if ((access & Opcodes.ACC_ABSTRACT) != 0) + sb.append("abstract "); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) + sb.append("synthetic "); + if ((access & Opcodes.ACC_ANNOTATION) != 0) + sb.append("annotation "); + if ((access & Opcodes.ACC_ENUM) != 0) + sb.append("enum "); + if ((access & Opcodes.ACC_DEPRECATED) != 0) + sb.append("deprecated "); + + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "access", "access", "", sb.toString()); + if (name != null) + att.addAttribute("", "name", "name", "", name); + if (signature != null) + att.addAttribute("", + "signature", + "signature", + "", + encode(signature)); + if (superName != null) + att.addAttribute("", "parent", "parent", "", superName); + att.addAttribute("", + "major", + "major", + "", + Integer.toString(version & 0xFFFF)); + att.addAttribute("", + "minor", + "minor", + "", + Integer.toString(version >>> 16)); + addStart("class", att); + + addStart("interfaces", new AttributesImpl()); + if (interfaces != null && interfaces.length > 0) { + for (int i = 0; i < interfaces.length; i++) { + AttributesImpl att2 = new AttributesImpl(); + att2.addAttribute("", "name", "name", "", interfaces[i]); + addElement("interface", att2); + } + } + addEnd("interfaces"); + } + + public FieldVisitor visitField( + int access, + String name, + String desc, + String signature, + Object value) + { + StringBuffer sb = new StringBuffer(); + if ((access & Opcodes.ACC_PUBLIC) != 0) + sb.append("public "); + if ((access & Opcodes.ACC_PRIVATE) != 0) + sb.append("private "); + if ((access & Opcodes.ACC_PROTECTED) != 0) + sb.append("protected "); + if ((access & Opcodes.ACC_STATIC) != 0) + sb.append("static "); + if ((access & Opcodes.ACC_FINAL) != 0) + sb.append("final "); + if ((access & Opcodes.ACC_VOLATILE) != 0) + sb.append("volatile "); + if ((access & Opcodes.ACC_TRANSIENT) != 0) + sb.append("transient "); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) + sb.append("synthetic "); + if ((access & Opcodes.ACC_ENUM) != 0) + sb.append("enum "); + if ((access & Opcodes.ACC_DEPRECATED) != 0) + sb.append("deprecated "); + + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "access", "access", "", sb.toString()); + att.addAttribute("", "name", "name", "", name); + att.addAttribute("", "desc", "desc", "", desc); + if (signature != null) + att.addAttribute("", + "signature", + "signature", + "", + encode(signature)); + if (value != null) { + att.addAttribute("", "value", "value", "", encode(value.toString())); + } + + return new SAXFieldAdapter(getContentHandler(), att); + } + + public MethodVisitor visitMethod( + int access, + String name, + String desc, + String signature, + String[] exceptions) + { + StringBuffer sb = new StringBuffer(); + if ((access & Opcodes.ACC_PUBLIC) != 0) + sb.append("public "); + if ((access & Opcodes.ACC_PRIVATE) != 0) + sb.append("private "); + if ((access & Opcodes.ACC_PROTECTED) != 0) + sb.append("protected "); + if ((access & Opcodes.ACC_STATIC) != 0) + sb.append("static "); + if ((access & Opcodes.ACC_FINAL) != 0) + sb.append("final "); + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) + sb.append("synchronized "); + if ((access & Opcodes.ACC_BRIDGE) != 0) + sb.append("bridge "); + if ((access & Opcodes.ACC_VARARGS) != 0) + sb.append("varargs "); + if ((access & Opcodes.ACC_NATIVE) != 0) + sb.append("native "); + if ((access & Opcodes.ACC_ABSTRACT) != 0) + sb.append("abstract "); + if ((access & Opcodes.ACC_STRICT) != 0) + sb.append("strict "); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) + sb.append("synthetic "); + if ((access & Opcodes.ACC_DEPRECATED) != 0) + sb.append("deprecated "); + + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "access", "access", "", sb.toString()); + att.addAttribute("", "name", "name", "", name); + att.addAttribute("", "desc", "desc", "", desc); + if (signature != null) { + att.addAttribute("", "signature", "signature", "", signature); + } + addStart("method", att); + + addStart("exceptions", new AttributesImpl()); + if (exceptions != null && exceptions.length > 0) { + for (int i = 0; i < exceptions.length; i++) { + AttributesImpl att2 = new AttributesImpl(); + att2.addAttribute("", "name", "name", "", exceptions[i]); + addElement("exception", att2); + } + } + addEnd("exceptions"); + + return new SAXCodeAdapter(getContentHandler(), access); + } + + public final void visitInnerClass( + String name, + String outerName, + String innerName, + int access) + { + StringBuffer sb = new StringBuffer(); + if ((access & Opcodes.ACC_PUBLIC) != 0) + sb.append("public "); + if ((access & Opcodes.ACC_PRIVATE) != 0) + sb.append("private "); + if ((access & Opcodes.ACC_PROTECTED) != 0) + sb.append("protected "); + if ((access & Opcodes.ACC_STATIC) != 0) + sb.append("static "); + if ((access & Opcodes.ACC_FINAL) != 0) + sb.append("final "); + if ((access & Opcodes.ACC_SUPER) != 0) + sb.append("super "); + if ((access & Opcodes.ACC_INTERFACE) != 0) + sb.append("interface "); + if ((access & Opcodes.ACC_ABSTRACT) != 0) + sb.append("abstract "); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) + sb.append("synthetic "); + if ((access & Opcodes.ACC_ANNOTATION) != 0) + sb.append("annotation "); + if ((access & Opcodes.ACC_ENUM) != 0) + sb.append("enum "); + if ((access & Opcodes.ACC_DEPRECATED) != 0) + sb.append("deprecated "); + + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "access", "access", "", sb.toString()); + if (name != null) + att.addAttribute("", "name", "name", "", name); + if (outerName != null) + att.addAttribute("", "outerName", "outerName", "", outerName); + if (innerName != null) + att.addAttribute("", "innerName", "innerName", "", innerName); + addElement("innerclass", att); + } + + public final void visitEnd() { + addEnd("class"); + if (!singleDocument) { + addDocumentEnd(); + } + } + + static final String encode(String s) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\\') { + sb.append("\\\\"); + } else if (c < 0x20 || c > 0x7f) { + sb.append("\\u"); + if (c < 0x10) { + sb.append("000"); + } else if (c < 0x100) { + sb.append("00"); + } else if (c < 0x1000) { + sb.append("0"); + } + sb.append(Integer.toString(c, 16)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXCodeAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXCodeAdapter.java new file mode 100644 index 000000000..decb492ff --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXCodeAdapter.java @@ -0,0 +1,310 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import java.util.HashMap; +import java.util.Map; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.util.AbstractVisitor; +import org.xml.sax.ContentHandler; +import org.xml.sax.helpers.AttributesImpl; + +/** + * A {@link MethodVisitor} that generates SAX 2.0 events from the visited + * method. + * + * @see org.objectweb.asm.xml.SAXClassAdapter + * @see org.objectweb.asm.xml.Processor + * + * @author Eugene Kuleshov + */ +public final class SAXCodeAdapter extends SAXAdapter implements MethodVisitor { + private Map labelNames; + + /** + * Constructs a new {@link SAXCodeAdapter SAXCodeAdapter} object. + * + * @param h content handler that will be used to send SAX 2.0 events. + * @param access + */ + public SAXCodeAdapter(ContentHandler h, int access) { + super(h); + labelNames = new HashMap(); + + if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) + { + addStart("code", new AttributesImpl()); + } + } + + public final void visitCode() { + } + + public final void visitInsn(int opcode) { + addElement(AbstractVisitor.OPCODES[opcode], new AttributesImpl()); + } + + public final void visitIntInsn(int opcode, int operand) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "value", "value", "", Integer.toString(operand)); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitVarInsn(int opcode, int var) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "var", "var", "", Integer.toString(var)); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitTypeInsn(int opcode, String desc) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "desc", "desc", "", desc); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitFieldInsn( + int opcode, + String owner, + String name, + String desc) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "owner", "owner", "", owner); + attrs.addAttribute("", "name", "name", "", name); + attrs.addAttribute("", "desc", "desc", "", desc); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitMethodInsn( + int opcode, + String owner, + String name, + String desc) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "owner", "owner", "", owner); + attrs.addAttribute("", "name", "name", "", name); + attrs.addAttribute("", "desc", "desc", "", desc); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitJumpInsn(int opcode, Label label) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "label", "label", "", getLabel(label)); + addElement(AbstractVisitor.OPCODES[opcode], attrs); + } + + public final void visitLabel(Label label) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "name", "name", "", getLabel(label)); + addElement("Label", attrs); + } + + public final void visitLdcInsn(Object cst) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", + "cst", + "cst", + "", + SAXClassAdapter.encode(cst.toString())); + attrs.addAttribute("", + "desc", + "desc", + "", + Type.getDescriptor(cst.getClass())); + addElement(AbstractVisitor.OPCODES[Opcodes.LDC], attrs); + } + + public final void visitIincInsn(int var, int increment) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "var", "var", "", Integer.toString(var)); + attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment)); + addElement(AbstractVisitor.OPCODES[Opcodes.IINC], attrs); + } + + public final void visitTableSwitchInsn( + int min, + int max, + Label dflt, + Label[] labels) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "min", "min", "", Integer.toString(min)); + attrs.addAttribute("", "max", "max", "", Integer.toString(max)); + attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt)); + String o = AbstractVisitor.OPCODES[Opcodes.TABLESWITCH]; + addStart(o, attrs); + for (int i = 0; i < labels.length; i++) { + AttributesImpl att2 = new AttributesImpl(); + att2.addAttribute("", "name", "name", "", getLabel(labels[i])); + addElement("label", att2); + } + addEnd(o); + } + + public final void visitLookupSwitchInsn( + Label dflt, + int[] keys, + Label[] labels) + { + AttributesImpl att = new AttributesImpl(); + att.addAttribute("", "dflt", "dflt", "", getLabel(dflt)); + String o = AbstractVisitor.OPCODES[Opcodes.LOOKUPSWITCH]; + addStart(o, att); + for (int i = 0; i < labels.length; i++) { + AttributesImpl att2 = new AttributesImpl(); + att2.addAttribute("", "name", "name", "", getLabel(labels[i])); + att2.addAttribute("", "key", "key", "", Integer.toString(keys[i])); + addElement("label", att2); + } + addEnd(o); + } + + public final void visitMultiANewArrayInsn(String desc, int dims) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "desc", "desc", "", desc); + attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims)); + addElement(AbstractVisitor.OPCODES[Opcodes.MULTIANEWARRAY], attrs); + } + + public final void visitTryCatchBlock( + Label start, + Label end, + Label handler, + String type) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "start", "start", "", getLabel(start)); + attrs.addAttribute("", "end", "end", "", getLabel(end)); + attrs.addAttribute("", "handler", "handler", "", getLabel(handler)); + if (type != null) + attrs.addAttribute("", "type", "type", "", type); + addElement("TryCatch", attrs); + } + + public final void visitMaxs(int maxStack, int maxLocals) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", + "maxStack", + "maxStack", + "", + Integer.toString(maxStack)); + attrs.addAttribute("", + "maxLocals", + "maxLocals", + "", + Integer.toString(maxLocals)); + addElement("Max", attrs); + + addEnd("code"); + } + + public void visitLocalVariable( + String name, + String desc, + String signature, + Label start, + Label end, + int index) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "name", "name", "", name); + attrs.addAttribute("", "desc", "desc", "", desc); + if (signature != null) + attrs.addAttribute("", + "signature", + "signature", + "", + SAXClassAdapter.encode(signature)); + attrs.addAttribute("", "start", "start", "", getLabel(start)); + attrs.addAttribute("", "end", "end", "", getLabel(end)); + attrs.addAttribute("", "var", "var", "", Integer.toString(index)); + addElement("LocalVar", attrs); + } + + public final void visitLineNumber(int line, Label start) { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "line", "line", "", Integer.toString(line)); + attrs.addAttribute("", "start", "start", "", getLabel(start)); + addElement("LineNumber", attrs); + } + + public AnnotationVisitor visitAnnotationDefault() { + return new SAXAnnotationAdapter(getContentHandler(), + "annotationDefault", + 0, + null, + null); + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new SAXAnnotationAdapter(getContentHandler(), + "annotation", + visible ? 1 : -1, + null, + desc); + } + + public AnnotationVisitor visitParameterAnnotation( + int parameter, + String desc, + boolean visible) + { + return new SAXAnnotationAdapter(getContentHandler(), + "parameterAnnotation", + visible ? 1 : -1, + parameter, + desc); + } + + public void visitEnd() { + addEnd("method"); + } + + public final void visitAttribute(Attribute attr) { + // TODO Auto-generated SAXCodeAdapter.visitAttribute + } + + private final String getLabel(Label label) { + String name = (String) labelNames.get(label); + if (name == null) { + name = Integer.toString(labelNames.size()); + labelNames.put(label, name); + } + return name; + } + +} diff --git a/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXFieldAdapter.java b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXFieldAdapter.java new file mode 100644 index 000000000..edfba0401 --- /dev/null +++ b/libjava/classpath/tools/external/asm/org/objectweb/asm/xml/SAXFieldAdapter.java @@ -0,0 +1,77 @@ +/*** + * ASM XML Adapter + * Copyright (c) 2004, Eugene Kuleshov + * 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.xml; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * SAXFieldAdapter + * + * @author Eugene Kuleshov + */ +public class SAXFieldAdapter implements FieldVisitor { + private final ContentHandler h; + + public SAXFieldAdapter(ContentHandler h, AttributesImpl att) { + this.h = h; + + try { + h.startElement("", "field", "field", att); + } catch (SAXException ex) { + throw new RuntimeException(ex.toString()); + } + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new SAXAnnotationAdapter(h, + "annotation", + visible ? 1 : -1, + null, + desc); + } + + public void visitAttribute(Attribute attr) { + // TODO Auto-generated method stub + } + + public void visitEnd() { + try { + h.endElement("", "field", "field"); + } catch (SAXException ex) { + throw new RuntimeException(ex.toString()); + } + } + +} |