bsh-2.0b4.orig/0000755000175000017500000000000010244162434012276 5ustar wbaerwbaerbsh-2.0b4.orig/asm/0000755000175000017500000000000010243450010013043 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/0000755000175000017500000000000010243450010013632 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/bsh/0000755000175000017500000000000010243450010014406 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/bsh/org/0000755000175000017500000000000010243450010015175 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/bsh/org/objectweb/0000755000175000017500000000000010243450010017141 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/0000755000175000017500000000000010243450010017721 5ustar wbaerwbaerbsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/ByteVector.java0000644000175000017500000001614710243450010022663 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.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. */ final 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 put1 (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. */ public 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 put2 (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. */ public 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 put4 (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 put8 (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 a String in UTF format into this byte vector. The byte vector is * automatically enlarged if necessary. * * @param s a String. * @return this byte vector. */ public ByteVector putUTF (final String s) { int charLength = s.length(); int byteLength = 0; for (int i = 0; i < charLength; ++i) { char c = s.charAt(i); if (c >= '\001' && c <= '\177') { byteLength++; } else if (c > '\u07FF') { byteLength += 3; } else { byteLength += 2; } } if (byteLength > 65535) { throw new IllegalArgumentException(); } int length = this.length; if (length + 2 + byteLength > data.length) { enlarge(2 + byteLength); } byte[] data = this.data; data[length++] = (byte)(byteLength >>> 8); data[length++] = (byte)(byteLength); for (int i = 0; i < charLength; ++i) { char c = s.charAt(i); if (c >= '\001' && c <= '\177') { data[length++] = (byte)c; } else if (c > '\u07FF') { data[length++] = (byte)(0xE0 | c >> 12 & 0xF); data[length++] = (byte)(0x80 | c >> 6 & 0x3F); data[length++] = (byte)(0x80 | c & 0x3F); } else { data[length++] = (byte)(0xC0 | c >> 6 & 0x1F); data[length++] = (byte)(0x80 | c & 0x3F); } } this.length = length; 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 null to put len 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) { byte[] newData = new byte[Math.max(2*data.length, length + size)]; System.arraycopy(data, 0, newData, 0, length); data = newData; } } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/ClassVisitor.java0000644000175000017500000001147710243450010023223 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * A visitor to visit a Java class. The methods of this interface must be called * in the following order: visit (visitField | * visitMethod | visitInnerClass)* visitEnd. */ public interface ClassVisitor { /** * Visits the header of the class. * * @param access the class's access flags (see {@link Constants}). This * parameter also indicates if the class is deprecated. * @param name the internal name of the class (see {@link Type#getInternalName * getInternalName}). * @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 null, but only for the {@link * Object java.lang.Object} class. * @param interfaces the internal names of the class's interfaces (see {@link * Type#getInternalName getInternalName}). May be null. * @param sourceFile the name of the source file from which this class was * compiled. May be null. */ void visit ( int access, String name, String superName, String[] interfaces, String sourceFile); /** * 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 * null. * @param innerName the (simple) name of the inner class inside its enclosing * class. May be null 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 Constants}). 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 value the field's initial value. This parameter, which may be * null if the field does not have an initial value, must be an * {@link java.lang.Integer Integer}, a {@link java.lang.Float Float}, a * {@link java.lang.Long Long}, a {@link java.lang.Double Double} or a * {@link String String}. */ void visitField (int access, String name, String desc, Object value); /** * Visits a method of the class. This method must return a new * {@link CodeVisitor CodeVisitor} instance (or null) each time it * is called, i.e., it should not return a previously returned visitor. * * @param access the method's access flags (see {@link Constants}). 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 exceptions the internal names of the method's exception * classes (see {@link Type#getInternalName getInternalName}). May be * null. * @return an object to visit the byte code of the method, or null if * this class visitor is not interested in visiting the code of this * method. */ CodeVisitor visitMethod ( int access, String name, String desc, 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 (); } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/ClassWriter.java0000644000175000017500000006070610243450010023037 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * A {@link ClassVisitor ClassVisitor} that generates Java class files. 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. */ public class ClassWriter implements ClassVisitor { /** * 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; /** * Index of the next item to be added in the constant pool. */ private short index; /** * The constant pool of this class. */ private ByteVector pool; /** * The constant pool's hash table data. */ private Item[] table; /** * The threshold of the constant pool's hash table. */ private int threshold; /** * 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 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 constant pool item that contains the name of the source file from * which this class was compiled. */ private Item sourceFile; /** * Number of fields of this class. */ private int fieldCount; /** * The fields of this class. */ private ByteVector fields; /** * true if the maximum stack size and number of local variables must * be automatically computed. */ private boolean computeMaxs; /** * The methods of this class. These methods are stored in a linked list of * {@link CodeWriter CodeWriter} objects, linked to each other by their {@link * CodeWriter#next} field. This field stores the first element of this list. */ CodeWriter firstMethod; /** * The methods of this class. These methods are stored in a linked list of * {@link CodeWriter CodeWriter} objects, linked to each other by their {@link * CodeWriter#next} field. This field stores the last element of this list. */ CodeWriter lastMethod; /** * The number of entries in the InnerClasses attribute. */ private int innerClassesCount; /** * The InnerClasses attribute. */ private ByteVector innerClasses; /** * A reusable key used to look for items in the hash {@link #table table}. */ Item key; /** * A reusable key used to look for items in the hash {@link #table table}. */ Item key2; /** * A reusable key used to look for items in the hash {@link #table table}. */ Item key3; /** * The type of instructions without any label. */ final static int NOARG_INSN = 0; /** * The type of instructions with an signed byte label. */ final static int SBYTE_INSN = 1; /** * The type of instructions with an signed short label. */ final static int SHORT_INSN = 2; /** * The type of instructions with a local variable index label. */ final static int VAR_INSN = 3; /** * The type of instructions with an implicit local variable index label. */ 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; // -------------------------------------------------------------------------- // Static initializer // -------------------------------------------------------------------------- /** * Computes the instruction types of JVM opcodes. */ static { int i; byte[] b = new byte[220]; String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADDDDDEEEEEEEEE" + "EEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA" + "AAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAAAAAAGGGGGGGHAFBFAAFFAAQPIIJJII" + "IIIIIIIIIIIIIIII"; 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 CodeWriter 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 true if the maximum stack size and the maximum * number of local variables must be automatically computed. If this flag * is true, then the arguments of the {@link * CodeVisitor#visitMaxs visitMaxs} method of the {@link CodeVisitor * CodeVisitor} 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) { index = 1; pool = new ByteVector(); table = new Item[64]; threshold = (int)(0.75d*table.length); key = new Item(); key2 = new Item(); key3 = new Item(); this.computeMaxs = computeMaxs; } // -------------------------------------------------------------------------- // Implementation of the ClassVisitor interface // -------------------------------------------------------------------------- public void visit ( final int access, final String name, final String superName, final String[] interfaces, final String sourceFile) { this.access = access; this.name = newClass(name).index; this.superName = superName == null ? 0 : newClass(superName).index; 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]).index; } } if (sourceFile != null) { newUTF8("SourceFile"); this.sourceFile = newUTF8(sourceFile); } if ((access & Constants.ACC_DEPRECATED) != 0) { newUTF8("Deprecated"); } } public void visitInnerClass ( final String name, final String outerName, final String innerName, final int access) { if (innerClasses == null) { newUTF8("InnerClasses"); innerClasses = new ByteVector(); } ++innerClassesCount; innerClasses.put2(name == null ? 0 : newClass(name).index); innerClasses.put2(outerName == null ? 0 : newClass(outerName).index); innerClasses.put2(innerName == null ? 0 : newUTF8(innerName).index); innerClasses.put2(access); } public void visitField ( final int access, final String name, final String desc, final Object value) { ++fieldCount; if (fields == null) { fields = new ByteVector(); } fields.put2(access).put2(newUTF8(name).index).put2(newUTF8(desc).index); int attributeCount = 0; if (value != null) { ++attributeCount; } if ((access & Constants.ACC_SYNTHETIC) != 0) { ++attributeCount; } if ((access & Constants.ACC_DEPRECATED) != 0) { ++attributeCount; } fields.put2(attributeCount); if (value != null) { fields.put2(newUTF8("ConstantValue").index); fields.put4(2).put2(newCst(value).index); } if ((access & Constants.ACC_SYNTHETIC) != 0) { fields.put2(newUTF8("Synthetic").index).put4(0); } if ((access & Constants.ACC_DEPRECATED) != 0) { fields.put2(newUTF8("Deprecated").index).put4(0); } } public CodeVisitor visitMethod ( final int access, final String name, final String desc, final String[] exceptions) { CodeWriter cw = new CodeWriter(this, computeMaxs); cw.init(access, name, desc, exceptions); return cw; } 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; if (fields != null) { size += fields.length; } int nbMethods = 0; CodeWriter cb = firstMethod; while (cb != null) { ++nbMethods; size += cb.getSize(); cb = cb.next; } size += pool.length; int attributeCount = 0; if (sourceFile != null) { ++attributeCount; size += 8; } if ((access & Constants.ACC_DEPRECATED) != 0) { ++attributeCount; size += 6; } if (innerClasses != null) { ++attributeCount; size += 8 + innerClasses.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.put4(0xCAFEBABE).put2(3).put2(45); out.put2(index).putByteArray(pool.data, 0, pool.length); out.put2(access).put2(name).put2(superName); out.put2(interfaceCount); for (int i = 0; i < interfaceCount; ++i) { out.put2(interfaces[i]); } out.put2(fieldCount); if (fields != null) { out.putByteArray(fields.data, 0, fields.length); } out.put2(nbMethods); cb = firstMethod; while (cb != null) { cb.put(out); cb = cb.next; } out.put2(attributeCount); if (sourceFile != null) { out.put2(newUTF8("SourceFile").index).put4(2).put2(sourceFile.index); } if ((access & Constants.ACC_DEPRECATED) != 0) { out.put2(newUTF8("Deprecated").index).put4(0); } if (innerClasses != null) { out.put2(newUTF8("InnerClasses").index); out.put4(innerClasses.length + 2).put2(innerClassesCount); out.putByteArray(innerClasses.data, 0, innerClasses.length); } 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 java.lang.Integer Integer}, a {@link * java.lang.Float Float}, a {@link java.lang.Long Long}, a {@link java.lang.Double Double} or a {@link String String}. * @return a new or already existing constant item with the given value. */ Item newCst (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 { throw new IllegalArgumentException("value " + cst); } } /** * Adds an UTF 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 UTF8 item. */ Item newUTF8 (final String value) { key.set(UTF8, value, null, null); Item result = get(key); if (result == null) { pool.put1(UTF8).putUTF(value); result = new Item(index++, key); put(result); } return result; } /** * Adds a class reference to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param value the internal name of the class. * @return a new or already existing class reference item. */ Item newClass (final String value) { key2.set(CLASS, value, null, null); Item result = get(key2); if (result == null) { pool.put12(CLASS, newUTF8(value).index); 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. * * @param owner the internal name of the field's owner class. * @param name the field's name. * @param desc the field's descriptor. * @return a new or already existing field reference item. */ Item 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).index, newNameType(name, desc).index); 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. * * @param owner the internal name of the method's owner class. * @param name the method's name. * @param desc the method's descriptor. * @return a new or already existing method reference item. */ Item newMethod ( final String owner, final String name, final String desc) { key3.set(METH, owner, name, desc); Item result = get(key3); if (result == null) { put122(METH, newClass(owner).index, newNameType(name, desc).index); result = new Item(index++, key3); put(result); } return result; } /** * Adds an interface method reference to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * * @param ownerItf the internal name of the method's owner interface. * @param name the method's name. * @param desc the method's descriptor. * @return a new or already existing interface method reference item. */ Item newItfMethod ( final String ownerItf, final String name, final String desc) { key3.set(IMETH, ownerItf, name, desc); Item result = get(key3); if (result == null) { put122(IMETH, newClass(ownerItf).index, newNameType(name, desc).index); result = new Item(index++, key3); put(result); } return result; } /** * 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. */ private Item newInteger (final int value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(INT).put4(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. */ private Item newFloat (final float value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(FLOAT).put4(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. */ private Item newLong (final long value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(LONG).put8(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. */ private Item newDouble (final double value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(DOUBLE).put8(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).index); 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. * * @param name a name. * @param desc a type descriptor. * @return a new or already existing name and type item. */ private Item 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).index, newUTF8(desc).index); result = new Item(index++, key2); put(result); } return result; } /** * 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 null if there is no such item. */ private Item get (final Item key) { Item tab[] = table; int hashCode = key.hashCode; int index = (hashCode & 0x7FFFFFFF) % tab.length; for (Item i = tab[index]; i != null; i = i.next) { if (i.hashCode == hashCode && key.isEqualTo(i)) { return i; } } return null; } /** * Puts the given item in the constant pool's hash table. The hash table * must 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 oldCapacity = table.length; Item oldMap[] = table; int newCapacity = oldCapacity * 2 + 1; Item newMap[] = new Item[newCapacity]; threshold = (int)(newCapacity * 0.75); table = newMap; for (int j = oldCapacity; j-- > 0; ) { for (Item old = oldMap[j]; old != null; ) { Item e = old; old = old.next; int index = (e.hashCode & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } } int index = (i.hashCode & 0x7FFFFFFF) % table.length; i.next = table[index]; table[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).put2(s2); } } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/CodeVisitor.java0000644000175000017500000002456310243450010023030 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * A visitor to visit the bytecode instructions of a Java method. The methods * of this visitor must be called in the sequential order of the bytecode * instructions of the visited code. The {@link #visitMaxs visitMaxs} method * must be called after all the instructions have been visited. The {@link * #visitTryCatchBlock visitTryCatchBlock}, {@link #visitLocalVariable * visitLocalVariable} and {@link #visitLineNumber visitLineNumber} methods may * be called in any order, at any time (provided the labels passed as arguments * have already been visited with {@link #visitLabel visitLabel}). */ public interface CodeVisitor { /** * 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. */ 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 java.lang.Integer Integer}, a {@link java.lang.Float * Float}, a {@link java.lang.Long Long}, a {@link java.lang.Double * Double} or a {@link String String}. */ 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. labels[i] is the * beginning of the handler block for the min + i 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. labels[i] is the * beginning of the handler block for the keys[i] 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, 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 null to catch any exceptions (for "finally" blocks). * @throws IllegalArgumentException if one of the labels has not already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ void visitTryCatchBlock (Label start, Label end, Label handler, String type); /** * 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); // ------------------------------------------------------------------------- // Debug information // ------------------------------------------------------------------------- /** * Visits a local variable declaration. * * @param name the name of a local variable. * @param desc the type descriptor of this local variable. * @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, 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 start has not already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ void visitLineNumber (int line, Label start); } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/CodeWriter.java0000644000175000017500000016434110243450010022644 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * A {@link CodeVisitor CodeVisitor} that generates Java bytecode instructions. * 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. */ public class CodeWriter implements CodeVisitor { /** * true if preconditions must be checked at runtime or not. */ final static boolean CHECK = false; /** * Next code writer (see {@link ClassWriter#firstMethod firstMethod}). */ CodeWriter next; /** * The class writer to which this method must be added. */ private ClassWriter cw; /** * The constant pool item that contains the name of this method. */ private Item name; /** * The constant pool item that contains the descriptor of this method. */ private Item desc; /** * Access flags of this method. */ private int access; /** * Maximum stack size of this method. */ private int maxStack; /** * Maximum number of local variables for this method. */ private int maxLocals; /** * The bytecode of this method. */ private ByteVector code = new ByteVector(); /** * Number of entries in the catch table of this method. */ private int catchCount; /** * The catch table of this method. */ private ByteVector catchTable; /** * Number of exceptions that can be thrown by this method. */ private 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. */ private int[] exceptions; /** * Number of entries in the LocalVariableTable attribute. */ private int localVarCount; /** * The LocalVariableTable attribute. */ private ByteVector localVar; /** * Number of entries in the LineNumberTable attribute. */ private int lineNumberCount; /** * The LineNumberTable attribute. */ private ByteVector lineNumber; /** * 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. // -------------------------------------------------------------------------- /** * true 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 * stackSize. */ 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 * stackSize. */ 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; // -------------------------------------------------------------------------- // Fields to optimize the creation of {@link Edge Edge} objects by using a // pool of reusable objects. The (shared) pool is a linked list of Edge // objects, linked to each other by their {@link Edge#poolNext} field. Each // time a CodeWriter needs to allocate an Edge, it removes the first Edge // of the pool and adds it to a private list of Edge objects. After the end // of the control flow analysis algorithm, the Edge objects in the private // list of the CodeWriter are added back to the pool (by appending this // private list to the pool list; in order to do this in constant time, both // head and tail of the private list are stored in this CodeWriter). // -------------------------------------------------------------------------- /** * The head of the list of {@link Edge Edge} objects used by this {@link * CodeWriter CodeWriter}. These objects, linked to each other by their * {@link Edge#poolNext} field, are added back to the shared pool at the * end of the control flow analysis algorithm. */ private Edge head; /** * The tail of the list of {@link Edge Edge} objects used by this {@link * CodeWriter CodeWriter}. These objects, linked to each other by their * {@link Edge#poolNext} field, are added back to the shared pool at the * end of the control flow analysis algorithm. */ private Edge tail; /** * The shared pool of {@link Edge Edge} objects. This pool is a linked list * of Edge objects, linked to each other by their {@link Edge#poolNext} field. */ private static Edge pool; // -------------------------------------------------------------------------- // Static initializer // -------------------------------------------------------------------------- /** * Computes the stack size variation corresponding to each JVM instruction. */ static { int i; int[] b = new int[202]; String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEE" + "EEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEF" + "DDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; 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 CodeWriter. * * @param cw the class writer in which the method must be added. * @param computeMaxs true if the maximum stack size and number of * local variables must be automatically computed. */ protected CodeWriter (final ClassWriter cw, final boolean computeMaxs) { if (cw.firstMethod == null) { cw.firstMethod = this; cw.lastMethod = this; } else { cw.lastMethod.next = this; cw.lastMethod = this; } this.cw = cw; this.computeMaxs = computeMaxs; if (computeMaxs) { // pushes the first block onto the stack of blocks to be visited currentBlock = new Label(); currentBlock.pushed = true; blockStack = currentBlock; } } /** * Initializes this CodeWriter to define the bytecode of the specified method. * * @param access the method's access flags (see {@link Constants}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param exceptions the internal names of the method's exceptions. May be * null. */ protected void init ( final int access, final String name, final String desc, final String[] exceptions) { this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); 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]).index; } } if (computeMaxs) { // updates maxLocals int size = getArgumentsAndReturnSizes(desc) >> 2; if ((access & Constants.ACC_STATIC) != 0) { --size; } if (size > maxLocals) { maxLocals = size; } } } // -------------------------------------------------------------------------- // Implementation of the CodeVisitor interface // -------------------------------------------------------------------------- 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 >= Constants.IRETURN && opcode <= Constants.RETURN) || opcode == Constants.ATHROW) { if (currentBlock != null) { currentBlock.maxStackSize = maxStackSize; currentBlock = null; } } } // adds the instruction to the bytecode of the method code.put1(opcode); } public void visitIntInsn (final int opcode, final int operand) { if (computeMaxs && opcode != Constants.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 == Constants.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 == Constants.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 == Constants.LLOAD || opcode == Constants.DLOAD || opcode == Constants.LSTORE || opcode == Constants.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 != Constants.RET) { int opt; if (opcode < Constants.ISTORE) { opt = 26 /*ILOAD_0*/ + ((opcode - Constants.ILOAD) << 2) + var; } else { opt = 59 /*ISTORE_0*/ + ((opcode - Constants.ISTORE) << 2) + var; } code.put1(opt); } else if (var >= 256) { code.put1(196 /*WIDE*/).put12(opcode, var); } else { code.put11(opcode, var); } } public void visitTypeInsn (final int opcode, final String desc) { if (computeMaxs && opcode == Constants.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).index); } 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 Constants.GETSTATIC: size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); break; case Constants.PUTSTATIC: size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); break; case Constants.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).index); } public void visitMethodInsn ( final int opcode, final String owner, final String name, final String desc) { Item i; if (opcode == Constants.INVOKEINTERFACE) { i = cw.newItfMethod(owner, name, desc); } else { i = cw.newMethod(owner, name, desc); } 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 == Constants.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 (opcode == Constants.INVOKEINTERFACE) { if (!computeMaxs) { if (argSize == 0) { argSize = getArgumentsAndReturnSizes(desc); i.intVal = argSize; } } code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); } else { code.put12(opcode, i.index); } } public void visitJumpInsn (final int opcode, final Label label) { if (CHECK) { if (label.owner == null) { label.owner = this; } else if (label.owner != this) { throw new IllegalArgumentException(); } } if (computeMaxs) { if (opcode == Constants.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 == Constants.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 // with IFNOTxxx GOTO_W , where IFNOTxxx is the "opposite" opcode // of IFxxx (i.e., IFNE for IFEQ) and where designates the // instruction just after the GOTO_W. if (opcode == Constants.GOTO) { code.put1(200); // GOTO_W } else if (opcode == Constants.JSR) { code.put1(201); // JSR_W } else { code.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.put2(8); // jump offset code.put1(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.put1(opcode); label.put(this, code, code.length - 1, false); } } public void visitLabel (final Label label) { if (CHECK) { if (label.owner == null) { label.owner = this; } else if (label.owner != this) { throw new IllegalArgumentException(); } } 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.newCst(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(Constants.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.put1(196 /*WIDE*/).put12(Constants.IINC, var).put2(increment); } else { code.put1(Constants.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.put1(Constants.TABLESWITCH); while (code.length % 4 != 0) { code.put1(0); } dflt.put(this, code, source, true); code.put4(min).put4(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.put1(Constants.LOOKUPSWITCH); while (code.length % 4 != 0) { code.put1(0); } dflt.put(this, code, source, true); code.put4(labels.length); for (int i = 0; i < labels.length; ++i) { code.put4(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 Item classItem = cw.newClass(desc); code.put12(Constants.MULTIANEWARRAY, classItem.index).put1(dims); } public void visitTryCatchBlock ( final Label start, final Label end, final Label handler, final String type) { if (CHECK) { if (start.owner != this || end.owner != this || handler.owner != this) { throw new IllegalArgumentException(); } if (!start.resolved || !end.resolved || !handler.resolved) { throw new IllegalArgumentException(); } } 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; if (catchTable == null) { catchTable = new ByteVector(); } catchTable.put2(start.position); catchTable.put2(end.position); catchTable.put2(handler.position); catchTable.put2(type != null ? cw.newClass(type).index : 0); } 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; // releases all the Edge objects used by this CodeWriter synchronized (SIZE) { // appends the [head ... tail] list at the beginning of the pool list if (tail != null) { tail.poolNext = pool; pool = head; } } } else { this.maxStack = maxStack; this.maxLocals = maxLocals; } } public void visitLocalVariable ( final String name, final String desc, final Label start, final Label end, final int index) { if (CHECK) { if (start.owner != this || !start.resolved) { throw new IllegalArgumentException(); } if (end.owner != this || !end.resolved) { throw new IllegalArgumentException(); } } if (localVar == null) { cw.newUTF8("LocalVariableTable"); localVar = new ByteVector(); } ++localVarCount; localVar.put2(start.position); localVar.put2(end.position - start.position); localVar.put2(cw.newUTF8(name).index); localVar.put2(cw.newUTF8(desc).index); localVar.put2(index); } public void visitLineNumber (final int line, final Label start) { if (CHECK) { if (start.owner != this || !start.resolved) { throw new IllegalArgumentException(); } } if (lineNumber == null) { cw.newUTF8("LineNumberTable"); lineNumber = new ByteVector(); } ++lineNumberCount; lineNumber.put2(start.position); lineNumber.put2(line); } // -------------------------------------------------------------------------- // 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 = (argSize << 2) | retSize * (argSize is therefore equal to i >> 2, and retSize to * i & 0x03). */ 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; // creates a new Edge object or reuses one from the shared pool synchronized (SIZE) { if (pool == null) { b = new Edge(); } else { b = pool; // removes b from the pool pool = pool.poolNext; } } // adds the previous Edge to the list of Edges used by this CodeWriter if (tail == null) { tail = b; } b.poolNext = head; head = b; // 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 (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) { size += 8 + localVar.length; } if (lineNumber != null) { size += 8 + lineNumber.length; } } if (exceptionCount > 0) { cw.newUTF8("Exceptions"); size += 8 + 2 * exceptionCount; } if ((access & Constants.ACC_SYNTHETIC) != 0) { cw.newUTF8("Synthetic"); size += 6; } if ((access & Constants.ACC_DEPRECATED) != 0) { cw.newUTF8("Deprecated"); size += 6; } 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.put2(access).put2(name.index).put2(desc.index); int attributeCount = 0; if (code.length > 0) { ++attributeCount; } if (exceptionCount > 0) { ++attributeCount; } if ((access & Constants.ACC_SYNTHETIC) != 0) { ++attributeCount; } if ((access & Constants.ACC_DEPRECATED) != 0) { ++attributeCount; } out.put2(attributeCount); if (code.length > 0) { int size = 12 + code.length + 8 * catchCount; if (localVar != null) { size += 8 + localVar.length; } if (lineNumber != null) { size += 8 + lineNumber.length; } out.put2(cw.newUTF8("Code").index).put4(size); out.put2(maxStack).put2(maxLocals); out.put4(code.length).putByteArray(code.data, 0, code.length); out.put2(catchCount); if (catchCount > 0) { out.putByteArray(catchTable.data, 0, catchTable.length); } attributeCount = 0; if (localVar != null) { ++attributeCount; } if (lineNumber != null) { ++attributeCount; } out.put2(attributeCount); if (localVar != null) { out.put2(cw.newUTF8("LocalVariableTable").index); out.put4(localVar.length + 2).put2(localVarCount); out.putByteArray(localVar.data, 0, localVar.length); } if (lineNumber != null) { out.put2(cw.newUTF8("LineNumberTable").index); out.put4(lineNumber.length + 2).put2(lineNumberCount); out.putByteArray(lineNumber.data, 0, lineNumber.length); } } if (exceptionCount > 0) { out.put2(cw.newUTF8("Exceptions").index).put4(2 * exceptionCount + 2); out.put2(exceptionCount); for (int i = 0; i < exceptionCount; ++i) { out.put2(exceptions[i]); } } if ((access & Constants.ACC_SYNTHETIC) != 0) { out.put2(cw.newUTF8("Synthetic").index).put4(0); } if ((access & Constants.ACC_DEPRECATED) != 0) { out.put2(cw.newUTF8("Deprecated").index).put4(0); } } // -------------------------------------------------------------------------- // 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. *

* This method must be called after all the method that is being built has * been visited. 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 last byte, * plus one (or, in other words, by the index of the first byte of * the next instruction). * @param sizes the number of bytes to be added to the above * instructions. More precisely, for each i < len, * sizes[i] bytes will be added at the end of the instruction * designated by indexes[i] or, if sizes[i] is * negative, the last |sizes[i]| bytes of the instruction * will be removed (the instruction size must not become negative * or null). The gaps introduced by this method must be filled in * "manually" in the array returned by the {@link #getCode getCode} * method. * @param len the number of instruction to be resized. Must be smaller than or * equal to indexes.length and sizes.length. * @return the indexes array, which now contains the new positions of * the resized instructions (designated as above). */ protected 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]; int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done 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 (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 (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { if (!resize[u]) { if (opcode == Constants.GOTO || opcode == Constants.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 instruction with IFNOTxxx GOTO_W , where // IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for // IFEQ) and where 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 == Constants.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.put1(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 (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx with // IFNOTxxx GOTO_W , where IFNOTxxx is the "opposite" opcode // of IFxxx (i.e., IFNE for IFEQ) and where designates the // instruction just after the GOTO_W. if (opcode == Constants.GOTO) { newCode.put1(200); // GOTO_W } else if (opcode == Constants.JSR) { newCode.put1(201); // JSR_W } else { newCode.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); newCode.put2(8); // jump offset newCode.put1(200); // GOTO_W newOffset -= 3; // newOffset now computed from start of GOTO_W } newCode.put4(newOffset); } else { newCode.put1(opcode); newCode.put2(newOffset); } u += 3; break; case ClassWriter.LABELW_INSN: label = u + readInt(b, u + 1); newOffset = getNewOffset(allIndexes, allSizes, u, label); newCode.put1(opcode); newCode.put4(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 int source = newCode.length; newCode.put1(Constants.TABLESWITCH); while (newCode.length % 4 != 0) { newCode.put1(0); } label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); j = readInt(b, u); u += 4; newCode.put4(j); j = readInt(b, u) - j + 1; u += 4; newCode.put4(readInt(b, u - 4)); for ( ; j > 0; --j) { label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); } break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes v = u; u = u + 4 - (v & 3); // reads and copies instruction source = newCode.length; newCode.put1(Constants.LOOKUPSWITCH); while (newCode.length % 4 != 0) { newCode.put1(0); } label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); j = readInt(b, u); u += 4; newCode.put4(j); for ( ; j > 0; --j) { newCode.put4(readInt(b, u)); u += 4; label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); } break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Constants.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 instructions addresses in the // catch, local var and line number tables if (catchTable != null) { b = catchTable.data; u = 0; while (u < catchTable.length) { writeShort(b, u, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u))); writeShort(b, u + 2, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u + 2))); writeShort(b, u + 4, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u + 4))); u += 8; } } if (localVar != null) { b = localVar.data; u = 0; while (u < localVar.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, 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; } } // 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. *

* Note: it is possible to have several entries for the same instruction * in the indexes and sizes: 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 last byte, * plus one (or, in other words, by the index of the first byte of * the next instruction). * @param sizes the number of bytes to be added to the above * instructions. More precisely, for each i < len, * sizes[i] bytes will be added at the end of the instruction * designated by indexes[i] or, if sizes[i] is * negative, the last |sizes[i]| bytes of the instruction * will be removed (the instruction size must not 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; } /** * Returns the current size of the bytecode of this method. This size just * includes the size of the bytecode instructions: it does not include the * size of the Exceptions, LocalVariableTable, LineNumberTable, Synthetic * and Deprecated attributes, if present. * * @return the current size of the bytecode of this method. */ protected int getCodeSize () { return code.length; } /** * Returns the current bytecode of this method. This bytecode only contains * the instructions: it does not include the Exceptions, LocalVariableTable, * LineNumberTable, Synthetic and Deprecated attributes, if present. * * @return the current bytecode of this method. The bytecode is contained * between the index 0 (inclusive) and the index {@link #getCodeSize * getCodeSize} (exclusive). */ protected byte[] getCode () { return code.data; } } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/Constants.java0000644000175000017500000002246410243450010022550 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.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. */ public interface Constants { // access flags int ACC_PUBLIC = 1; int ACC_PRIVATE = 2; int ACC_PROTECTED = 4; int ACC_STATIC = 8; int ACC_FINAL = 16; int ACC_SYNCHRONIZED = 32; int ACC_VOLATILE = 64; int ACC_TRANSIENT = 128; int ACC_NATIVE = 256; int ACC_INTERFACE = 512; int ACC_ABSTRACT = 1024; int ACC_STRICT = 2048; int ACC_SUPER = 32; int ACC_SYNTHETIC = 65536; int ACC_DEPRECATED = 131072; // 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; // - } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/Edge.java0000644000175000017500000000336210243450010021434 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * An edge in the control flow graph of a method body. See {@link Label Label}. */ 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; /** * The next available edge in the pool. See {@link CodeWriter#pool pool}. */ Edge poolNext; } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/Item.java0000644000175000017500000001432410243450010021466 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.org.objectweb.asm; /** * A constant pool item. Constant pool items can be created with the 'newXXX' * methods in the {@link ClassWriter} class. */ final class Item { /** * Index of this item in the constant pool. */ short 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 the constants defined in the * {@link ClassWriter ClassWriter} class. */ int type; /** * Value of this item, for a {@link ClassWriter#INT INT} item. */ int intVal; /** * Value of this item, for a {@link ClassWriter#LONG LONG} item. */ long longVal; /** * Value of this item, for a {@link ClassWriter#FLOAT FLOAT} item. */ float floatVal; /** * Value of this item, for a {@link ClassWriter#DOUBLE 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} object. */ Item () { } /** * 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 short 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 {@link ClassWriter#INT INT} item. * * @param intVal the value of this item. */ void set (final int intVal) { this.type = ClassWriter.INT; this.intVal = intVal; this.hashCode = type + intVal; } /** * Sets this item to a {@link ClassWriter#LONG LONG} item. * * @param longVal the value of this item. */ void set (final long longVal) { this.type = ClassWriter.LONG; this.longVal = longVal; this.hashCode = type + (int)longVal; } /** * Sets this item to a {@link ClassWriter#FLOAT FLOAT} item. * * @param floatVal the value of this item. */ void set (final float floatVal) { this.type = ClassWriter.FLOAT; this.floatVal = floatVal; this.hashCode = type + (int)floatVal; } /** * Sets this item to a {@link ClassWriter#DOUBLE DOUBLE} item. * * @param doubleVal the value of this item. */ void set (final double doubleVal) { this.type = ClassWriter.DOUBLE; this.doubleVal = doubleVal; this.hashCode = 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 = type + strVal1.hashCode(); return; case ClassWriter.NAME_TYPE: hashCode = type + strVal1.hashCode()*strVal2.hashCode(); return; //case ClassWriter.FIELD: //case ClassWriter.METH: //case ClassWriter.IMETH: default: hashCode = type + strVal1.hashCode()*strVal2.hashCode()*strVal3.hashCode(); return; } } /** * Indicates if the given item is equal to this one. * * @param i the item to be compared to this one. * @return true if the given item if equal to this one, * false 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); //case ClassWriter.FIELD: //case ClassWriter.METH: //case ClassWriter.IMETH: default: return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3); } } return false; } } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/Label.java0000644000175000017500000002314510243450010021610 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.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. */ public class Label { /** * The code writer to which this label belongs, or null if unknown. */ CodeWriter owner; /** * Indicates if the position of this label is known. */ boolean resolved; /** * The position of this label in the code, if known. */ int position; /** * 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 CodeWriter#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 CodeWriter#visitMaxs visitMaxs}. */ Label next; /** * true if this basic block has been pushed in the basic block stack. * See {@link CodeWriter#visitMaxs visitMaxs}. */ boolean pushed; // -------------------------------------------------------------------------- // Constructor // -------------------------------------------------------------------------- /** * Constructs a new label. */ public Label () { } // -------------------------------------------------------------------------- // Methods to compute offsets and to manage forward references // -------------------------------------------------------------------------- /** * 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 true if the reference must be stored in 4 bytes, * or false 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 CodeWriter owner, final ByteVector out, final int source, final boolean wideOffset) { if (CodeWriter.CHECK) { if (this.owner == null) { this.owner = owner; } else if (this.owner != owner) { throw new IllegalArgumentException(); } } if (resolved) { if (wideOffset) { out.put4(position - source); } else { out.put2(position - source); } } else { if (wideOffset) { addReference(-1 - source, out.length); out.put4(-1); } else { addReference(source, out.length); out.put2(-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 true 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 CodeWriter#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 CodeWriter owner, final int position, final byte[] data) { if (CodeWriter.CHECK) { if (this.owner == null) { this.owner = owner; } if (resolved || this.owner != owner) { throw new IllegalArgumentException(); } } 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 CodeWriter). 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 <= Constants.JSR) { // changes IFEQ ... JSR to opcodes 202 to 217 (inclusive) data[reference - 1] = (byte)(opcode + 49); } else { // changes IFNULL and IFNONNULL to opcodes 218 and 219 (inclusive) 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; } } bsh-2.0b4.orig/asm/src/bsh/org/objectweb/asm/Type.java0000644000175000017500000004352410243450010021515 0ustar wbaerwbaer/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (C) 2000 INRIA, France Telecom * Copyright (C) 2002 France Telecom * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: Eric.Bruneton@rd.francetelecom.com * * Author: Eric Bruneton */ package bsh.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. */ public class Type { /** * The sort of the void type. See {@link #getSort getSort}. */ public final static int VOID = 0; /** * The sort of the boolean type. See {@link #getSort getSort}. */ public final static int BOOLEAN = 1; /** * The sort of the char type. See {@link #getSort getSort}. */ public final static int CHAR = 2; /** * The sort of the byte type. See {@link #getSort getSort}. */ public final static int BYTE = 3; /** * The sort of the short type. See {@link #getSort getSort}. */ public final static int SHORT = 4; /** * The sort of the int type. See {@link #getSort getSort}. */ public final static int INT = 5; /** * The sort of the float type. See {@link #getSort getSort}. */ public final static int FLOAT = 6; /** * The sort of the long type. See {@link #getSort getSort}. */ public final static int LONG = 7; /** * The sort of the double 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 void type. */ public final static Type VOID_TYPE = new Type(VOID); /** * The boolean type. */ public final static Type BOOLEAN_TYPE = new Type(BOOLEAN); /** * The char type. */ public final static Type CHAR_TYPE = new Type(CHAR); /** * The byte type. */ public final static Type BYTE_TYPE = new Type(BYTE); /** * The short type. */ public final static Type SHORT_TYPE = new Type(SHORT); /** * The int type. */ public final static Type INT_TYPE = new Type(INT); /** * The float type. */ public final static Type FLOAT_TYPE = new Type(FLOAT); /** * The long type. */ public final static Type LONG_TYPE = new Type(LONG); /** * The double 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 object type. * This method should only be used for an object type. * * @return the fully qualified name of the class corresponding to this object * type. */ public String getClassName () { 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 long and * double, 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 float and * opcode is IRETURN, this method returns FRETURN. */ public int getOpcode (final int opcode) { if (opcode == Constants.IALOAD || opcode == Constants.IASTORE) { switch (sort) { case VOID: return opcode + 5; case BOOLEAN: case BYTE: return opcode + 6; case CHAR: return opcode + 7; case SHORT: return opcode + 8; 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; } } } } bsh-2.0b4.orig/asm/README-asm.txt0000644000175000017500000000101110243450010015310 0ustar wbaerwbaer These files are part of the org.objectweb.asm distribution. (http://asm.objectweb.org) and are included under the terms of the LGPL license. ASM is a very light weight, fast, visitor-pattern style Java byte code reader / generator. We have repackaged these classes under a "bsh." prefix for two reasons: 1) BeanShell uses the subset of ASM only for writing classes and 2) Since BeanShell is widely distributed we don't want to break the ability of script writers to use updated versions of ASM in their scripts. bsh-2.0b4.orig/bsf/0000755000175000017500000000000010243450010013035 5ustar wbaerwbaerbsh-2.0b4.orig/bsf/src/0000755000175000017500000000000010243450010013624 5ustar wbaerwbaerbsh-2.0b4.orig/bsf/src/bsh/0000755000175000017500000000000010243450010014400 5ustar wbaerwbaerbsh-2.0b4.orig/bsf/src/bsh/util/0000755000175000017500000000000010243450010015355 5ustar wbaerwbaerbsh-2.0b4.orig/bsf/src/bsh/util/BeanShellBSFEngine.java0000644000175000017500000001646310243450010021550 0ustar wbaerwbaerpackage bsh.util; /* This file is associated with the BeanShell Java Scripting language distribution (http://www.beanshell.org/). This file is hereby placed into the public domain... You may copy, modify, and redistribute it without restriction. */ import java.util.Vector; import org.apache.bsf.*; import org.apache.bsf.util.*; import bsh.Interpreter; import bsh.InterpreterError; import bsh.EvalError; import bsh.TargetError; import bsh.Primitive; /** This is the BeanShell adapter for IBM's Bean Scripting Famework. It is an implementation of the BSFEngine class, allowing BSF aware applications to use BeanShell as a scripting language.

I believe this implementation is complete (with some hesitation about the the usefullness of the compileXXX() style methods - provided by the base utility class).

@author Pat Niemeyer */ public class BeanShellBSFEngine extends BSFEngineImpl { Interpreter interpreter; boolean installedApplyMethod; public void initialize ( BSFManager mgr, String lang, Vector declaredBeans) throws BSFException { super.initialize( mgr, lang, declaredBeans ); interpreter = new Interpreter(); // declare the bsf manager for callbacks, etc. try { interpreter.set( "bsf", mgr ); } catch ( EvalError e ) { throw new BSFException("bsh internal error: "+e.toString()); } for(int i=0; i