asm-3.3.2/0000755000175000017500000000000011633370220012232 5ustar twernertwernerasm-3.3.2/build.config0000644000175000017500000000161311053005772014524 0ustar twernertwerner# Defines values for the 'build.properties' build properties # This file is used to build the project in the case of bundled external jars objectweb.ant.tasks.path config/ow_util_ant_tasks.jar bcel.path test/lib/bcel-5.2.jar aspectj.path test/lib/aspectjweaver-1.5.3.jar serp.path test/lib/serp-1.14.2.jar javassist.path test/lib/javassist.3.6.GA.jar janino.path test/lib/janino-2.5.11.jar cobertura.path test/lib/cobertura-1.9.jar;test/lib/jakarta-oro-2.0.8.jar;test/lib/log4j-1.2.9.jar;test/lib/asm-2.2.1.jar;test/lib/asm-tree-2.2.1.jar cobertura.runtime.path test/lib/cobertura-1.9.jar kawa.runtime.path test/lib/kawa-1.9.1.jar csg-bytecode.runtime.path test/lib/csg-bytecode.jar cojen.runtime.path test/lib/cojen-2.0.jar jbet.runtime.path test/lib/jbet3-R1.jar jclasslib.runtime.path test/lib/jclasslib.jar jiapi.runtime.path test/lib/jiapi.jar rhino.runtime.path test/lib/rhino1_7R1.jar asm-3.3.2/src/0000755000175000017500000000000011633370220013021 5ustar twernertwernerasm-3.3.2/src/org/0000755000175000017500000000000011633370220013610 5ustar twernertwernerasm-3.3.2/src/org/objectweb/0000755000175000017500000000000011633370220015554 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/0000755000175000017500000000000011633370220016334 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/FieldWriter.java0000644000175000017500000002163511366756346021452 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * An {@link FieldVisitor} that generates Java fields in bytecode form. * * @author Eric Bruneton */ final class FieldWriter implements FieldVisitor { /** * Next field writer (see {@link ClassWriter#firstField firstField}). */ FieldWriter next; /** * The class writer to which this field must be added. */ private final ClassWriter cw; /** * Access flags of this field. */ private final int access; /** * The index of the constant pool item that contains the name of this * method. */ private final int name; /** * The index of the constant pool item that contains the descriptor of this * field. */ private final int desc; /** * The index of the constant pool item that contains the signature of this * field. */ private int signature; /** * The index of the constant pool item that contains the constant value of * this field. */ private int value; /** * The runtime visible annotations of this field. May be null. */ private AnnotationWriter anns; /** * The runtime invisible annotations of this field. May be null. */ private AnnotationWriter ianns; /** * The non standard attributes of this field. May be null. */ private Attribute attrs; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructs a new {@link FieldWriter}. * * @param cw the class writer to which this field must be added. * @param access the field's access flags (see {@link Opcodes}). * @param name the field's name. * @param desc the field's descriptor (see {@link Type}). * @param signature the field's signature. May be null. * @param value the field's constant value. May be null. */ FieldWriter( final ClassWriter cw, final int access, final String name, final String desc, final String signature, final Object value) { if (cw.firstField == null) { cw.firstField = this; } else { cw.lastField.next = this; } cw.lastField = this; this.cw = cw; this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); if (ClassReader.SIGNATURES && signature != null) { this.signature = cw.newUTF8(signature); } if (value != null) { this.value = cw.newConstItem(value).index; } } // ------------------------------------------------------------------------ // Implementation of the FieldVisitor interface // ------------------------------------------------------------------------ public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(cw.newUTF8(desc)).putShort(0); AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); if (visible) { aw.next = anns; anns = aw; } else { aw.next = ianns; ianns = aw; } return aw; } public void visitAttribute(final Attribute attr) { attr.next = attrs; attrs = attr; } public void visitEnd() { } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Returns the size of this field. * * @return the size of this field. */ int getSize() { int size = 8; if (value != 0) { cw.newUTF8("ConstantValue"); size += 8; } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { cw.newUTF8("Synthetic"); size += 6; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cw.newUTF8("Deprecated"); size += 6; } if (ClassReader.SIGNATURES && signature != 0) { cw.newUTF8("Signature"); size += 8; } if (ClassReader.ANNOTATIONS && anns != null) { cw.newUTF8("RuntimeVisibleAnnotations"); size += 8 + anns.getSize(); } if (ClassReader.ANNOTATIONS && ianns != null) { cw.newUTF8("RuntimeInvisibleAnnotations"); size += 8 + ianns.getSize(); } if (attrs != null) { size += attrs.getSize(cw, null, 0, -1, -1); } return size; } /** * Puts the content of this field into the given byte vector. * * @param out where the content of this field must be put. */ void put(final ByteVector out) { int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); out.putShort(access & ~mask).putShort(name).putShort(desc); int attributeCount = 0; if (value != 0) { ++attributeCount; } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { ++attributeCount; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; } if (ClassReader.SIGNATURES && signature != 0) { ++attributeCount; } if (ClassReader.ANNOTATIONS && anns != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && ianns != null) { ++attributeCount; } if (attrs != null) { attributeCount += attrs.getCount(); } out.putShort(attributeCount); if (value != 0) { out.putShort(cw.newUTF8("ConstantValue")); out.putInt(2).putShort(value); } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { out.putShort(cw.newUTF8("Synthetic")).putInt(0); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } if (ClassReader.SIGNATURES && signature != 0) { out.putShort(cw.newUTF8("Signature")); out.putInt(2).putShort(signature); } if (ClassReader.ANNOTATIONS && anns != null) { out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } if (ClassReader.ANNOTATIONS && ianns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } if (attrs != null) { attrs.put(cw, null, 0, -1, -1, out); } } } asm-3.3.2/src/org/objectweb/asm/Opcodes.java0000644000175000017500000002521111366756346020620 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * Defines the JVM opcodes, access flags and array type codes. This interface * does not define all the JVM opcodes because some opcodes are automatically * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n * opcodes are therefore not defined in this interface. Likewise for LDC, * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and * JSR_W. * * @author Eric Bruneton * @author Eugene Kuleshov */ public interface Opcodes { // versions int V1_1 = 3 << 16 | 45; int V1_2 = 0 << 16 | 46; int V1_3 = 0 << 16 | 47; int V1_4 = 0 << 16 | 48; int V1_5 = 0 << 16 | 49; int V1_6 = 0 << 16 | 50; int V1_7 = 0 << 16 | 51; // access flags int ACC_PUBLIC = 0x0001; // class, field, method int ACC_PRIVATE = 0x0002; // class, field, method int ACC_PROTECTED = 0x0004; // class, field, method int ACC_STATIC = 0x0008; // field, method int ACC_FINAL = 0x0010; // class, field, method int ACC_SUPER = 0x0020; // class int ACC_SYNCHRONIZED = 0x0020; // method int ACC_VOLATILE = 0x0040; // field int ACC_BRIDGE = 0x0040; // method int ACC_VARARGS = 0x0080; // method int ACC_TRANSIENT = 0x0080; // field int ACC_NATIVE = 0x0100; // method int ACC_INTERFACE = 0x0200; // class int ACC_ABSTRACT = 0x0400; // class, method int ACC_STRICT = 0x0800; // method int ACC_SYNTHETIC = 0x1000; // class, field, method int ACC_ANNOTATION = 0x2000; // class int ACC_ENUM = 0x4000; // class(?) field inner // ASM specific pseudo access flags int ACC_DEPRECATED = 0x20000; // class, field, method // types for NEWARRAY int T_BOOLEAN = 4; int T_CHAR = 5; int T_FLOAT = 6; int T_DOUBLE = 7; int T_BYTE = 8; int T_SHORT = 9; int T_INT = 10; int T_LONG = 11; // stack map frame types /** * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */ int F_NEW = -1; /** * Represents a compressed frame with complete frame data. */ int F_FULL = 0; /** * Represents a compressed frame where locals are the same as the locals in * the previous frame, except that additional 1-3 locals are defined, and * with an empty stack. */ int F_APPEND = 1; /** * Represents a compressed frame where locals are the same as the locals in * the previous frame, except that the last 1-3 locals are absent and with * an empty stack. */ int F_CHOP = 2; /** * Represents a compressed frame with exactly the same locals as the * previous frame and with an empty stack. */ int F_SAME = 3; /** * Represents a compressed frame with exactly the same locals as the * previous frame and with a single value on the stack. */ int F_SAME1 = 4; Integer TOP = new Integer(0); Integer INTEGER = new Integer(1); Integer FLOAT = new Integer(2); Integer DOUBLE = new Integer(3); Integer LONG = new Integer(4); Integer NULL = new Integer(5); Integer UNINITIALIZED_THIS = new Integer(6); /** * Represents a owner of an invokedynamic call. */ String INVOKEDYNAMIC_OWNER = "java/lang/dyn/Dynamic"; // 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 INVOKEDYNAMIC = 186; // - 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; // - } asm-3.3.2/src/org/objectweb/asm/util/0000755000175000017500000000000011633370220017311 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/util/CheckMethodAdapter.java0000644000175000017500000014023211503342725023642 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Attribute; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Analyzer; import org.objectweb.asm.tree.analysis.BasicVerifier; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** * A {@link MethodAdapter} that checks that its methods are properly used. More * precisely this method adapter checks each instruction individually, i.e., * each visit method checks some preconditions based only on its * arguments - such as the fact that the given opcode is correct for a given * visit method. This adapter can also perform some basic data flow checks (more * precisely those that can be performed without the full class hierarchy - see * {@link org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a * method whose signature is void m (), the invalid instruction * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow * checks are enabled. These checks are enabled by using the {@link * CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They * are not performed if any other constructor is used. * * @author Eric Bruneton */ public class CheckMethodAdapter extends MethodAdapter { /** * The class version number. */ public int version; /** * true if the visitCode method has been called. */ private boolean startCode; /** * true if the visitMaxs method has been called. */ private boolean endCode; /** * true if the visitEnd method has been called. */ private boolean endMethod; /** * The already visited labels. This map associate Integer values to Label * keys. */ private final Map labels; /** * Code of the visit method to be used for each opcode. */ private static final int[] TYPE; /** * The Label.status field. */ private static Field labelStatusField; static { String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD" + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD" + "KLBBBBBBFFFFGGGGGECEBBEEBBAMHHAA"; TYPE = new int[s.length()]; for (int i = 0; i < TYPE.length; ++i) { TYPE[i] = s.charAt(i) - 'A' - 1; } } // code to generate the above string // public static void main (String[] args) { // int[] TYPE = new int[] { // 0, //NOP // 0, //ACONST_NULL // 0, //ICONST_M1 // 0, //ICONST_0 // 0, //ICONST_1 // 0, //ICONST_2 // 0, //ICONST_3 // 0, //ICONST_4 // 0, //ICONST_5 // 0, //LCONST_0 // 0, //LCONST_1 // 0, //FCONST_0 // 0, //FCONST_1 // 0, //FCONST_2 // 0, //DCONST_0 // 0, //DCONST_1 // 1, //BIPUSH // 1, //SIPUSH // 7, //LDC // -1, //LDC_W // -1, //LDC2_W // 2, //ILOAD // 2, //LLOAD // 2, //FLOAD // 2, //DLOAD // 2, //ALOAD // -1, //ILOAD_0 // -1, //ILOAD_1 // -1, //ILOAD_2 // -1, //ILOAD_3 // -1, //LLOAD_0 // -1, //LLOAD_1 // -1, //LLOAD_2 // -1, //LLOAD_3 // -1, //FLOAD_0 // -1, //FLOAD_1 // -1, //FLOAD_2 // -1, //FLOAD_3 // -1, //DLOAD_0 // -1, //DLOAD_1 // -1, //DLOAD_2 // -1, //DLOAD_3 // -1, //ALOAD_0 // -1, //ALOAD_1 // -1, //ALOAD_2 // -1, //ALOAD_3 // 0, //IALOAD // 0, //LALOAD // 0, //FALOAD // 0, //DALOAD // 0, //AALOAD // 0, //BALOAD // 0, //CALOAD // 0, //SALOAD // 2, //ISTORE // 2, //LSTORE // 2, //FSTORE // 2, //DSTORE // 2, //ASTORE // -1, //ISTORE_0 // -1, //ISTORE_1 // -1, //ISTORE_2 // -1, //ISTORE_3 // -1, //LSTORE_0 // -1, //LSTORE_1 // -1, //LSTORE_2 // -1, //LSTORE_3 // -1, //FSTORE_0 // -1, //FSTORE_1 // -1, //FSTORE_2 // -1, //FSTORE_3 // -1, //DSTORE_0 // -1, //DSTORE_1 // -1, //DSTORE_2 // -1, //DSTORE_3 // -1, //ASTORE_0 // -1, //ASTORE_1 // -1, //ASTORE_2 // -1, //ASTORE_3 // 0, //IASTORE // 0, //LASTORE // 0, //FASTORE // 0, //DASTORE // 0, //AASTORE // 0, //BASTORE // 0, //CASTORE // 0, //SASTORE // 0, //POP // 0, //POP2 // 0, //DUP // 0, //DUP_X1 // 0, //DUP_X2 // 0, //DUP2 // 0, //DUP2_X1 // 0, //DUP2_X2 // 0, //SWAP // 0, //IADD // 0, //LADD // 0, //FADD // 0, //DADD // 0, //ISUB // 0, //LSUB // 0, //FSUB // 0, //DSUB // 0, //IMUL // 0, //LMUL // 0, //FMUL // 0, //DMUL // 0, //IDIV // 0, //LDIV // 0, //FDIV // 0, //DDIV // 0, //IREM // 0, //LREM // 0, //FREM // 0, //DREM // 0, //INEG // 0, //LNEG // 0, //FNEG // 0, //DNEG // 0, //ISHL // 0, //LSHL // 0, //ISHR // 0, //LSHR // 0, //IUSHR // 0, //LUSHR // 0, //IAND // 0, //LAND // 0, //IOR // 0, //LOR // 0, //IXOR // 0, //LXOR // 8, //IINC // 0, //I2L // 0, //I2F // 0, //I2D // 0, //L2I // 0, //L2F // 0, //L2D // 0, //F2I // 0, //F2L // 0, //F2D // 0, //D2I // 0, //D2L // 0, //D2F // 0, //I2B // 0, //I2C // 0, //I2S // 0, //LCMP // 0, //FCMPL // 0, //FCMPG // 0, //DCMPL // 0, //DCMPG // 6, //IFEQ // 6, //IFNE // 6, //IFLT // 6, //IFGE // 6, //IFGT // 6, //IFLE // 6, //IF_ICMPEQ // 6, //IF_ICMPNE // 6, //IF_ICMPLT // 6, //IF_ICMPGE // 6, //IF_ICMPGT // 6, //IF_ICMPLE // 6, //IF_ACMPEQ // 6, //IF_ACMPNE // 6, //GOTO // 6, //JSR // 2, //RET // 9, //TABLESWITCH // 10, //LOOKUPSWITCH // 0, //IRETURN // 0, //LRETURN // 0, //FRETURN // 0, //DRETURN // 0, //ARETURN // 0, //RETURN // 4, //GETSTATIC // 4, //PUTSTATIC // 4, //GETFIELD // 4, //PUTFIELD // 5, //INVOKEVIRTUAL // 5, //INVOKESPECIAL // 5, //INVOKESTATIC // 5, //INVOKEINTERFACE // 5, //INVOKEDYNAMIC // 3, //NEW // 1, //NEWARRAY // 3, //ANEWARRAY // 0, //ARRAYLENGTH // 0, //ATHROW // 3, //CHECKCAST // 3, //INSTANCEOF // 0, //MONITORENTER // 0, //MONITOREXIT // -1, //WIDE // 11, //MULTIANEWARRAY // 6, //IFNULL // 6, //IFNONNULL // -1, //GOTO_W // -1 //JSR_W // }; // for (int i = 0; i < TYPE.length; ++i) { // System.out.print((char)(TYPE[i] + 1 + 'A')); // } // System.out.println(); // } /** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will not perform any data flow check (see {@link * CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * * @param mv the method visitor to which this adapter must delegate calls. */ public CheckMethodAdapter(final MethodVisitor mv) { this(mv, new HashMap()); } /** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will not perform any data flow check (see {@link * CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * * @param mv the method visitor to which this adapter must delegate calls. * @param labels a map of already visited labels (in other methods). */ public CheckMethodAdapter(final MethodVisitor mv, final Map labels) { super(mv); this.labels = labels; } /** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will perform basic data flow checks. For instance in a method whose * signature is void m (), the invalid instruction IRETURN, or * the invalid sequence IADD L2I will be detected. * * @param access the method's access flags. * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param mv the method visitor to which this adapter must delegate calls. * @param labels a map of already visited labels (in other methods). */ public CheckMethodAdapter( final int access, final String name, final String desc, final MethodVisitor mv, final Map labels) { this(new MethodNode(access, name, desc, null, null) { public void visitEnd() { Analyzer a = new Analyzer(new BasicVerifier()); try { a.analyze("dummy", this); } catch (Exception e) { if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) { throw new RuntimeException("Data flow checking option requires valid, non zero maxLocals and maxStack values."); } e.printStackTrace(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); CheckClassAdapter.printAnalyzerResult(this, a, pw); pw.close(); throw new RuntimeException(e.getMessage() + ' ' + sw.toString()); } accept(mv); } }, labels); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { checkEndMethod(); checkDesc(desc, false); return new CheckAnnotationAdapter(mv.visitAnnotation(desc, visible)); } public AnnotationVisitor visitAnnotationDefault() { checkEndMethod(); return new CheckAnnotationAdapter(mv.visitAnnotationDefault(), false); } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { checkEndMethod(); checkDesc(desc, false); return new CheckAnnotationAdapter(mv.visitParameterAnnotation(parameter, desc, visible)); } public void visitAttribute(final Attribute attr) { checkEndMethod(); if (attr == null) { throw new IllegalArgumentException("Invalid attribute (must not be null)"); } mv.visitAttribute(attr); } public void visitCode() { startCode = true; mv.visitCode(); } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { int mLocal; int mStack; switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: mLocal = Integer.MAX_VALUE; mStack = Integer.MAX_VALUE; break; case Opcodes.F_SAME: mLocal = 0; mStack = 0; break; case Opcodes.F_SAME1: mLocal = 0; mStack = 1; break; case Opcodes.F_APPEND: case Opcodes.F_CHOP: mLocal = 3; mStack = 0; break; default: throw new IllegalArgumentException("Invalid frame type " + type); } if (nLocal > mLocal) { throw new IllegalArgumentException("Invalid nLocal=" + nLocal + " for frame type " + type); } if (nStack > mStack) { throw new IllegalArgumentException("Invalid nStack=" + nStack + " for frame type " + type); } if (type != Opcodes.F_CHOP) { if (nLocal > 0 && (local == null || local.length < nLocal)) { throw new IllegalArgumentException("Array local[] is shorter than nLocal"); } for (int i = 0; i < nLocal; ++i) { checkFrameValue(local[i]); } } if (nStack > 0 && (stack == null || stack.length < nStack)) { throw new IllegalArgumentException("Array stack[] is shorter than nStack"); } for (int i = 0; i < nStack; ++i) { checkFrameValue(stack[i]); } mv.visitFrame(type, nLocal, local, nStack, stack); } public void visitInsn(final int opcode) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 0); mv.visitInsn(opcode); } public void visitIntInsn(final int opcode, final int operand) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 1); switch (opcode) { case Opcodes.BIPUSH: checkSignedByte(operand, "Invalid operand"); break; case Opcodes.SIPUSH: checkSignedShort(operand, "Invalid operand"); break; // case Constants.NEWARRAY: default: if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { throw new IllegalArgumentException("Invalid operand (must be an array type code T_...): " + operand); } } mv.visitIntInsn(opcode, operand); } public void visitVarInsn(final int opcode, final int var) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 2); checkUnsignedShort(var, "Invalid variable index"); mv.visitVarInsn(opcode, var); } public void visitTypeInsn(final int opcode, final String type) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 3); checkInternalName(type, "type"); if (opcode == Opcodes.NEW && type.charAt(0) == '[') { throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type); } mv.visitTypeInsn(opcode, type); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 4); checkInternalName(owner, "owner"); checkUnqualifiedName(version, name, "name"); checkDesc(desc, false); mv.visitFieldInsn(opcode, owner, name, desc); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 5); checkMethodIdentifier(version, name, "name"); checkInternalName(owner, "owner"); checkMethodDesc(desc); if (opcode == Opcodes.INVOKEDYNAMIC && owner != Opcodes.INVOKEDYNAMIC_OWNER) { throw new IllegalArgumentException("INVOKEDYNAMIC cannot be used with another owner than INVOKEDYNAMIC_OWNER"); } mv.visitMethodInsn(opcode, owner, name, desc); } public void visitJumpInsn(final int opcode, final Label label) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 6); checkLabel(label, false, "label"); checkNonDebugLabel(label); mv.visitJumpInsn(opcode, label); } public void visitLabel(final Label label) { checkStartCode(); checkEndCode(); checkLabel(label, false, "label"); if (labels.get(label) != null) { throw new IllegalArgumentException("Already visited label"); } labels.put(label, new Integer(labels.size())); mv.visitLabel(label); } public void visitLdcInsn(final Object cst) { checkStartCode(); checkEndCode(); if (!(cst instanceof Type)) { checkConstant(cst); } mv.visitLdcInsn(cst); } public void visitIincInsn(final int var, final int increment) { checkStartCode(); checkEndCode(); checkUnsignedShort(var, "Invalid variable index"); checkSignedShort(increment, "Invalid increment"); mv.visitIincInsn(var, increment); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { checkStartCode(); checkEndCode(); if (max < min) { throw new IllegalArgumentException("Max = " + max + " must be greater than or equal to min = " + min); } checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (labels == null || labels.length != max - min + 1) { throw new IllegalArgumentException("There must be max - min + 1 labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); checkNonDebugLabel(labels[i]); } mv.visitTableSwitchInsn(min, max, dflt, labels); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { checkEndCode(); checkStartCode(); checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (keys == null || labels == null || keys.length != labels.length) { throw new IllegalArgumentException("There must be the same number of keys and labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); checkNonDebugLabel(labels[i]); } mv.visitLookupSwitchInsn(dflt, keys, labels); } public void visitMultiANewArrayInsn(final String desc, final int dims) { checkStartCode(); checkEndCode(); checkDesc(desc, false); if (desc.charAt(0) != '[') { throw new IllegalArgumentException("Invalid descriptor (must be an array type descriptor): " + desc); } if (dims < 1) { throw new IllegalArgumentException("Invalid dimensions (must be greater than 0): " + dims); } if (dims > desc.lastIndexOf('[') + 1) { throw new IllegalArgumentException("Invalid dimensions (must not be greater than dims(desc)): " + dims); } mv.visitMultiANewArrayInsn(desc, dims); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { checkStartCode(); checkEndCode(); checkLabel(start, false, "start label"); checkLabel(end, false, "end label"); checkLabel(handler, false, "handler label"); checkNonDebugLabel(start); checkNonDebugLabel(end); checkNonDebugLabel(handler); if (labels.get(start) != null || labels.get(end) != null || labels.get(handler) != null) { throw new IllegalStateException("Try catch blocks must be visited before their labels"); } if (type != null) { checkInternalName(type, "type"); } mv.visitTryCatchBlock(start, end, handler, type); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { checkStartCode(); checkEndCode(); checkUnqualifiedName(version, name, "name"); checkDesc(desc, false); checkLabel(start, true, "start label"); checkLabel(end, true, "end label"); checkUnsignedShort(index, "Invalid variable index"); int s = ((Integer) labels.get(start)).intValue(); int e = ((Integer) labels.get(end)).intValue(); if (e < s) { throw new IllegalArgumentException("Invalid start and end labels (end must be greater than start)"); } mv.visitLocalVariable(name, desc, signature, start, end, index); } public void visitLineNumber(final int line, final Label start) { checkStartCode(); checkEndCode(); checkUnsignedShort(line, "Invalid line number"); checkLabel(start, true, "start label"); mv.visitLineNumber(line, start); } public void visitMaxs(final int maxStack, final int maxLocals) { checkStartCode(); checkEndCode(); endCode = true; checkUnsignedShort(maxStack, "Invalid max stack"); checkUnsignedShort(maxLocals, "Invalid max locals"); mv.visitMaxs(maxStack, maxLocals); } public void visitEnd() { checkEndMethod(); endMethod = true; mv.visitEnd(); } // ------------------------------------------------------------------------- /** * Checks that the visitCode method has been called. */ void checkStartCode() { if (!startCode) { throw new IllegalStateException("Cannot visit instructions before visitCode has been called."); } } /** * Checks that the visitMaxs method has not been called. */ void checkEndCode() { if (endCode) { throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called."); } } /** * Checks that the visitEnd method has not been called. */ void checkEndMethod() { if (endMethod) { throw new IllegalStateException("Cannot visit elements after visitEnd has been called."); } } /** * Checks a stack frame value. * * @param value the value to be checked. */ static void checkFrameValue(final Object value) { if (value == Opcodes.TOP || value == Opcodes.INTEGER || value == Opcodes.FLOAT || value == Opcodes.LONG || value == Opcodes.DOUBLE || value == Opcodes.NULL || value == Opcodes.UNINITIALIZED_THIS) { return; } if (value instanceof String) { checkInternalName((String) value, "Invalid stack frame value"); return; } if (!(value instanceof Label)) { throw new IllegalArgumentException("Invalid stack frame value: " + value); } } /** * Checks that the type of the given opcode is equal to the given type. * * @param opcode the opcode to be checked. * @param type the expected opcode type. */ static void checkOpcode(final int opcode, final int type) { if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { throw new IllegalArgumentException("Invalid opcode: " + opcode); } } /** * Checks that the given value is a signed byte. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkSignedByte(final int value, final String msg) { if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { throw new IllegalArgumentException(msg + " (must be a signed byte): " + value); } } /** * Checks that the given value is a signed short. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkSignedShort(final int value, final String msg) { if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { throw new IllegalArgumentException(msg + " (must be a signed short): " + value); } } /** * Checks that the given value is an unsigned short. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkUnsignedShort(final int value, final String msg) { if (value < 0 || value > 65535) { throw new IllegalArgumentException(msg + " (must be an unsigned short): " + value); } } /** * Checks that the given value is an {@link Integer}, a{@link Float}, a * {@link Long}, a {@link Double} or a {@link String}. * * @param cst the value to be checked. */ static void checkConstant(final Object cst) { if (!(cst instanceof Integer) && !(cst instanceof Float) && !(cst instanceof Long) && !(cst instanceof Double) && !(cst instanceof String)) { throw new IllegalArgumentException("Invalid constant: " + cst); } } /** * Checks that the given string is a valid unqualified name. * * @param version the class version. * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkUnqualifiedName(int version, final String name, final String msg) { if ((version & 0xFFFF) < Opcodes.V1_5) { checkIdentifier(name, msg); } else { for (int i = 0; i < name.length(); ++i) { if (".;[/".indexOf(name.charAt(i)) != -1) { throw new IllegalArgumentException("Invalid " + msg + " (must be a valid unqualified name): " + name); } } } } /** * Checks that the given string is a valid Java identifier. * * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkIdentifier(final String name, final String msg) { checkIdentifier(name, 0, -1, msg); } /** * Checks that the given substring is a valid Java identifier. * * @param name the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param end index of the last character of the identifier (exclusive). -1 * is equivalent to name.length() if name is not * null. * @param msg a message to be used in case of error. */ static void checkIdentifier( final String name, final int start, final int end, final String msg) { if (name == null || (end == -1 ? name.length() <= start : end <= start)) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null or empty)"); } if (!Character.isJavaIdentifierStart(name.charAt(start))) { throw new IllegalArgumentException("Invalid " + msg + " (must be a valid Java identifier): " + name); } int max = end == -1 ? name.length() : end; for (int i = start + 1; i < max; ++i) { if (!Character.isJavaIdentifierPart(name.charAt(i))) { throw new IllegalArgumentException("Invalid " + msg + " (must be a valid Java identifier): " + name); } } } /** * Checks that the given string is a valid Java identifier or is equal to * '<init>' or '<clinit>'. * * @param version the class version. * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkMethodIdentifier(int version, final String name, final String msg) { if (name == null || name.length() == 0) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null or empty)"); } if ("".equals(name) || "".equals(name)) { return; } if ((version & 0xFFFF) >= Opcodes.V1_5) { for (int i = 0; i < name.length(); ++i) { if (".;[/<>".indexOf(name.charAt(i)) != -1) { throw new IllegalArgumentException("Invalid " + msg + " (must be a valid unqualified name): " + name); } } return; } if (!Character.isJavaIdentifierStart(name.charAt(0))) { throw new IllegalArgumentException("Invalid " + msg + " (must be a '', '' or a valid Java identifier): " + name); } for (int i = 1; i < name.length(); ++i) { if (!Character.isJavaIdentifierPart(name.charAt(i))) { throw new IllegalArgumentException("Invalid " + msg + " (must be '' or '' or a valid Java identifier): " + name); } } } /** * Checks that the given string is a valid internal class name. * * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkInternalName(final String name, final String msg) { if (name == null || name.length() == 0) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null or empty)"); } if (name.charAt(0) == '[') { checkDesc(name, false); } else { checkInternalName(name, 0, -1, msg); } } /** * Checks that the given substring is a valid internal class name. * * @param name the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param end index of the last character of the identifier (exclusive). -1 * is equivalent to name.length() if name is not * null. * @param msg a message to be used in case of error. */ static void checkInternalName( final String name, final int start, final int end, final String msg) { int max = end == -1 ? name.length() : end; try { int begin = start; int slash; do { slash = name.indexOf('/', begin + 1); if (slash == -1 || slash > max) { slash = max; } checkIdentifier(name, begin, slash, null); begin = slash + 1; } while (slash != max); } catch (IllegalArgumentException _) { throw new IllegalArgumentException("Invalid " + msg + " (must be a fully qualified class name in internal form): " + name); } } /** * Checks that the given string is a valid type descriptor. * * @param desc the string to be checked. * @param canBeVoid true if V can be considered valid. */ static void checkDesc(final String desc, final boolean canBeVoid) { int end = checkDesc(desc, 0, canBeVoid); if (end != desc.length()) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that a the given substring is a valid type descriptor. * * @param desc the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param canBeVoid true if V can be considered valid. * @return the index of the last character of the type decriptor, plus one. */ static int checkDesc( final String desc, final int start, final boolean canBeVoid) { if (desc == null || start >= desc.length()) { throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)"); } int index; switch (desc.charAt(start)) { case 'V': if (canBeVoid) { return start + 1; } else { throw new IllegalArgumentException("Invalid descriptor: " + desc); } case 'Z': case 'C': case 'B': case 'S': case 'I': case 'F': case 'J': case 'D': return start + 1; case '[': index = start + 1; while (index < desc.length() && desc.charAt(index) == '[') { ++index; } if (index < desc.length()) { return checkDesc(desc, index, false); } else { throw new IllegalArgumentException("Invalid descriptor: " + desc); } case 'L': index = desc.indexOf(';', start); if (index == -1 || index - start < 2) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } try { checkInternalName(desc, start + 1, index, null); } catch (IllegalArgumentException _) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } return index + 1; default: throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that the given string is a valid method descriptor. * * @param desc the string to be checked. */ static void checkMethodDesc(final String desc) { if (desc == null || desc.length() == 0) { throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)"); } if (desc.charAt(0) != '(' || desc.length() < 3) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } int start = 1; if (desc.charAt(start) != ')') { do { if (desc.charAt(start) == 'V') { throw new IllegalArgumentException("Invalid descriptor: " + desc); } start = checkDesc(desc, start, false); } while (start < desc.length() && desc.charAt(start) != ')'); } start = checkDesc(desc, start + 1, true); if (start != desc.length()) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks a class signature. * * @param signature a string containing the signature that must be checked. */ static void checkClassSignature(final String signature) { // ClassSignature: // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* int pos = 0; if (getChar(signature, 0) == '<') { pos = checkFormalTypeParameters(signature, pos); } pos = checkClassTypeSignature(signature, pos); while (getChar(signature, pos) == 'L') { pos = checkClassTypeSignature(signature, pos); } if (pos != signature.length()) { throw new IllegalArgumentException(signature + ": error at index " + pos); } } /** * Checks a method signature. * * @param signature a string containing the signature that must be checked. */ static void checkMethodSignature(final String signature) { // MethodTypeSignature: // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( // ^ClassTypeSignature | ^TypeVariableSignature )* int pos = 0; if (getChar(signature, 0) == '<') { pos = checkFormalTypeParameters(signature, pos); } pos = checkChar('(', signature, pos); while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { pos = checkTypeSignature(signature, pos); } pos = checkChar(')', signature, pos); if (getChar(signature, pos) == 'V') { ++pos; } else { pos = checkTypeSignature(signature, pos); } while (getChar(signature, pos) == '^') { ++pos; if (getChar(signature, pos) == 'L') { pos = checkClassTypeSignature(signature, pos); } else { pos = checkTypeVariableSignature(signature, pos); } } if (pos != signature.length()) { throw new IllegalArgumentException(signature + ": error at index " + pos); } } /** * Checks a field signature. * * @param signature a string containing the signature that must be checked. */ static void checkFieldSignature(final String signature) { int pos = checkFieldTypeSignature(signature, 0); if (pos != signature.length()) { throw new IllegalArgumentException(signature + ": error at index " + pos); } } /** * Checks the formal type parameters of a class or method signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkFormalTypeParameters(final String signature, int pos) { // FormalTypeParameters: // < FormalTypeParameter+ > pos = checkChar('<', signature, pos); pos = checkFormalTypeParameter(signature, pos); while (getChar(signature, pos) != '>') { pos = checkFormalTypeParameter(signature, pos); } return pos + 1; } /** * Checks a formal type parameter of a class or method signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkFormalTypeParameter(final String signature, int pos) { // FormalTypeParameter: // Identifier : FieldTypeSignature? (: FieldTypeSignature)* pos = checkIdentifier(signature, pos); pos = checkChar(':', signature, pos); if ("L[T".indexOf(getChar(signature, pos)) != -1) { pos = checkFieldTypeSignature(signature, pos); } while (getChar(signature, pos) == ':') { pos = checkFieldTypeSignature(signature, pos + 1); } return pos; } /** * Checks a field type signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkFieldTypeSignature(final String signature, int pos) { // FieldTypeSignature: // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature // // ArrayTypeSignature: // [ TypeSignature switch (getChar(signature, pos)) { case 'L': return checkClassTypeSignature(signature, pos); case '[': return checkTypeSignature(signature, pos + 1); default: return checkTypeVariableSignature(signature, pos); } } /** * Checks a class type signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkClassTypeSignature(final String signature, int pos) { // ClassTypeSignature: // L Identifier ( / Identifier )* TypeArguments? ( . Identifier // TypeArguments? )* ; pos = checkChar('L', signature, pos); pos = checkIdentifier(signature, pos); while (getChar(signature, pos) == '/') { pos = checkIdentifier(signature, pos + 1); } if (getChar(signature, pos) == '<') { pos = checkTypeArguments(signature, pos); } while (getChar(signature, pos) == '.') { pos = checkIdentifier(signature, pos + 1); if (getChar(signature, pos) == '<') { pos = checkTypeArguments(signature, pos); } } return checkChar(';', signature, pos); } /** * Checks the type arguments in a class type signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkTypeArguments(final String signature, int pos) { // TypeArguments: // < TypeArgument+ > pos = checkChar('<', signature, pos); pos = checkTypeArgument(signature, pos); while (getChar(signature, pos) != '>') { pos = checkTypeArgument(signature, pos); } return pos + 1; } /** * Checks a type argument in a class type signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkTypeArgument(final String signature, int pos) { // TypeArgument: // * | ( ( + | - )? FieldTypeSignature ) char c = getChar(signature, pos); if (c == '*') { return pos + 1; } else if (c == '+' || c == '-') { pos++; } return checkFieldTypeSignature(signature, pos); } /** * Checks a type variable signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkTypeVariableSignature( final String signature, int pos) { // TypeVariableSignature: // T Identifier ; pos = checkChar('T', signature, pos); pos = checkIdentifier(signature, pos); return checkChar(';', signature, pos); } /** * Checks a type signature. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkTypeSignature(final String signature, int pos) { // TypeSignature: // Z | C | B | S | I | F | J | D | FieldTypeSignature switch (getChar(signature, pos)) { case 'Z': case 'C': case 'B': case 'S': case 'I': case 'F': case 'J': case 'D': return pos + 1; default: return checkFieldTypeSignature(signature, pos); } } /** * Checks an identifier. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkIdentifier(final String signature, int pos) { if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { throw new IllegalArgumentException(signature + ": identifier expected at index " + pos); } ++pos; while (Character.isJavaIdentifierPart(getChar(signature, pos))) { ++pos; } return pos; } /** * Checks a single character. * * @param signature a string containing the signature that must be checked. * @param pos index of first character to be checked. * @return the index of the first character after the checked part. */ private static int checkChar(final char c, final String signature, int pos) { if (getChar(signature, pos) == c) { return pos + 1; } throw new IllegalArgumentException(signature + ": '" + c + "' expected at index " + pos); } /** * Returns the signature car at the given index. * * @param signature a signature. * @param pos an index in signature. * @return the character at the given index, or 0 if there is no such * character. */ private static char getChar(final String signature, int pos) { return pos < signature.length() ? signature.charAt(pos) : (char) 0; } /** * Checks that the given label is not null. This method can also check that * the label has been visited. * * @param label the label to be checked. * @param checkVisited true to check that the label has been * visited. * @param msg a message to be used in case of error. */ void checkLabel( final Label label, final boolean checkVisited, final String msg) { if (label == null) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null)"); } if (checkVisited && labels.get(label) == null) { throw new IllegalArgumentException("Invalid " + msg + " (must be visited first)"); } } /** * Checks that the given lavel is not a label used only for debug purposes. * * @param label the label to be checked. */ private static void checkNonDebugLabel(final Label label) { Field f = getLabelStatusField(); int status = 0; try { status = f == null ? 0 : ((Integer) f.get(label)).intValue(); } catch (IllegalAccessException e) { throw new Error("Internal error"); } if ((status & 0x01) != 0) { throw new IllegalArgumentException("Labels used for debug info cannot be reused for control flow"); } } /** * Returns the Field object corresponding to the Label.status field. * * @return the Field object corresponding to the Label.status field. */ private static Field getLabelStatusField() { if (labelStatusField == null) { labelStatusField = getLabelField("a"); if (labelStatusField == null) { labelStatusField = getLabelField("status"); } } return labelStatusField; } /** * Returns the field of the Label class whose name is given. * * @param name a field name. * @return the field of the Label class whose name is given, or null. */ private static Field getLabelField(final String name) { try { Field f = Label.class.getDeclaredField(name); f.setAccessible(true); return f; } catch (NoSuchFieldException e) { return null; } } } asm-3.3.2/src/org/objectweb/asm/util/CheckAnnotationAdapter.java0000644000175000017500000001111110701747173024532 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Type; /** * An {@link AnnotationVisitor} that checks that its methods are properly used. * * @author Eric Bruneton */ public class CheckAnnotationAdapter implements AnnotationVisitor { private final AnnotationVisitor av; private final boolean named; private boolean end; public CheckAnnotationAdapter(final AnnotationVisitor av) { this(av, true); } CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) { this.av = av; this.named = named; } public void visit(final String name, final Object value) { checkEnd(); checkName(name); if (!(value instanceof Byte || value instanceof Boolean || value instanceof Character || value instanceof Short || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof String || value instanceof Type || value instanceof byte[] || value instanceof boolean[] || value instanceof char[] || value instanceof short[] || value instanceof int[] || value instanceof long[] || value instanceof float[] || value instanceof double[])) { throw new IllegalArgumentException("Invalid annotation value"); } if (av != null) { av.visit(name, value); } } public void visitEnum( final String name, final String desc, final String value) { checkEnd(); checkName(name); CheckMethodAdapter.checkDesc(desc, false); if (value == null) { throw new IllegalArgumentException("Invalid enum value"); } if (av != null) { av.visitEnum(name, desc, value); } } public AnnotationVisitor visitAnnotation( final String name, final String desc) { checkEnd(); checkName(name); CheckMethodAdapter.checkDesc(desc, false); return new CheckAnnotationAdapter(av == null ? null : av.visitAnnotation(name, desc)); } public AnnotationVisitor visitArray(final String name) { checkEnd(); checkName(name); return new CheckAnnotationAdapter(av == null ? null : av.visitArray(name), false); } public void visitEnd() { checkEnd(); end = true; if (av != null) { av.visitEnd(); } } private void checkEnd() { if (end) { throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); } } private void checkName(final String name) { if (named && name == null) { throw new IllegalArgumentException("Annotation value name must not be null"); } } } asm-3.3.2/src/org/objectweb/asm/util/ASMifierMethodVisitor.java0000644000175000017500000003412210701747173024350 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import java.util.HashMap; /** * A {@link MethodVisitor} that prints the ASM code that generates the methods * it visits. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class ASMifierMethodVisitor extends ASMifierAbstractVisitor implements MethodVisitor { /** * Constructs a new {@link ASMifierMethodVisitor} object. */ public ASMifierMethodVisitor() { super("mv"); this.labelNames = new HashMap(); } public AnnotationVisitor visitAnnotationDefault() { buf.setLength(0); buf.append("{\n").append("av0 = mv.visitAnnotationDefault();\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { buf.setLength(0); buf.append("{\n") .append("av0 = mv.visitParameterAnnotation(") .append(parameter) .append(", "); appendConstant(desc); buf.append(", ").append(visible).append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public void visitCode() { text.add("mv.visitCode();\n"); } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { buf.setLength(0); switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: declareFrameTypes(nLocal, local); declareFrameTypes(nStack, stack); if (type == Opcodes.F_NEW) { buf.append("mv.visitFrame(Opcodes.F_NEW, "); } else { buf.append("mv.visitFrame(Opcodes.F_FULL, "); } buf.append(nLocal).append(", new Object[] {"); appendFrameTypes(nLocal, local); buf.append("}, ").append(nStack).append(", new Object[] {"); appendFrameTypes(nStack, stack); buf.append('}'); break; case Opcodes.F_APPEND: declareFrameTypes(nLocal, local); buf.append("mv.visitFrame(Opcodes.F_APPEND,") .append(nLocal) .append(", new Object[] {"); appendFrameTypes(nLocal, local); buf.append("}, 0, null"); break; case Opcodes.F_CHOP: buf.append("mv.visitFrame(Opcodes.F_CHOP,") .append(nLocal) .append(", null, 0, null"); break; case Opcodes.F_SAME: buf.append("mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null"); break; case Opcodes.F_SAME1: declareFrameTypes(1, stack); buf.append("mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); appendFrameTypes(1, stack); buf.append('}'); break; } buf.append(");\n"); text.add(buf.toString()); } public void visitInsn(final int opcode) { buf.setLength(0); buf.append("mv.visitInsn(").append(OPCODES[opcode]).append(");\n"); text.add(buf.toString()); } public void visitIntInsn(final int opcode, final int operand) { buf.setLength(0); buf.append("mv.visitIntInsn(") .append(OPCODES[opcode]) .append(", ") .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand)) .append(");\n"); text.add(buf.toString()); } public void visitVarInsn(final int opcode, final int var) { buf.setLength(0); buf.append("mv.visitVarInsn(") .append(OPCODES[opcode]) .append(", ") .append(var) .append(");\n"); text.add(buf.toString()); } public void visitTypeInsn(final int opcode, final String type) { buf.setLength(0); buf.append("mv.visitTypeInsn(").append(OPCODES[opcode]).append(", "); appendConstant(type); buf.append(");\n"); text.add(buf.toString()); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); buf.append("mv.visitFieldInsn(").append(OPCODES[opcode]).append(", "); appendConstant(owner); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(");\n"); text.add(buf.toString()); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); buf.append("mv.visitMethodInsn(").append(OPCODES[opcode]).append(", "); appendConstant(owner); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(");\n"); text.add(buf.toString()); } public void visitJumpInsn(final int opcode, final Label label) { buf.setLength(0); declareLabel(label); buf.append("mv.visitJumpInsn(").append(OPCODES[opcode]).append(", "); appendLabel(label); buf.append(");\n"); text.add(buf.toString()); } public void visitLabel(final Label label) { buf.setLength(0); declareLabel(label); buf.append("mv.visitLabel("); appendLabel(label); buf.append(");\n"); text.add(buf.toString()); } public void visitLdcInsn(final Object cst) { buf.setLength(0); buf.append("mv.visitLdcInsn("); appendConstant(cst); buf.append(");\n"); text.add(buf.toString()); } public void visitIincInsn(final int var, final int increment) { buf.setLength(0); buf.append("mv.visitIincInsn(") .append(var) .append(", ") .append(increment) .append(");\n"); text.add(buf.toString()); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("mv.visitTableSwitchInsn(") .append(min) .append(", ") .append(max) .append(", "); appendLabel(dflt); buf.append(", new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" });\n"); text.add(buf.toString()); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("mv.visitLookupSwitchInsn("); appendLabel(dflt); buf.append(", new int[] {"); for (int i = 0; i < keys.length; ++i) { buf.append(i == 0 ? " " : ", ").append(keys[i]); } buf.append(" }, new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" });\n"); text.add(buf.toString()); } public void visitMultiANewArrayInsn(final String desc, final int dims) { buf.setLength(0); buf.append("mv.visitMultiANewArrayInsn("); appendConstant(desc); buf.append(", ").append(dims).append(");\n"); text.add(buf.toString()); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { buf.setLength(0); declareLabel(start); declareLabel(end); declareLabel(handler); buf.append("mv.visitTryCatchBlock("); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", "); appendLabel(handler); buf.append(", "); appendConstant(type); buf.append(");\n"); text.add(buf.toString()); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { buf.setLength(0); buf.append("mv.visitLocalVariable("); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(", "); appendConstant(signature); buf.append(", "); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", ").append(index).append(");\n"); text.add(buf.toString()); } public void visitLineNumber(final int line, final Label start) { buf.setLength(0); buf.append("mv.visitLineNumber(").append(line).append(", "); appendLabel(start); buf.append(");\n"); text.add(buf.toString()); } public void visitMaxs(final int maxStack, final int maxLocals) { buf.setLength(0); buf.append("mv.visitMaxs(") .append(maxStack) .append(", ") .append(maxLocals) .append(");\n"); text.add(buf.toString()); } private void declareFrameTypes(final int n, final Object[] o) { for (int i = 0; i < n; ++i) { if (o[i] instanceof Label) { declareLabel((Label) o[i]); } } } private void appendFrameTypes(final int n, final Object[] o) { for (int i = 0; i < n; ++i) { if (i > 0) { buf.append(", "); } if (o[i] instanceof String) { appendConstant(o[i]); } else if (o[i] instanceof Integer) { switch (((Integer) o[i]).intValue()) { case 0: buf.append("Opcodes.TOP"); break; case 1: buf.append("Opcodes.INTEGER"); break; case 2: buf.append("Opcodes.FLOAT"); break; case 3: buf.append("Opcodes.DOUBLE"); break; case 4: buf.append("Opcodes.LONG"); break; case 5: buf.append("Opcodes.NULL"); break; case 6: buf.append("Opcodes.UNINITIALIZED_THIS"); break; } } else { appendLabel((Label) o[i]); } } } /** * Appends a declaration of the given label to {@link #buf buf}. This * declaration is of the form "Label lXXX = new Label();". Does nothing if * the given label has already been declared. * * @param l a label. */ private void declareLabel(final Label l) { String name = (String) labelNames.get(l); if (name == null) { name = "l" + labelNames.size(); labelNames.put(l, name); buf.append("Label ").append(name).append(" = new Label();\n"); } } /** * Appends the name of the given label to {@link #buf buf}. The given label * must already have a name. One way to ensure this is to always * call {@link #declareLabel declared} before calling this method. * * @param l a label. */ private void appendLabel(final Label l) { buf.append((String) labelNames.get(l)); } } asm-3.3.2/src/org/objectweb/asm/util/ASMifiable.java0000644000175000017500000000451610635277351022132 0ustar twernertwerner/** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.util.Map; /** * An attribute that can print the ASM code to create an equivalent attribute. * * Implementation should print the ASM code that generates attribute data * structures for current attribute state. * * @author Eugene Kuleshov */ public interface ASMifiable { /** * Prints the ASM code to create an attribute equal to this attribute. * * @param buf A buffer used for printing Java code. * @param varName name of the variable in a printed code used to store * attribute instance. * @param labelNames map of label instances to their names. */ void asmify(StringBuffer buf, String varName, Map labelNames); } asm-3.3.2/src/org/objectweb/asm/util/AbstractVisitor.java0000644000175000017500000001706511211477631023316 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Attribute; /** * An abstract visitor. * * @author Eric Bruneton */ public abstract class AbstractVisitor { /** * The names of the Java Virtual Machine opcodes. */ public static final String[] OPCODES; /** * Types for operand parameter of the * {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when * opcode is NEWARRAY. */ public static final String[] TYPES; static { String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2," + "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0," + "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,," + "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD," + "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE," + "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE," + "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP," + "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD," + "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV," + "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL," + "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L," + "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP," + "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE," + "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE," + "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH," + "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC," + "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL," + "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY," + "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF," + "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,"; OPCODES = new String[200]; int i = 0; int j = 0; int l; while ((l = s.indexOf(',', j)) > 0) { OPCODES[i++] = j + 1 == l ? null : s.substring(j, l); j = l + 1; } s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,"; TYPES = new String[12]; j = 0; i = 4; while ((l = s.indexOf(',', j)) > 0) { TYPES[i++] = s.substring(j, l); j = l + 1; } } /** * The text to be printed. Since the code of methods is not necessarily * visited in sequential order, one method after the other, but can be * interlaced (some instructions from method one, then some instructions * from method two, then some instructions from method one again...), it is * not possible to print the visited instructions directly to a sequential * stream. A class is therefore printed in a two steps process: a string * tree is constructed during the visit, and printed to a sequential stream * at the end of the visit. This string tree is stored in this field, as a * string list that can contain other string lists, which can themselves * contain other string lists, and so on. */ public final List text; /** * A buffer that can be used to create strings. */ protected final StringBuffer buf; /** * Constructs a new {@link AbstractVisitor}. */ protected AbstractVisitor() { this.text = new ArrayList(); this.buf = new StringBuffer(); } /** * Returns the text constructed by this visitor. * * @return the text constructed by this visitor. */ public List getText() { return text; } /** * Prints the text constructed by this visitor. * * @param pw the print writer to be used. */ public void print(final PrintWriter pw) { printList(pw, text); } /** * Appends a quoted string to a given buffer. * * @param buf the buffer where the string must be added. * @param s the string to be added. */ public static void appendString(final StringBuffer buf, final String s) { buf.append('\"'); for (int i = 0; i < s.length(); ++i) { char c = s.charAt(i); if (c == '\n') { buf.append("\\n"); } else if (c == '\r') { buf.append("\\r"); } else if (c == '\\') { buf.append("\\\\"); } else if (c == '"') { buf.append("\\\""); } else if (c < 0x20 || c > 0x7f) { buf.append("\\u"); if (c < 0x10) { buf.append("000"); } else if (c < 0x100) { buf.append("00"); } else if (c < 0x1000) { buf.append('0'); } buf.append(Integer.toString(c, 16)); } else { buf.append(c); } } buf.append('\"'); } /** * Prints the given string tree. * * @param pw the writer to be used to print the tree. * @param l a string tree, i.e., a string list that can contain other string * lists, and so on recursively. */ static void printList(final PrintWriter pw, final List l) { for (int i = 0; i < l.size(); ++i) { Object o = l.get(i); if (o instanceof List) { printList(pw, (List) o); } else { pw.print(o.toString()); } } } /** * Returns the default {@link ASMifiable} prototypes. * * @return the default {@link ASMifiable} prototypes. */ public static Attribute[] getDefaultAttributes() { return new Attribute[0]; } } asm-3.3.2/src/org/objectweb/asm/util/ASMifierAbstractVisitor.java0000644000175000017500000002037210701747173024675 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.Type; import java.util.Map; /** * An abstract ASMifier visitor. * * @author Eric Bruneton */ public class ASMifierAbstractVisitor extends AbstractVisitor { /** * The name of the variable for this visitor in the produced code. */ protected String name; /** * The label names. This map associates String values to Label keys. It is * used only in ASMifierMethodVisitor. */ Map labelNames; /** * Constructs a new {@link ASMifierAbstractVisitor}. * * @param name the name of the variable for this visitor in the produced * code. */ protected ASMifierAbstractVisitor(final String name) { this.name = name; } /** * Prints the ASM code that generates the given annotation. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values. */ public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { buf.setLength(0); buf.append("{\n") .append("av0 = ") .append(name) .append(".visitAnnotation("); appendConstant(desc); buf.append(", ").append(visible).append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } /** * Prints the ASM code that generates the given attribute. * * @param attr an attribute. */ public void visitAttribute(final Attribute attr) { buf.setLength(0); buf.append("// ATTRIBUTE ").append(attr.type).append('\n'); if (attr instanceof ASMifiable) { buf.append("{\n"); ((ASMifiable) attr).asmify(buf, "attr", labelNames); buf.append(name).append(".visitAttribute(attr);\n"); buf.append("}\n"); } text.add(buf.toString()); } /** * Prints the ASM code to end the visit. */ public void visitEnd() { buf.setLength(0); buf.append(name).append(".visitEnd();\n"); text.add(buf.toString()); } /** * Appends a string representation of the given constant to the given * buffer. * * @param cst an {@link Integer}, {@link Float}, {@link Long}, * {@link Double} or {@link String} object. May be null. */ void appendConstant(final Object cst) { appendConstant(buf, cst); } /** * Appends a string representation of the given constant to the given * buffer. * * @param buf a string buffer. * @param cst an {@link Integer}, {@link Float}, {@link Long}, * {@link Double} or {@link String} object. May be null. */ static void appendConstant(final StringBuffer buf, final Object cst) { if (cst == null) { buf.append("null"); } else if (cst instanceof String) { appendString(buf, (String) cst); } else if (cst instanceof Type) { buf.append("Type.getType(\""); buf.append(((Type) cst).getDescriptor()); buf.append("\")"); } else if (cst instanceof Byte) { buf.append("new Byte((byte)").append(cst).append(')'); } else if (cst instanceof Boolean) { buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE"); } else if (cst instanceof Short) { buf.append("new Short((short)").append(cst).append(')'); } else if (cst instanceof Character) { int c = ((Character) cst).charValue(); buf.append("new Character((char)").append(c).append(')'); } else if (cst instanceof Integer) { buf.append("new Integer(").append(cst).append(')'); } else if (cst instanceof Float) { buf.append("new Float(\"").append(cst).append("\")"); } else if (cst instanceof Long) { buf.append("new Long(").append(cst).append("L)"); } else if (cst instanceof Double) { buf.append("new Double(\"").append(cst).append("\")"); } else if (cst instanceof byte[]) { byte[] v = (byte[]) cst; buf.append("new byte[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]); } buf.append('}'); } else if (cst instanceof boolean[]) { boolean[] v = (boolean[]) cst; buf.append("new boolean[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]); } buf.append('}'); } else if (cst instanceof short[]) { short[] v = (short[]) cst; buf.append("new short[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]); } buf.append('}'); } else if (cst instanceof char[]) { char[] v = (char[]) cst; buf.append("new char[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",") .append("(char)") .append((int) v[i]); } buf.append('}'); } else if (cst instanceof int[]) { int[] v = (int[]) cst; buf.append("new int[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]); } buf.append('}'); } else if (cst instanceof long[]) { long[] v = (long[]) cst; buf.append("new long[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]).append('L'); } buf.append('}'); } else if (cst instanceof float[]) { float[] v = (float[]) cst; buf.append("new float[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]).append('f'); } buf.append('}'); } else if (cst instanceof double[]) { double[] v = (double[]) cst; buf.append("new double[] {"); for (int i = 0; i < v.length; i++) { buf.append(i == 0 ? "" : ",").append(v[i]).append('d'); } buf.append('}'); } } } asm-3.3.2/src/org/objectweb/asm/util/package.html0000644000175000017500000000377110177716604021616 0ustar twernertwerner Provides ASM visitors that can be useful for programming and debugging purposes. These class visitors are normally not used by applications at runtime. This is why they are bundled in an optional asm-util.jar library that is separated from (but requires) the asm.jar library, which contains the core ASM framework. @since ASM 1.3.2 asm-3.3.2/src/org/objectweb/asm/util/TraceSignatureVisitor.java0000644000175000017500000002141710701747173024473 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.Opcodes; import org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} that prints a disassembled view of the signature * it visits. * * @author Eugene Kuleshov * @author Eric Bruneton */ public class TraceSignatureVisitor implements SignatureVisitor { private final StringBuffer declaration; private boolean isInterface; private boolean seenFormalParameter; private boolean seenInterfaceBound; private boolean seenParameter; private boolean seenInterface; private StringBuffer returnType; private StringBuffer exceptions; /** * Stack used to keep track of class types that have arguments. Each element * of this stack is a boolean encoded in one bit. The top of the stack is * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = * /2. */ private int argumentStack; /** * Stack used to keep track of array class types. Each element of this stack * is a boolean encoded in one bit. The top of the stack is the lowest order * bit. Pushing false = *2, pushing true = *2+1, popping = /2. */ private int arrayStack; private String separator = ""; public TraceSignatureVisitor(final int access) { isInterface = (access & Opcodes.ACC_INTERFACE) != 0; this.declaration = new StringBuffer(); } private TraceSignatureVisitor(final StringBuffer buf) { this.declaration = buf; } public void visitFormalTypeParameter(final String name) { declaration.append(seenFormalParameter ? ", " : "<").append(name); seenFormalParameter = true; seenInterfaceBound = false; } public SignatureVisitor visitClassBound() { separator = " extends "; startType(); return this; } public SignatureVisitor visitInterfaceBound() { separator = seenInterfaceBound ? ", " : " extends "; seenInterfaceBound = true; startType(); return this; } public SignatureVisitor visitSuperclass() { endFormals(); separator = " extends "; startType(); return this; } public SignatureVisitor visitInterface() { separator = seenInterface ? ", " : isInterface ? " extends " : " implements "; seenInterface = true; startType(); return this; } public SignatureVisitor visitParameterType() { endFormals(); if (seenParameter) { declaration.append(", "); } else { seenParameter = true; declaration.append('('); } startType(); return this; } public SignatureVisitor visitReturnType() { endFormals(); if (seenParameter) { seenParameter = false; } else { declaration.append('('); } declaration.append(')'); returnType = new StringBuffer(); return new TraceSignatureVisitor(returnType); } public SignatureVisitor visitExceptionType() { if (exceptions == null) { exceptions = new StringBuffer(); } else { exceptions.append(", "); } // startType(); return new TraceSignatureVisitor(exceptions); } public void visitBaseType(final char descriptor) { switch (descriptor) { case 'V': declaration.append("void"); break; case 'B': declaration.append("byte"); break; case 'J': declaration.append("long"); break; case 'Z': declaration.append("boolean"); break; case 'I': declaration.append("int"); break; case 'S': declaration.append("short"); break; case 'C': declaration.append("char"); break; case 'F': declaration.append("float"); break; // case 'D': default: declaration.append("double"); break; } endType(); } public void visitTypeVariable(final String name) { declaration.append(name); endType(); } public SignatureVisitor visitArrayType() { startType(); arrayStack |= 1; return this; } public void visitClassType(final String name) { if ("java/lang/Object".equals(name)) { // Map // or // abstract public V get(Object key); (seen in Dictionary.class) // should have Object // but java.lang.String extends java.lang.Object is unnecessary boolean needObjectClass = argumentStack % 2 != 0 || seenParameter; if (needObjectClass) { declaration.append(separator).append(name.replace('/', '.')); } } else { declaration.append(separator).append(name.replace('/', '.')); } separator = ""; argumentStack *= 2; } public void visitInnerClassType(final String name) { if (argumentStack % 2 != 0) { declaration.append('>'); } argumentStack /= 2; declaration.append('.'); declaration.append(separator).append(name.replace('/', '.')); separator = ""; argumentStack *= 2; } public void visitTypeArgument() { if (argumentStack % 2 == 0) { ++argumentStack; declaration.append('<'); } else { declaration.append(", "); } declaration.append('?'); } public SignatureVisitor visitTypeArgument(final char tag) { if (argumentStack % 2 == 0) { ++argumentStack; declaration.append('<'); } else { declaration.append(", "); } if (tag == EXTENDS) { declaration.append("? extends "); } else if (tag == SUPER) { declaration.append("? super "); } startType(); return this; } public void visitEnd() { if (argumentStack % 2 != 0) { declaration.append('>'); } argumentStack /= 2; endType(); } public String getDeclaration() { return declaration.toString(); } public String getReturnType() { return returnType == null ? null : returnType.toString(); } public String getExceptions() { return exceptions == null ? null : exceptions.toString(); } // ----------------------------------------------- private void endFormals() { if (seenFormalParameter) { declaration.append('>'); seenFormalParameter = false; } } private void startType() { arrayStack *= 2; } private void endType() { if (arrayStack % 2 == 0) { arrayStack /= 2; } else { while (arrayStack % 2 != 0) { arrayStack /= 2; declaration.append("[]"); } } } } asm-3.3.2/src/org/objectweb/asm/util/CheckSignatureAdapter.java0000644000175000017500000002246110701747173024373 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} that checks that its methods are properly used. * * @author Eric Bruneton */ public class CheckSignatureAdapter implements SignatureVisitor { /** * Type to be used to check class signatures. See * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. */ public static final int CLASS_SIGNATURE = 0; /** * Type to be used to check method signatures. See * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. */ public static final int METHOD_SIGNATURE = 1; /** * Type to be used to check type signatures.See * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. */ public static final int TYPE_SIGNATURE = 2; private static final int EMPTY = 1; private static final int FORMAL = 2; private static final int BOUND = 4; private static final int SUPER = 8; private static final int PARAM = 16; private static final int RETURN = 32; private static final int SIMPLE_TYPE = 64; private static final int CLASS_TYPE = 128; private static final int END = 256; /** * Type of the signature to be checked. */ private final int type; /** * State of the automaton used to check the order of method calls. */ private int state; /** * true if the checked type signature can be 'V'. */ private boolean canBeVoid; /** * The visitor to which this adapter must delegate calls. May be * null. */ private final SignatureVisitor sv; /** * Creates a new {@link CheckSignatureAdapter} object. * * @param type the type of signature to be checked. See * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and * {@link #TYPE_SIGNATURE}. * @param sv the visitor to which this adapter must delegate calls. May be * null. */ public CheckSignatureAdapter(final int type, final SignatureVisitor sv) { this.type = type; this.state = EMPTY; this.sv = sv; } // class and method signatures public void visitFormalTypeParameter(final String name) { if (type == TYPE_SIGNATURE || (state != EMPTY && state != FORMAL && state != BOUND)) { throw new IllegalStateException(); } CheckMethodAdapter.checkIdentifier(name, "formal type parameter"); state = FORMAL; if (sv != null) { sv.visitFormalTypeParameter(name); } } public SignatureVisitor visitClassBound() { if (state != FORMAL) { throw new IllegalStateException(); } state = BOUND; SignatureVisitor v = sv == null ? null : sv.visitClassBound(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } public SignatureVisitor visitInterfaceBound() { if (state != FORMAL && state != BOUND) { throw new IllegalArgumentException(); } SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } // class signatures public SignatureVisitor visitSuperclass() { if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) { throw new IllegalArgumentException(); } state = SUPER; SignatureVisitor v = sv == null ? null : sv.visitSuperclass(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } public SignatureVisitor visitInterface() { if (state != SUPER) { throw new IllegalStateException(); } SignatureVisitor v = sv == null ? null : sv.visitInterface(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } // method signatures public SignatureVisitor visitParameterType() { if (type != METHOD_SIGNATURE || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { throw new IllegalArgumentException(); } state = PARAM; SignatureVisitor v = sv == null ? null : sv.visitParameterType(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } public SignatureVisitor visitReturnType() { if (type != METHOD_SIGNATURE || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { throw new IllegalArgumentException(); } state = RETURN; SignatureVisitor v = sv == null ? null : sv.visitReturnType(); CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v); cv.canBeVoid = true; return cv; } public SignatureVisitor visitExceptionType() { if (state != RETURN) { throw new IllegalStateException(); } SignatureVisitor v = sv == null ? null : sv.visitExceptionType(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } // type signatures public void visitBaseType(final char descriptor) { if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } if (descriptor == 'V') { if (!canBeVoid) { throw new IllegalArgumentException(); } } else { if ("ZCBSIFJD".indexOf(descriptor) == -1) { throw new IllegalArgumentException(); } } state = SIMPLE_TYPE; if (sv != null) { sv.visitBaseType(descriptor); } } public void visitTypeVariable(final String name) { if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } CheckMethodAdapter.checkIdentifier(name, "type variable"); state = SIMPLE_TYPE; if (sv != null) { sv.visitTypeVariable(name); } } public SignatureVisitor visitArrayType() { if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } state = SIMPLE_TYPE; SignatureVisitor v = sv == null ? null : sv.visitArrayType(); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } public void visitClassType(final String name) { if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } CheckMethodAdapter.checkInternalName(name, "class name"); state = CLASS_TYPE; if (sv != null) { sv.visitClassType(name); } } public void visitInnerClassType(final String name) { if (state != CLASS_TYPE) { throw new IllegalStateException(); } CheckMethodAdapter.checkIdentifier(name, "inner class name"); if (sv != null) { sv.visitInnerClassType(name); } } public void visitTypeArgument() { if (state != CLASS_TYPE) { throw new IllegalStateException(); } if (sv != null) { sv.visitTypeArgument(); } } public SignatureVisitor visitTypeArgument(final char wildcard) { if (state != CLASS_TYPE) { throw new IllegalStateException(); } if ("+-=".indexOf(wildcard) == -1) { throw new IllegalArgumentException(); } SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard); return new CheckSignatureAdapter(TYPE_SIGNATURE, v); } public void visitEnd() { if (state != CLASS_TYPE) { throw new IllegalStateException(); } state = END; if (sv != null) { sv.visitEnd(); } } } asm-3.3.2/src/org/objectweb/asm/util/TraceFieldVisitor.java0000644000175000017500000000536110635277351023557 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; /** * A {@link FieldVisitor} that prints a disassembled view of the fields it * visits. * * @author Eric Bruneton */ public class TraceFieldVisitor extends TraceAbstractVisitor implements FieldVisitor { /** * The {@link FieldVisitor} to which this visitor delegates calls. May be * null. */ protected FieldVisitor fv; public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { AnnotationVisitor av = super.visitAnnotation(desc, visible); if (fv != null) { ((TraceAnnotationVisitor) av).av = fv.visitAnnotation(desc, visible); } return av; } public void visitAttribute(final Attribute attr) { super.visitAttribute(attr); if (fv != null) { fv.visitAttribute(attr); } } public void visitEnd() { super.visitEnd(); if (fv != null) { fv.visitEnd(); } } } asm-3.3.2/src/org/objectweb/asm/util/CheckClassAdapter.java0000644000175000017500000005061711525262537023504 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.FileInputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Attribute; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.analysis.Analyzer; import org.objectweb.asm.tree.analysis.SimpleVerifier; import org.objectweb.asm.tree.analysis.Frame; /** * A {@link ClassAdapter} that checks that its methods are properly used. More * precisely this class adapter checks each method call individually, based * only on its arguments, but does not check the sequence * of method calls. For example, the invalid sequence * visitField(ACC_PUBLIC, "i", "I", null) visitField(ACC_PUBLIC, * "i", "D", null) * will not be detected by this class adapter. * *

CheckClassAdapter can be also used to verify bytecode * transformations in order to make sure transformed bytecode is sane. For * example: * *

 *   InputStream is = ...; // get bytes for the source class
 *   ClassReader cr = new ClassReader(is);
 *   ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
 *   ClassVisitor cv = new MyClassAdapter(new CheckClassAdapter(cw));
 *   cr.accept(cv, 0);
 *
 *   StringWriter sw = new StringWriter();
 *   PrintWriter pw = new PrintWriter(sw);
 *   CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw);
 *   assertTrue(sw.toString(), sw.toString().length()==0);
 * 
* * Above code runs transformed bytecode trough the * CheckClassAdapter. It won't be exactly the same verification * as JVM does, but it run data flow analysis for the code of each method and * checks that expectations are met for each method instruction. * *

If method bytecode has errors, assertion text will show the erroneous * instruction number and dump of the failed method with information about * locals and stack slot for each instruction. For example (format is - * insnNumber locals : stack): * *

 * org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
 *   at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
 *   at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
 * ...
 * remove()V
 * 00000 LinkedBlockingQueue$Itr . . . . . . . .  :
 *   ICONST_0
 * 00001 LinkedBlockingQueue$Itr . . . . . . . .  : I
 *   ISTORE 2
 * 00001 LinkedBlockingQueue$Itr . I . . . . . .  :
 * ...
 *
 * 00071 LinkedBlockingQueue$Itr . I . . . . . .  :
 *   ILOAD 1
 * 00072 ?
 *   INVOKESPECIAL java/lang/Integer. (I)V
 * ...
 * 
* * In the above output you can see that variable 1 loaded by * ILOAD 1 instruction at position 00071 is not * initialized. You can also see that at the beginning of the method (code * inserted by the transformation) variable 2 is initialized. * *

Note that when used like that, CheckClassAdapter.verify() * can trigger additional class loading, because it is using * SimpleVerifier. * * @author Eric Bruneton */ public class CheckClassAdapter extends ClassAdapter { /** * The class version number. */ private int version; /** * true if the visit method has been called. */ private boolean start; /** * true if the visitSource method has been called. */ private boolean source; /** * true if the visitOuterClass method has been called. */ private boolean outer; /** * true if the visitEnd method has been called. */ private boolean end; /** * The already visited labels. This map associate Integer values to Label * keys. */ private Map labels; /** * true if the method code must be checked with a BasicVerifier. */ private boolean checkDataFlow; /** * Checks a given class.

Usage: CheckClassAdapter <binary * class name or class file name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { if (args.length != 1) { System.err.println("Verifies the given class."); System.err.println("Usage: CheckClassAdapter " + ""); return; } ClassReader cr; if (args[0].endsWith(".class")) { cr = new ClassReader(new FileInputStream(args[0])); } else { cr = new ClassReader(args[0]); } verify(cr, false, new PrintWriter(System.err)); } /** * Checks a given class * * @param cr a ClassReader that contains bytecode for the * analysis. * @param loader a ClassLoader which will be used to load * referenced classes. This is useful if you are verifiying multiple * interdependent classes. * @param dump true if bytecode should be printed out not only when errors * are found. * @param pw write where results going to be printed */ public static void verify( final ClassReader cr, final ClassLoader loader, final boolean dump, final PrintWriter pw) { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); Type syperType = cn.superName == null ? null : Type.getObjectType(cn.superName); List methods = cn.methods; List interfaces = new ArrayList(); for (Iterator i = cn.interfaces.iterator(); i.hasNext();) { interfaces.add(Type.getObjectType(i.next().toString())); } for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); SimpleVerifier verifier = new SimpleVerifier(Type.getObjectType(cn.name), syperType, interfaces, (cn.access | Opcodes.ACC_INTERFACE) != 0); Analyzer a = new Analyzer(verifier); if (loader != null) { verifier.setClassLoader(loader); } try { a.analyze(cn.name, method); if (!dump) { continue; } } catch (Exception e) { e.printStackTrace(pw); } printAnalyzerResult(method, a, pw); } pw.flush(); } /** * Checks a given class * * @param cr a ClassReader that contains bytecode for the * analysis. * @param dump true if bytecode should be printed out not only when errors * are found. * @param pw write where results going to be printed */ public static void verify( final ClassReader cr, final boolean dump, final PrintWriter pw) { verify(cr, null, dump, pw); } static void printAnalyzerResult( MethodNode method, Analyzer a, final PrintWriter pw) { Frame[] frames = a.getFrames(); TraceMethodVisitor mv = new TraceMethodVisitor(); pw.println(method.name + method.desc); for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame f = frames[j]; if (f == null) { s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())) .append(' '); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())) .append(' '); } } while (s.length() < method.maxStack + method.maxLocals + 1) { s.append(' '); } pw.print(Integer.toString(j + 100000).substring(1)); pw.print(" " + s + " : " + mv.buf); // mv.text.get(j)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); pw.print(" " + mv.buf); } pw.println(); } private static String getShortName(final String name) { int n = name.lastIndexOf('/'); int k = name.length(); if (name.charAt(k - 1) == ';') { k--; } return n == -1 ? name : name.substring(n + 1, k); } /** * Constructs a new {@link CheckClassAdapter}. * * @param cv the class visitor to which this adapter must delegate calls. */ public CheckClassAdapter(final ClassVisitor cv) { this(cv, true); } /** * Constructs a new {@link CheckClassAdapter}. * * @param cv the class visitor to which this adapter must delegate calls. * @param checkDataFlow true to perform basic data flow checks, or * false to not perform any data flow check (see * {@link CheckMethodAdapter}). This option requires valid maxLocals * and maxStack values. */ public CheckClassAdapter(final ClassVisitor cv, boolean checkDataFlow) { super(cv); this.labels = new HashMap(); this.checkDataFlow = checkDataFlow; } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { if (start) { throw new IllegalStateException("visit must be called only once"); } start = true; checkState(); checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE if (name == null || !name.endsWith("package-info")) { CheckMethodAdapter.checkInternalName(name, "class name"); } if ("java/lang/Object".equals(name)) { if (superName != null) { throw new IllegalArgumentException("The super class name of the Object class must be 'null'"); } } else { CheckMethodAdapter.checkInternalName(superName, "super class name"); } if (signature != null) { CheckMethodAdapter.checkClassSignature(signature); } if ((access & Opcodes.ACC_INTERFACE) != 0) { if (!"java/lang/Object".equals(superName)) { throw new IllegalArgumentException("The super class name of interfaces must be 'java/lang/Object'"); } } if (interfaces != null) { for (int i = 0; i < interfaces.length; ++i) { CheckMethodAdapter.checkInternalName(interfaces[i], "interface name at index " + i); } } this.version = version; cv.visit(version, access, name, signature, superName, interfaces); } public void visitSource(final String file, final String debug) { checkState(); if (source) { throw new IllegalStateException("visitSource can be called only once."); } source = true; cv.visitSource(file, debug); } public void visitOuterClass( final String owner, final String name, final String desc) { checkState(); if (outer) { throw new IllegalStateException("visitOuterClass can be called only once."); } outer = true; if (owner == null) { throw new IllegalArgumentException("Illegal outer class owner"); } if (desc != null) { CheckMethodAdapter.checkMethodDesc(desc); } cv.visitOuterClass(owner, name, desc); } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { checkState(); CheckMethodAdapter.checkInternalName(name, "class name"); if (outerName != null) { CheckMethodAdapter.checkInternalName(outerName, "outer class name"); } if (innerName != null) { CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); } checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); cv.visitInnerClass(name, outerName, innerName, access); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { checkState(); checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); CheckMethodAdapter.checkDesc(desc, false); if (signature != null) { CheckMethodAdapter.checkFieldSignature(signature); } if (value != null) { CheckMethodAdapter.checkConstant(value); } FieldVisitor av = cv.visitField(access, name, desc, signature, value); return new CheckFieldAdapter(av); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { checkState(); checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE CheckMethodAdapter.checkMethodIdentifier(version, name, "method name"); CheckMethodAdapter.checkMethodDesc(desc); if (signature != null) { CheckMethodAdapter.checkMethodSignature(signature); } if (exceptions != null) { for (int i = 0; i < exceptions.length; ++i) { CheckMethodAdapter.checkInternalName(exceptions[i], "exception name at index " + i); } } CheckMethodAdapter cma; if (checkDataFlow) { cma = new CheckMethodAdapter(access, name, desc, cv.visitMethod(access, name, desc, signature, exceptions), labels); } else { cma = new CheckMethodAdapter(cv.visitMethod(access, name, desc, signature, exceptions), labels); } cma.version = version; return cma; } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { checkState(); CheckMethodAdapter.checkDesc(desc, false); return new CheckAnnotationAdapter(cv.visitAnnotation(desc, visible)); } public void visitAttribute(final Attribute attr) { checkState(); if (attr == null) { throw new IllegalArgumentException("Invalid attribute (must not be null)"); } cv.visitAttribute(attr); } public void visitEnd() { checkState(); end = true; cv.visitEnd(); } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Checks that the visit method has been called and that visitEnd has not * been called. */ private void checkState() { if (!start) { throw new IllegalStateException("Cannot visit member before visit has been called."); } if (end) { throw new IllegalStateException("Cannot visit member after visitEnd has been called."); } } /** * Checks that the given access flags do not contain invalid flags. This * method also checks that mutually incompatible flags are not set * simultaneously. * * @param access the access flags to be checked * @param possibleAccess the valid access flags. */ static void checkAccess(final int access, final int possibleAccess) { if ((access & ~possibleAccess) != 0) { throw new IllegalArgumentException("Invalid access flags: " + access); } int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1; int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1; int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1; if (pub + pri + pro > 1) { throw new IllegalArgumentException("public private and protected are mutually exclusive: " + access); } int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1; int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1; if (fin + abs > 1) { throw new IllegalArgumentException("final and abstract are mutually exclusive: " + access); } } } asm-3.3.2/src/org/objectweb/asm/util/ASMifierClassVisitor.java0000644000175000017500000004371611525262537024207 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.FileInputStream; import java.io.PrintWriter; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@link ClassVisitor} that prints the ASM code that generates the classes it * visits. This class visitor can be used to quickly write ASM code to generate * some given bytecode:

  • write the Java source code equivalent to the * bytecode you want to generate;
  • compile it with javac;
  • *
  • make a {@link ASMifierClassVisitor} visit this compiled class (see the * {@link #main main} method);
  • edit the generated source code, if * necessary.
The source code printed when visiting the * Hello class is the following:

* *
 * import org.objectweb.asm.*;
 *
 * public class HelloDump implements Opcodes {
 *
 *     public static byte[] dump() throws Exception {
 *
 *         ClassWriter cw = new ClassWriter(0);
 *         FieldVisitor fv;
 *         MethodVisitor mv;
 *         AnnotationVisitor av0;
 *
 *         cw.visit(49,
 *                 ACC_PUBLIC + ACC_SUPER,
 *                 "Hello",
 *                 null,
 *                 "java/lang/Object",
 *                 null);
 *
 *         cw.visitSource("Hello.java", null);
 *
 *         {
 *             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 *             mv.visitVarInsn(ALOAD, 0);
 *             mv.visitMethodInsn(INVOKESPECIAL,
 *                     "java/lang/Object",
 *                     "<init>",
 *                     "()V");
 *             mv.visitInsn(RETURN);
 *             mv.visitMaxs(1, 1);
 *             mv.visitEnd();
 *         }
 *         {
 *             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
 *                     "main",
 *                     "([Ljava/lang/String;)V",
 *                     null,
 *                     null);
 *             mv.visitFieldInsn(GETSTATIC,
 *                     "java/lang/System",
 *                     "out",
 *                     "Ljava/io/PrintStream;");
 *             mv.visitLdcInsn("hello");
 *             mv.visitMethodInsn(INVOKEVIRTUAL,
 *                     "java/io/PrintStream",
 *                     "println",
 *                     "(Ljava/lang/String;)V");
 *             mv.visitInsn(RETURN);
 *             mv.visitMaxs(2, 1);
 *             mv.visitEnd();
 *         }
 *         cw.visitEnd();
 *
 *         return cw.toByteArray();
 *     }
 * }
 *
 * 
* *
where Hello is defined by:

* *
 * public class Hello {
 *
 *     public static void main(String[] args) {
 *         System.out.println("hello");
 *     }
 * }
 * 
* *
* * @author Eric Bruneton * @author Eugene Kuleshov */ public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements ClassVisitor { /** * Pseudo access flag used to distinguish class access flags. */ private static final int ACCESS_CLASS = 262144; /** * Pseudo access flag used to distinguish field access flags. */ private static final int ACCESS_FIELD = 524288; /** * Pseudo access flag used to distinguish inner class flags. */ private static final int ACCESS_INNER = 1048576; /** * The print writer to be used to print the class. */ protected final PrintWriter pw; /** * Prints the ASM source code to generate the given class to the standard * output.

Usage: ASMifierClassVisitor [-debug] <binary * class name or class file name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { int i = 0; int flags = ClassReader.SKIP_DEBUG; boolean ok = true; if (args.length < 1 || args.length > 2) { ok = false; } if (ok && "-debug".equals(args[0])) { i = 1; flags = 0; if (args.length != 2) { ok = false; } } if (!ok) { System.err.println("Prints the ASM code to generate the given class."); System.err.println("Usage: ASMifierClassVisitor [-debug] " + ""); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), getDefaultAttributes(), flags); } /** * Constructs a new {@link ASMifierClassVisitor} object. * * @param pw the print writer to be used to print the class. */ public ASMifierClassVisitor(final PrintWriter pw) { super("cw"); this.pw = pw; } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { String simpleName; int n = name.lastIndexOf('/'); if (n == -1) { simpleName = name; } else { text.add("package asm." + name.substring(0, n).replace('/', '.') + ";\n"); simpleName = name.substring(n + 1); } text.add("import java.util.*;\n"); text.add("import org.objectweb.asm.*;\n"); text.add("import org.objectweb.asm.attrs.*;\n"); text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); text.add("public static byte[] dump () throws Exception {\n\n"); text.add("ClassWriter cw = new ClassWriter(0);\n"); text.add("FieldVisitor fv;\n"); text.add("MethodVisitor mv;\n"); text.add("AnnotationVisitor av0;\n\n"); buf.setLength(0); buf.append("cw.visit("); switch (version) { case Opcodes.V1_1: buf.append("V1_1"); break; case Opcodes.V1_2: buf.append("V1_2"); break; case Opcodes.V1_3: buf.append("V1_3"); break; case Opcodes.V1_4: buf.append("V1_4"); break; case Opcodes.V1_5: buf.append("V1_5"); break; case Opcodes.V1_6: buf.append("V1_6"); break; default: buf.append(version); break; } buf.append(", "); appendAccess(access | ACCESS_CLASS); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(signature); buf.append(", "); appendConstant(superName); buf.append(", "); if (interfaces != null && interfaces.length > 0) { buf.append("new String[] {"); for (int i = 0; i < interfaces.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(interfaces[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(");\n\n"); text.add(buf.toString()); } public void visitSource(final String file, final String debug) { buf.setLength(0); buf.append("cw.visitSource("); appendConstant(file); buf.append(", "); appendConstant(debug); buf.append(");\n\n"); text.add(buf.toString()); } public void visitOuterClass( final String owner, final String name, final String desc) { buf.setLength(0); buf.append("cw.visitOuterClass("); appendConstant(owner); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(");\n\n"); text.add(buf.toString()); } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { buf.setLength(0); buf.append("cw.visitInnerClass("); appendConstant(name); buf.append(", "); appendConstant(outerName); buf.append(", "); appendConstant(innerName); buf.append(", "); appendAccess(access | ACCESS_INNER); buf.append(");\n\n"); text.add(buf.toString()); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { buf.setLength(0); buf.append("{\n"); buf.append("fv = cw.visitField("); appendAccess(access | ACCESS_FIELD); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(", "); appendConstant(signature); buf.append(", "); appendConstant(value); buf.append(");\n"); text.add(buf.toString()); ASMifierFieldVisitor aav = new ASMifierFieldVisitor(); text.add(aav.getText()); text.add("}\n"); return aav; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append("{\n"); buf.append("mv = cw.visitMethod("); appendAccess(access); buf.append(", "); appendConstant(name); buf.append(", "); appendConstant(desc); buf.append(", "); appendConstant(signature); buf.append(", "); if (exceptions != null && exceptions.length > 0) { buf.append("new String[] {"); for (int i = 0; i < exceptions.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(exceptions[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(");\n"); text.add(buf.toString()); ASMifierMethodVisitor acv = createASMifierMethodVisitor(); text.add(acv.getText()); text.add("}\n"); return acv; } protected ASMifierMethodVisitor createASMifierMethodVisitor() { return new ASMifierMethodVisitor(); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { buf.setLength(0); buf.append("{\n"); buf.append("av0 = cw.visitAnnotation("); appendConstant(desc); buf.append(", "); buf.append(visible); buf.append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public void visitEnd() { text.add("cw.visitEnd();\n\n"); text.add("return cw.toByteArray();\n"); text.add("}\n"); text.add("}\n"); printList(pw, text); pw.flush(); } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Appends a string representation of the given access modifiers to {@link * #buf buf}. * * @param access some access modifiers. */ void appendAccess(final int access) { boolean first = true; if ((access & Opcodes.ACC_PUBLIC) != 0) { buf.append("ACC_PUBLIC"); first = false; } if ((access & Opcodes.ACC_PRIVATE) != 0) { buf.append("ACC_PRIVATE"); first = false; } if ((access & Opcodes.ACC_PROTECTED) != 0) { buf.append("ACC_PROTECTED"); first = false; } if ((access & Opcodes.ACC_FINAL) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_FINAL"); first = false; } if ((access & Opcodes.ACC_STATIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STATIC"); first = false; } if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { if (!first) { buf.append(" + "); } if ((access & ACCESS_CLASS) == 0) { buf.append("ACC_SYNCHRONIZED"); } else { buf.append("ACC_SUPER"); } first = false; } if ((access & Opcodes.ACC_VOLATILE) != 0 && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VOLATILE"); first = false; } if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_BRIDGE"); first = false; } if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VARARGS"); first = false; } if ((access & Opcodes.ACC_TRANSIENT) != 0 && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_TRANSIENT"); first = false; } if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_NATIVE"); first = false; } if ((access & Opcodes.ACC_ENUM) != 0 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { if (!first) { buf.append(" + "); } buf.append("ACC_ENUM"); first = false; } if ((access & Opcodes.ACC_ANNOTATION) != 0 && (access & ACCESS_CLASS) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ANNOTATION"); first = false; } if ((access & Opcodes.ACC_ABSTRACT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ABSTRACT"); first = false; } if ((access & Opcodes.ACC_INTERFACE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_INTERFACE"); first = false; } if ((access & Opcodes.ACC_STRICT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STRICT"); first = false; } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_SYNTHETIC"); first = false; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_DEPRECATED"); first = false; } if (first) { buf.append('0'); } } } asm-3.3.2/src/org/objectweb/asm/util/TraceAbstractVisitor.java0000644000175000017500000001410410701747173024270 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; /** * An abstract trace visitor. * * @author Eric Bruneton */ public abstract class TraceAbstractVisitor extends AbstractVisitor { /** * Constant used in {@link #appendDescriptor appendDescriptor} for internal * type names in bytecode notation. */ public static final int INTERNAL_NAME = 0; /** * Constant used in {@link #appendDescriptor appendDescriptor} for field * descriptors, formatted in bytecode notation */ public static final int FIELD_DESCRIPTOR = 1; /** * Constant used in {@link #appendDescriptor appendDescriptor} for field * signatures, formatted in bytecode notation */ public static final int FIELD_SIGNATURE = 2; /** * Constant used in {@link #appendDescriptor appendDescriptor} for method * descriptors, formatted in bytecode notation */ public static final int METHOD_DESCRIPTOR = 3; /** * Constant used in {@link #appendDescriptor appendDescriptor} for method * signatures, formatted in bytecode notation */ public static final int METHOD_SIGNATURE = 4; /** * Constant used in {@link #appendDescriptor appendDescriptor} for class * signatures, formatted in bytecode notation */ public static final int CLASS_SIGNATURE = 5; /** * Constant used in {@link #appendDescriptor appendDescriptor} for field or * method return value signatures, formatted in default Java notation * (non-bytecode) */ public static final int TYPE_DECLARATION = 6; /** * Constant used in {@link #appendDescriptor appendDescriptor} for class * signatures, formatted in default Java notation (non-bytecode) */ public static final int CLASS_DECLARATION = 7; /** * Constant used in {@link #appendDescriptor appendDescriptor} for method * parameter signatures, formatted in default Java notation (non-bytecode) */ public static final int PARAMETERS_DECLARATION = 8; /** * Tab for class members. */ protected String tab = " "; /** * Prints a disassembled view of the given annotation. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values. */ public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { buf.setLength(0); buf.append(tab).append('@'); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append('('); text.add(buf.toString()); TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); text.add(tav.getText()); text.add(visible ? ")\n" : ") // invisible\n"); return tav; } /** * Prints a disassembled view of the given attribute. * * @param attr an attribute. */ public void visitAttribute(final Attribute attr) { buf.setLength(0); buf.append(tab).append("ATTRIBUTE "); appendDescriptor(-1, attr.type); if (attr instanceof Traceable) { ((Traceable) attr).trace(buf, null); } else { buf.append(" : unknown\n"); } text.add(buf.toString()); } /** * Does nothing. */ public void visitEnd() { // does nothing } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ protected TraceAnnotationVisitor createTraceAnnotationVisitor() { return new TraceAnnotationVisitor(); } /** * Appends an internal name, a type descriptor or a type signature to * {@link #buf buf}. * * @param type indicates if desc is an internal name, a field descriptor, a * method descriptor, a class signature, ... * @param desc an internal name, type descriptor, or type signature. May be * null. */ protected void appendDescriptor(final int type, final String desc) { if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE || type == METHOD_SIGNATURE) { if (desc != null) { buf.append("// signature ").append(desc).append('\n'); } } else { buf.append(desc); } } } asm-3.3.2/src/org/objectweb/asm/util/CheckFieldAdapter.java0000644000175000017500000000547510701747173023463 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; /** * A {@link FieldVisitor} that checks that its methods are properly used. */ public class CheckFieldAdapter implements FieldVisitor { private final FieldVisitor fv; private boolean end; public CheckFieldAdapter(final FieldVisitor fv) { this.fv = fv; } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { checkEnd(); CheckMethodAdapter.checkDesc(desc, false); return new CheckAnnotationAdapter(fv.visitAnnotation(desc, visible)); } public void visitAttribute(final Attribute attr) { checkEnd(); if (attr == null) { throw new IllegalArgumentException("Invalid attribute (must not be null)"); } fv.visitAttribute(attr); } public void visitEnd() { checkEnd(); end = true; fv.visitEnd(); } private void checkEnd() { if (end) { throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); } } } asm-3.3.2/src/org/objectweb/asm/util/ASMifierAnnotationVisitor.java0000644000175000017500000001124110635277351025241 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; /** * An {@link AnnotationVisitor} that prints the ASM code that generates the * annotations it visits. * * @author Eric Bruneton */ public class ASMifierAnnotationVisitor extends AbstractVisitor implements AnnotationVisitor { /** * Identifier of the annotation visitor variable in the produced code. */ protected final int id; /** * Constructs a new {@link ASMifierAnnotationVisitor}. * * @param id identifier of the annotation visitor variable in the produced * code. */ public ASMifierAnnotationVisitor(final int id) { this.id = id; } // ------------------------------------------------------------------------ // Implementation of the AnnotationVisitor interface // ------------------------------------------------------------------------ public void visit(final String name, final Object value) { buf.setLength(0); buf.append("av").append(id).append(".visit("); ASMifierAbstractVisitor.appendConstant(buf, name); buf.append(", "); ASMifierAbstractVisitor.appendConstant(buf, value); buf.append(");\n"); text.add(buf.toString()); } public void visitEnum( final String name, final String desc, final String value) { buf.setLength(0); buf.append("av").append(id).append(".visitEnum("); ASMifierAbstractVisitor.appendConstant(buf, name); buf.append(", "); ASMifierAbstractVisitor.appendConstant(buf, desc); buf.append(", "); ASMifierAbstractVisitor.appendConstant(buf, value); buf.append(");\n"); text.add(buf.toString()); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { buf.setLength(0); buf.append("{\n"); buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); buf.append(id).append(".visitAnnotation("); ASMifierAbstractVisitor.appendConstant(buf, name); buf.append(", "); ASMifierAbstractVisitor.appendConstant(buf, desc); buf.append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(id + 1); text.add(av.getText()); text.add("}\n"); return av; } public AnnotationVisitor visitArray(final String name) { buf.setLength(0); buf.append("{\n"); buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); buf.append(id).append(".visitArray("); ASMifierAbstractVisitor.appendConstant(buf, name); buf.append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(id + 1); text.add(av.getText()); text.add("}\n"); return av; } public void visitEnd() { buf.setLength(0); buf.append("av").append(id).append(".visitEnd();\n"); text.add(buf.toString()); } } asm-3.3.2/src/org/objectweb/asm/util/TraceMethodVisitor.java0000644000175000017500000004140310701747173023747 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import java.util.HashMap; import java.util.Map; /** * A {@link MethodVisitor} that prints a disassembled view of the methods it * visits. * * @author Eric Bruneton */ public class TraceMethodVisitor extends TraceAbstractVisitor implements MethodVisitor { /** * The {@link MethodVisitor} to which this visitor delegates calls. May be * null. */ protected MethodVisitor mv; /** * Tab for bytecode instructions. */ protected String tab2 = " "; /** * Tab for table and lookup switch instructions. */ protected String tab3 = " "; /** * Tab for labels. */ protected String ltab = " "; /** * The label names. This map associate String values to Label keys. */ protected final Map labelNames; /** * Constructs a new {@link TraceMethodVisitor}. */ public TraceMethodVisitor() { this(null); } /** * Constructs a new {@link TraceMethodVisitor}. * * @param mv the {@link MethodVisitor} to which this visitor delegates * calls. May be null. */ public TraceMethodVisitor(final MethodVisitor mv) { this.labelNames = new HashMap(); this.mv = mv; } // ------------------------------------------------------------------------ // Implementation of the MethodVisitor interface // ------------------------------------------------------------------------ public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { AnnotationVisitor av = super.visitAnnotation(desc, visible); if (mv != null) { ((TraceAnnotationVisitor) av).av = mv.visitAnnotation(desc, visible); } return av; } public void visitAttribute(final Attribute attr) { buf.setLength(0); buf.append(tab).append("ATTRIBUTE "); appendDescriptor(-1, attr.type); if (attr instanceof Traceable) { ((Traceable) attr).trace(buf, labelNames); } else { buf.append(" : unknown\n"); } text.add(buf.toString()); if (mv != null) { mv.visitAttribute(attr); } } public AnnotationVisitor visitAnnotationDefault() { text.add(tab2 + "default="); TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); text.add(tav.getText()); text.add("\n"); if (mv != null) { tav.av = mv.visitAnnotationDefault(); } return tav; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { buf.setLength(0); buf.append(tab2).append('@'); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append('('); text.add(buf.toString()); TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); text.add(tav.getText()); text.add(visible ? ") // parameter " : ") // invisible, parameter "); text.add(new Integer(parameter)); text.add("\n"); if (mv != null) { tav.av = mv.visitParameterAnnotation(parameter, desc, visible); } return tav; } public void visitCode() { if (mv != null) { mv.visitCode(); } } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { buf.setLength(0); buf.append(ltab); buf.append("FRAME "); switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: buf.append("FULL ["); appendFrameTypes(nLocal, local); buf.append("] ["); appendFrameTypes(nStack, stack); buf.append(']'); break; case Opcodes.F_APPEND: buf.append("APPEND ["); appendFrameTypes(nLocal, local); buf.append(']'); break; case Opcodes.F_CHOP: buf.append("CHOP ").append(nLocal); break; case Opcodes.F_SAME: buf.append("SAME"); break; case Opcodes.F_SAME1: buf.append("SAME1 "); appendFrameTypes(1, stack); break; } buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitFrame(type, nLocal, local, nStack, stack); } } public void visitInsn(final int opcode) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitInsn(opcode); } } public void visitIntInsn(final int opcode, final int operand) { buf.setLength(0); buf.append(tab2) .append(OPCODES[opcode]) .append(' ') .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand)) .append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitIntInsn(opcode, operand); } } public void visitVarInsn(final int opcode, final int var) { buf.setLength(0); buf.append(tab2) .append(OPCODES[opcode]) .append(' ') .append(var) .append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitVarInsn(opcode, var); } } public void visitTypeInsn(final int opcode, final String type) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, type); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitTypeInsn(opcode, type); } } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, owner); buf.append('.').append(name).append(" : "); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitFieldInsn(opcode, owner, name, desc); } } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, owner); buf.append('.').append(name).append(' '); appendDescriptor(METHOD_DESCRIPTOR, desc); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } } public void visitJumpInsn(final int opcode, final Label label) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendLabel(label); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitJumpInsn(opcode, label); } } public void visitLabel(final Label label) { buf.setLength(0); buf.append(ltab); appendLabel(label); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitLabel(label); } } public void visitLdcInsn(final Object cst) { buf.setLength(0); buf.append(tab2).append("LDC "); if (cst instanceof String) { AbstractVisitor.appendString(buf, (String) cst); } else if (cst instanceof Type) { buf.append(((Type) cst).getDescriptor()).append(".class"); } else { buf.append(cst); } buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitLdcInsn(cst); } } public void visitIincInsn(final int var, final int increment) { buf.setLength(0); buf.append(tab2) .append("IINC ") .append(var) .append(' ') .append(increment) .append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitIincInsn(var, increment); } } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { buf.setLength(0); buf.append(tab2).append("TABLESWITCH\n"); for (int i = 0; i < labels.length; ++i) { buf.append(tab3).append(min + i).append(": "); appendLabel(labels[i]); buf.append('\n'); } buf.append(tab3).append("default: "); appendLabel(dflt); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitTableSwitchInsn(min, max, dflt, labels); } } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { buf.setLength(0); buf.append(tab2).append("LOOKUPSWITCH\n"); for (int i = 0; i < labels.length; ++i) { buf.append(tab3).append(keys[i]).append(": "); appendLabel(labels[i]); buf.append('\n'); } buf.append(tab3).append("default: "); appendLabel(dflt); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitLookupSwitchInsn(dflt, keys, labels); } } public void visitMultiANewArrayInsn(final String desc, final int dims) { buf.setLength(0); buf.append(tab2).append("MULTIANEWARRAY "); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append(' ').append(dims).append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitMultiANewArrayInsn(desc, dims); } } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { buf.setLength(0); buf.append(tab2).append("TRYCATCHBLOCK "); appendLabel(start); buf.append(' '); appendLabel(end); buf.append(' '); appendLabel(handler); buf.append(' '); appendDescriptor(INTERNAL_NAME, type); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitTryCatchBlock(start, end, handler, type); } } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { buf.setLength(0); buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append(' '); appendLabel(start); buf.append(' '); appendLabel(end); buf.append(' ').append(index).append('\n'); if (signature != null) { buf.append(tab2); appendDescriptor(FIELD_SIGNATURE, signature); TraceSignatureVisitor sv = new TraceSignatureVisitor(0); SignatureReader r = new SignatureReader(signature); r.acceptType(sv); buf.append(tab2) .append("// declaration: ") .append(sv.getDeclaration()) .append('\n'); } text.add(buf.toString()); if (mv != null) { mv.visitLocalVariable(name, desc, signature, start, end, index); } } public void visitLineNumber(final int line, final Label start) { buf.setLength(0); buf.append(tab2).append("LINENUMBER ").append(line).append(' '); appendLabel(start); buf.append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitLineNumber(line, start); } } public void visitMaxs(final int maxStack, final int maxLocals) { buf.setLength(0); buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); text.add(buf.toString()); buf.setLength(0); buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); text.add(buf.toString()); if (mv != null) { mv.visitMaxs(maxStack, maxLocals); } } public void visitEnd() { super.visitEnd(); if (mv != null) { mv.visitEnd(); } } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ private void appendFrameTypes(final int n, final Object[] o) { for (int i = 0; i < n; ++i) { if (i > 0) { buf.append(' '); } if (o[i] instanceof String) { String desc = (String) o[i]; if (desc.startsWith("[")) { appendDescriptor(FIELD_DESCRIPTOR, desc); } else { appendDescriptor(INTERNAL_NAME, desc); } } else if (o[i] instanceof Integer) { switch (((Integer) o[i]).intValue()) { case 0: appendDescriptor(FIELD_DESCRIPTOR, "T"); break; case 1: appendDescriptor(FIELD_DESCRIPTOR, "I"); break; case 2: appendDescriptor(FIELD_DESCRIPTOR, "F"); break; case 3: appendDescriptor(FIELD_DESCRIPTOR, "D"); break; case 4: appendDescriptor(FIELD_DESCRIPTOR, "J"); break; case 5: appendDescriptor(FIELD_DESCRIPTOR, "N"); break; case 6: appendDescriptor(FIELD_DESCRIPTOR, "U"); break; } } else { appendLabel((Label) o[i]); } } } /** * Appends the name of the given label to {@link #buf buf}. Creates a new * label name if the given label does not yet have one. * * @param l a label. */ protected void appendLabel(final Label l) { String name = (String) labelNames.get(l); if (name == null) { name = "L" + labelNames.size(); labelNames.put(l, name); } buf.append(name); } } asm-3.3.2/src/org/objectweb/asm/util/TraceAnnotationVisitor.java0000644000175000017500000002115010635277351024640 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Type; /** * An {@link AnnotationVisitor} that prints a disassembled view of the * annotations it visits. * * @author Eric Bruneton */ public class TraceAnnotationVisitor extends TraceAbstractVisitor implements AnnotationVisitor { /** * The {@link AnnotationVisitor} to which this visitor delegates calls. May * be null. */ protected AnnotationVisitor av; private int valueNumber = 0; /** * Constructs a new {@link TraceAnnotationVisitor}. */ public TraceAnnotationVisitor() { // ignore } // ------------------------------------------------------------------------ // Implementation of the AnnotationVisitor interface // ------------------------------------------------------------------------ public void visit(final String name, final Object value) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { buf.append(name).append('='); } if (value instanceof String) { visitString((String) value); } else if (value instanceof Type) { visitType((Type) value); } else if (value instanceof Byte) { visitByte(((Byte) value).byteValue()); } else if (value instanceof Boolean) { visitBoolean(((Boolean) value).booleanValue()); } else if (value instanceof Short) { visitShort(((Short) value).shortValue()); } else if (value instanceof Character) { visitChar(((Character) value).charValue()); } else if (value instanceof Integer) { visitInt(((Integer) value).intValue()); } else if (value instanceof Float) { visitFloat(((Float) value).floatValue()); } else if (value instanceof Long) { visitLong(((Long) value).longValue()); } else if (value instanceof Double) { visitDouble(((Double) value).doubleValue()); } else if (value.getClass().isArray()) { buf.append('{'); if (value instanceof byte[]) { byte[] v = (byte[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitByte(v[i]); } } else if (value instanceof boolean[]) { boolean[] v = (boolean[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitBoolean(v[i]); } } else if (value instanceof short[]) { short[] v = (short[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitShort(v[i]); } } else if (value instanceof char[]) { char[] v = (char[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitChar(v[i]); } } else if (value instanceof int[]) { int[] v = (int[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitInt(v[i]); } } else if (value instanceof long[]) { long[] v = (long[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitLong(v[i]); } } else if (value instanceof float[]) { float[] v = (float[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitFloat(v[i]); } } else if (value instanceof double[]) { double[] v = (double[]) value; for (int i = 0; i < v.length; i++) { appendComa(i); visitDouble(v[i]); } } buf.append('}'); } text.add(buf.toString()); if (av != null) { av.visit(name, value); } } private void visitInt(final int value) { buf.append(value); } private void visitLong(final long value) { buf.append(value).append('L'); } private void visitFloat(final float value) { buf.append(value).append('F'); } private void visitDouble(final double value) { buf.append(value).append('D'); } private void visitChar(final char value) { buf.append("(char)").append((int) value); } private void visitShort(final short value) { buf.append("(short)").append(value); } private void visitByte(final byte value) { buf.append("(byte)").append(value); } private void visitBoolean(final boolean value) { buf.append(value); } private void visitString(final String value) { appendString(buf, value); } private void visitType(final Type value) { buf.append(value.getClassName()).append(".class"); } public void visitEnum( final String name, final String desc, final String value) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { buf.append(name).append('='); } appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append('.').append(value); text.add(buf.toString()); if (av != null) { av.visitEnum(name, desc, value); } } public AnnotationVisitor visitAnnotation( final String name, final String desc) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { buf.append(name).append('='); } buf.append('@'); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append('('); text.add(buf.toString()); TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); text.add(tav.getText()); text.add(")"); if (av != null) { tav.av = av.visitAnnotation(name, desc); } return tav; } public AnnotationVisitor visitArray(final String name) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { buf.append(name).append('='); } buf.append('{'); text.add(buf.toString()); TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); text.add(tav.getText()); text.add("}"); if (av != null) { tav.av = av.visitArray(name); } return tav; } public void visitEnd() { if (av != null) { av.visitEnd(); } } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ private void appendComa(final int i) { if (i != 0) { buf.append(", "); } } } asm-3.3.2/src/org/objectweb/asm/util/ASMifierFieldVisitor.java0000644000175000017500000000406110635277351024154 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import org.objectweb.asm.FieldVisitor; /** * A {@link FieldVisitor} that prints the ASM code that generates the fields it * visits. * * @author Eric Bruneton */ public class ASMifierFieldVisitor extends ASMifierAbstractVisitor implements FieldVisitor { /** * Constructs a new {@link ASMifierFieldVisitor}. */ public ASMifierFieldVisitor() { super("fv"); } } asm-3.3.2/src/org/objectweb/asm/util/Traceable.java0000644000175000017500000000437210635277351022060 0ustar twernertwerner/** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.util.Map; /** * An attribute that can print eadable representation of the attribute. * * Implementation should construct readable output from an attribute data * structures for current attribute state. Such representation could be used in * unit test assertions. * * @author Eugene Kuleshov */ public interface Traceable { /** * Build a human readable representation of the attribute. * * @param buf A buffer used for printing Java code. * @param labelNames map of label instances to their names. */ void trace(StringBuffer buf, Map labelNames); } asm-3.3.2/src/org/objectweb/asm/util/TraceClassVisitor.java0000644000175000017500000004044711525262537023604 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.FileInputStream; import java.io.PrintWriter; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.signature.SignatureReader; /** * A {@link ClassVisitor} that prints a disassembled view of the classes it * visits. This class visitor can be used alone (see the {@link #main main} * method) to disassemble a class. It can also be used in the middle of class * visitor chain to trace the class that is visited at a given point in this * chain. This may be uselful for debugging purposes.

The trace printed when * visiting the Hello class is the following:

* *
 * // class version 49.0 (49)
 * // access flags 0x21
 * public class Hello {
 *
 *  // compiled from: Hello.java
 *
 *   // access flags 0x1
 *   public <init> ()V
 *     ALOAD 0
 *     INVOKESPECIAL java/lang/Object <init> ()V
 *     RETURN
 *     MAXSTACK = 1
 *     MAXLOCALS = 1
 *
 *   // access flags 0x9
 *   public static main ([Ljava/lang/String;)V
 *     GETSTATIC java/lang/System out Ljava/io/PrintStream;
 *     LDC "hello"
 *     INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V
 *     RETURN
 *     MAXSTACK = 2
 *     MAXLOCALS = 1
 * }
 * 
* *
where Hello is defined by:

* *
 * public class Hello {
 *
 *     public static void main(String[] args) {
 *         System.out.println("hello");
 *     }
 * }
 * 
* *
* * @author Eric Bruneton * @author Eugene Kuleshov */ public class TraceClassVisitor extends TraceAbstractVisitor implements ClassVisitor { /** * The {@link ClassVisitor} to which this visitor delegates calls. May be * null. */ protected final ClassVisitor cv; /** * The print writer to be used to print the class. */ protected final PrintWriter pw; /** * Prints a disassembled view of the given class to the standard output.

* Usage: TraceClassVisitor [-debug] <binary class name or class * file name > * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { int i = 0; int flags = ClassReader.SKIP_DEBUG; boolean ok = true; if (args.length < 1 || args.length > 2) { ok = false; } if (ok && "-debug".equals(args[0])) { i = 1; flags = 0; if (args.length != 2) { ok = false; } } if (!ok) { System.err.println("Prints a disassembled view of the given class."); System.err.println("Usage: TraceClassVisitor [-debug] " + ""); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), getDefaultAttributes(), flags); } /** * Constructs a new {@link TraceClassVisitor}. * * @param pw the print writer to be used to print the class. */ public TraceClassVisitor(final PrintWriter pw) { this(null, pw); } /** * Constructs a new {@link TraceClassVisitor}. * * @param cv the {@link ClassVisitor} to which this visitor delegates calls. * May be null. * @param pw the print writer to be used to print the class. */ public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) { this.cv = cv; this.pw = pw; } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { int major = version & 0xFFFF; int minor = version >>> 16; buf.setLength(0); buf.append("// class version ") .append(major) .append('.') .append(minor) .append(" (") .append(version) .append(")\n"); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append("// DEPRECATED\n"); } buf.append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); appendDescriptor(CLASS_SIGNATURE, signature); if (signature != null) { TraceSignatureVisitor sv = new TraceSignatureVisitor(access); SignatureReader r = new SignatureReader(signature); r.accept(sv); buf.append("// declaration: ") .append(name) .append(sv.getDeclaration()) .append('\n'); } appendAccess(access & ~Opcodes.ACC_SUPER); if ((access & Opcodes.ACC_ANNOTATION) != 0) { buf.append("@interface "); } else if ((access & Opcodes.ACC_INTERFACE) != 0) { buf.append("interface "); } else if ((access & Opcodes.ACC_ENUM) == 0) { buf.append("class "); } appendDescriptor(INTERNAL_NAME, name); if (superName != null && !"java/lang/Object".equals(superName)) { buf.append(" extends "); appendDescriptor(INTERNAL_NAME, superName); buf.append(' '); } if (interfaces != null && interfaces.length > 0) { buf.append(" implements "); for (int i = 0; i < interfaces.length; ++i) { appendDescriptor(INTERNAL_NAME, interfaces[i]); buf.append(' '); } } buf.append(" {\n\n"); text.add(buf.toString()); if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } } public void visitSource(final String file, final String debug) { buf.setLength(0); if (file != null) { buf.append(tab) .append("// compiled from: ") .append(file) .append('\n'); } if (debug != null) { buf.append(tab) .append("// debug info: ") .append(debug) .append('\n'); } if (buf.length() > 0) { text.add(buf.toString()); } if (cv != null) { cv.visitSource(file, debug); } } public void visitOuterClass( final String owner, final String name, final String desc) { buf.setLength(0); buf.append(tab).append("OUTERCLASS "); appendDescriptor(INTERNAL_NAME, owner); buf.append(' '); if (name != null) { buf.append(name).append(' '); } appendDescriptor(METHOD_DESCRIPTOR, desc); buf.append('\n'); text.add(buf.toString()); if (cv != null) { cv.visitOuterClass(owner, name, desc); } } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { text.add("\n"); AnnotationVisitor tav = super.visitAnnotation(desc, visible); if (cv != null) { ((TraceAnnotationVisitor) tav).av = cv.visitAnnotation(desc, visible); } return tav; } public void visitAttribute(final Attribute attr) { text.add("\n"); super.visitAttribute(attr); if (cv != null) { cv.visitAttribute(attr); } } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { buf.setLength(0); buf.append(tab).append("// access flags 0x"); buf.append(Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()).append('\n'); buf.append(tab); appendAccess(access); buf.append("INNERCLASS "); appendDescriptor(INTERNAL_NAME, name); buf.append(' '); appendDescriptor(INTERNAL_NAME, outerName); buf.append(' '); appendDescriptor(INTERNAL_NAME, innerName); buf.append('\n'); text.add(buf.toString()); if (cv != null) { cv.visitInnerClass(name, outerName, innerName, access); } } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { buf.setLength(0); buf.append('\n'); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append(tab).append("// DEPRECATED\n"); } buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); if (signature != null) { buf.append(tab); appendDescriptor(FIELD_SIGNATURE, signature); TraceSignatureVisitor sv = new TraceSignatureVisitor(0); SignatureReader r = new SignatureReader(signature); r.acceptType(sv); buf.append(tab) .append("// declaration: ") .append(sv.getDeclaration()) .append('\n'); } buf.append(tab); appendAccess(access); appendDescriptor(FIELD_DESCRIPTOR, desc); buf.append(' ').append(name); if (value != null) { buf.append(" = "); if (value instanceof String) { buf.append('\"').append(value).append('\"'); } else { buf.append(value); } } buf.append('\n'); text.add(buf.toString()); TraceFieldVisitor tav = createTraceFieldVisitor(); text.add(tav.getText()); if (cv != null) { tav.fv = cv.visitField(access, name, desc, signature, value); } return tav; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append('\n'); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append(tab).append("// DEPRECATED\n"); } buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); if (signature != null) { buf.append(tab); appendDescriptor(METHOD_SIGNATURE, signature); TraceSignatureVisitor v = new TraceSignatureVisitor(0); SignatureReader r = new SignatureReader(signature); r.accept(v); String genericDecl = v.getDeclaration(); String genericReturn = v.getReturnType(); String genericExceptions = v.getExceptions(); buf.append(tab) .append("// declaration: ") .append(genericReturn) .append(' ') .append(name) .append(genericDecl); if (genericExceptions != null) { buf.append(" throws ").append(genericExceptions); } buf.append('\n'); } buf.append(tab); appendAccess(access); if ((access & Opcodes.ACC_NATIVE) != 0) { buf.append("native "); } if ((access & Opcodes.ACC_VARARGS) != 0) { buf.append("varargs "); } if ((access & Opcodes.ACC_BRIDGE) != 0) { buf.append("bridge "); } buf.append(name); appendDescriptor(METHOD_DESCRIPTOR, desc); if (exceptions != null && exceptions.length > 0) { buf.append(" throws "); for (int i = 0; i < exceptions.length; ++i) { appendDescriptor(INTERNAL_NAME, exceptions[i]); buf.append(' '); } } buf.append('\n'); text.add(buf.toString()); TraceMethodVisitor tcv = createTraceMethodVisitor(); text.add(tcv.getText()); if (cv != null) { tcv.mv = cv.visitMethod(access, name, desc, signature, exceptions); } return tcv; } public void visitEnd() { text.add("}\n"); print(pw); pw.flush(); if (cv != null) { cv.visitEnd(); } } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ protected TraceFieldVisitor createTraceFieldVisitor() { return new TraceFieldVisitor(); } protected TraceMethodVisitor createTraceMethodVisitor() { return new TraceMethodVisitor(); } /** * Appends a string representation of the given access modifiers to {@link * #buf buf}. * * @param access some access modifiers. */ private void appendAccess(final int access) { if ((access & Opcodes.ACC_PUBLIC) != 0) { buf.append("public "); } if ((access & Opcodes.ACC_PRIVATE) != 0) { buf.append("private "); } if ((access & Opcodes.ACC_PROTECTED) != 0) { buf.append("protected "); } if ((access & Opcodes.ACC_FINAL) != 0) { buf.append("final "); } if ((access & Opcodes.ACC_STATIC) != 0) { buf.append("static "); } if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { buf.append("synchronized "); } if ((access & Opcodes.ACC_VOLATILE) != 0) { buf.append("volatile "); } if ((access & Opcodes.ACC_TRANSIENT) != 0) { buf.append("transient "); } if ((access & Opcodes.ACC_ABSTRACT) != 0) { buf.append("abstract "); } if ((access & Opcodes.ACC_STRICT) != 0) { buf.append("strictfp "); } if ((access & Opcodes.ACC_ENUM) != 0) { buf.append("enum "); } } } asm-3.3.2/src/org/objectweb/asm/commons/0000755000175000017500000000000011633370220020007 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/commons/SerialVersionUIDAdder.java0000644000175000017500000004467211302174331024754 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.ByteArrayOutputStream; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@link ClassAdapter} that adds a serial version unique identifier to a * class if missing. Here is typical usage of this class: * *

 *   ClassWriter cw = new ClassWriter(...);
 *   ClassVisitor sv = new SerialVersionUIDAdder(cw);
 *   ClassVisitor ca = new MyClassAdapter(sv);
 *   new ClassReader(orginalClass).accept(ca, false);
 * 
* * The SVUID algorithm can be found http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html: * *
 * The serialVersionUID is computed using the signature of a stream of bytes
 * that reflect the class definition. The National Institute of Standards and
 * Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
 * signature for the stream. The first two 32-bit quantities are used to form a
 * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
 * types to a sequence of bytes. The values input to the stream are defined by
 * the Java Virtual Machine (VM) specification for classes.
 *
 * The sequence of items in the stream is as follows:
 *
 * 1. The class name written using UTF encoding.
 * 2. The class modifiers written as a 32-bit integer.
 * 3. The name of each interface sorted by name written using UTF encoding.
 * 4. For each field of the class sorted by field name (except private static
 * and private transient fields):
 * 1. The name of the field in UTF encoding.
 * 2. The modifiers of the field written as a 32-bit integer.
 * 3. The descriptor of the field in UTF encoding
 * 5. If a class initializer exists, write out the following:
 * 1. The name of the method, <clinit>, in UTF encoding.
 * 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
 * written as a 32-bit integer.
 * 3. The descriptor of the method, ()V, in UTF encoding.
 * 6. For each non-private constructor sorted by method name and signature:
 * 1. The name of the method, <init>, in UTF encoding.
 * 2. The modifiers of the method written as a 32-bit integer.
 * 3. The descriptor of the method in UTF encoding.
 * 7. For each non-private method sorted by method name and signature:
 * 1. The name of the method in UTF encoding.
 * 2. The modifiers of the method written as a 32-bit integer.
 * 3. The descriptor of the method in UTF encoding.
 * 8. The SHA-1 algorithm is executed on the stream of bytes produced by
 * DataOutputStream and produces five 32-bit values sha[0..4].
 *
 * 9. The hash value is assembled from the first and second 32-bit values of 
 * the SHA-1 message digest. If the result of the message digest, the five
 * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named 
 * sha, the hash value would be computed as follows:
 *
 * long hash = ((sha[0] >>> 24) & 0xFF) |
 * ((sha[0] >>> 16) & 0xFF) << 8 |
 * ((sha[0] >>> 8) & 0xFF) << 16 |
 * ((sha[0] >>> 0) & 0xFF) << 24 |
 * ((sha[1] >>> 24) & 0xFF) << 32 |
 * ((sha[1] >>> 16) & 0xFF) << 40 |
 * ((sha[1] >>> 8) & 0xFF) << 48 |
 * ((sha[1] >>> 0) & 0xFF) << 56;
 * 
* * @author Rajendra Inamdar, Vishal Vishnoi */ public class SerialVersionUIDAdder extends ClassAdapter { /** * Flag that indicates if we need to compute SVUID. */ protected boolean computeSVUID; /** * Set to true if the class already has SVUID. */ protected boolean hasSVUID; /** * Classes access flags. */ protected int access; /** * Internal name of the class */ protected String name; /** * Interfaces implemented by the class. */ protected String[] interfaces; /** * Collection of fields. (except private static and private transient * fields) */ protected Collection svuidFields; /** * Set to true if the class has static initializer. */ protected boolean hasStaticInitializer; /** * Collection of non-private constructors. */ protected Collection svuidConstructors; /** * Collection of non-private methods. */ protected Collection svuidMethods; /** * Creates a new {@link SerialVersionUIDAdder}. * * @param cv a {@link ClassVisitor} to which this visitor will delegate * calls. */ public SerialVersionUIDAdder(final ClassVisitor cv) { super(cv); svuidFields = new ArrayList(); svuidConstructors = new ArrayList(); svuidMethods = new ArrayList(); } // ------------------------------------------------------------------------ // Overriden methods // ------------------------------------------------------------------------ /* * Visit class header and get class name, access , and interfaces * information (step 1,2, and 3) for SVUID computation. */ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; if (computeSVUID) { this.name = name; this.access = access; this.interfaces = interfaces; } super.visit(version, access, name, signature, superName, interfaces); } /* * Visit the methods and get constructor and method information (step 5 and * 7). Also determine if there is a class initializer (step 6). */ public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (computeSVUID) { if ("".equals(name)) { hasStaticInitializer = true; } /* * Remembers non private constructors and methods for SVUID * computation For constructor and method modifiers, only the * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags * are used. */ int mods = access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT); // all non private methods if ((access & Opcodes.ACC_PRIVATE) == 0) { if ("".equals(name)) { svuidConstructors.add(new Item(name, mods, desc)); } else if (!"".equals(name)) { svuidMethods.add(new Item(name, mods, desc)); } } } return cv.visitMethod(access, name, desc, signature, exceptions); } /* * Gets class field information for step 4 of the algorithm. Also determines * if the class already has a SVUID. */ public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { if (computeSVUID) { if ("serialVersionUID".equals(name)) { // since the class already has SVUID, we won't be computing it. computeSVUID = false; hasSVUID = true; } /* * Remember field for SVUID computation For field modifiers, only * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when * computing serialVersionUID values. */ if ((access & Opcodes.ACC_PRIVATE) == 0 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) { int mods = access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT); svuidFields.add(new Item(name, mods, desc)); } } return super.visitField(access, name, desc, signature, value); } /** * Handle a bizarre special case. Nested classes (static classes declared * inside another class) that are protected have their access bit set to * public in their class files to deal with some odd reflection situation. * Our SVUID computation must do as the JVM does and ignore access bits in * the class file in favor of the access bits InnerClass attribute. */ public void visitInnerClass(final String aname, final String outerName, final String innerName, final int attr_access) { if ((name != null) && name.equals(aname)) { this.access = attr_access; } super.visitInnerClass(aname, outerName, innerName, attr_access); } /* * Add the SVUID if class doesn't have one */ public void visitEnd() { // compute SVUID and add it to the class if (computeSVUID && !hasSVUID) { try { cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, new Long(computeSVUID())); } catch (Throwable e) { throw new RuntimeException("Error while computing SVUID for " + name, e); } } super.visitEnd(); } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Returns the value of SVUID if the class doesn't have one already. Please * note that 0 is returned if the class already has SVUID, thus use * isHasSVUID to determine if the class already had an SVUID. * * @return Returns the serial version UID */ protected long computeSVUID() throws IOException { ByteArrayOutputStream bos; DataOutputStream dos = null; long svuid = 0; try { bos = new ByteArrayOutputStream(); dos = new DataOutputStream(bos); /* * 1. The class name written using UTF encoding. */ dos.writeUTF(name.replace('/', '.')); /* * 2. The class modifiers written as a 32-bit integer. */ dos.writeInt(access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); /* * 3. The name of each interface sorted by name written using UTF * encoding. */ Arrays.sort(interfaces); for (int i = 0; i < interfaces.length; i++) { dos.writeUTF(interfaces[i].replace('/', '.')); } /* * 4. For each field of the class sorted by field name (except * private static and private transient fields): * * 1. The name of the field in UTF encoding. 2. The modifiers of the * field written as a 32-bit integer. 3. The descriptor of the field * in UTF encoding * * Note that field signatures are not dot separated. Method and * constructor signatures are dot separated. Go figure... */ writeItems(svuidFields, dos, false); /* * 5. If a class initializer exists, write out the following: 1. The * name of the method, , in UTF encoding. 2. The modifier of * the method, java.lang.reflect.Modifier.STATIC, written as a * 32-bit integer. 3. The descriptor of the method, ()V, in UTF * encoding. */ if (hasStaticInitializer) { dos.writeUTF(""); dos.writeInt(Opcodes.ACC_STATIC); dos.writeUTF("()V"); } // if.. /* * 6. For each non-private constructor sorted by method name and * signature: 1. The name of the method, , in UTF encoding. 2. * The modifiers of the method written as a 32-bit integer. 3. The * descriptor of the method in UTF encoding. */ writeItems(svuidConstructors, dos, true); /* * 7. For each non-private method sorted by method name and * signature: 1. The name of the method in UTF encoding. 2. The * modifiers of the method written as a 32-bit integer. 3. The * descriptor of the method in UTF encoding. */ writeItems(svuidMethods, dos, true); dos.flush(); /* * 8. The SHA-1 algorithm is executed on the stream of bytes * produced by DataOutputStream and produces five 32-bit values * sha[0..4]. */ byte[] hashBytes = computeSHAdigest(bos.toByteArray()); /* * 9. The hash value is assembled from the first and second 32-bit * values of the SHA-1 message digest. If the result of the message * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of * five int values named sha, the hash value would be computed as * follows: * * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) << * 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) << * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) << * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) << * 56; */ for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { svuid = (svuid << 8) | (hashBytes[i] & 0xFF); } } finally { // close the stream (if open) if (dos != null) { dos.close(); } } return svuid; } /** * Returns the SHA-1 message digest of the given value. * * @param value the value whose SHA message digest must be computed. * @return the SHA-1 message digest of the given value. */ protected byte[] computeSHAdigest(final byte[] value) { try { return MessageDigest.getInstance("SHA").digest(value); } catch (Exception e) { throw new UnsupportedOperationException(e.toString()); } } /** * Sorts the items in the collection and writes it to the data output stream * * @param itemCollection collection of items * @param dos a DataOutputStream value * @param dotted a boolean value * @exception IOException if an error occurs */ private static void writeItems( final Collection itemCollection, final DataOutput dos, final boolean dotted) throws IOException { int size = itemCollection.size(); Item[] items = (Item[]) itemCollection.toArray(new Item[size]); Arrays.sort(items); for (int i = 0; i < size; i++) { dos.writeUTF(items[i].name); dos.writeInt(items[i].access); dos.writeUTF(dotted ? items[i].desc.replace('/', '.') : items[i].desc); } } // ------------------------------------------------------------------------ // Inner classes // ------------------------------------------------------------------------ static class Item implements Comparable { final String name; final int access; final String desc; Item(final String name, final int access, final String desc) { this.name = name; this.access = access; this.desc = desc; } public int compareTo(final Object o) { Item other = (Item) o; int retVal = name.compareTo(other.name); if (retVal == 0) { retVal = desc.compareTo(other.desc); } return retVal; } } } asm-3.3.2/src/org/objectweb/asm/commons/RemappingFieldAdapter.java0000644000175000017500000000503311302173367025050 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; /** * A FieldVisitor adapter for type remapping. * * @author Eugene Kuleshov */ public class RemappingFieldAdapter implements FieldVisitor { private final FieldVisitor fv; private final Remapper remapper; public RemappingFieldAdapter(FieldVisitor fv, Remapper remapper) { this.fv = fv; this.remapper = remapper; } public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), visible); return av == null ? null : new RemappingAnnotationAdapter(av, remapper); } public void visitAttribute(Attribute attr) { fv.visitAttribute(attr); } public void visitEnd() { fv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/commons/EmptyVisitor.java0000644000175000017500000001361610701747173023351 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * An empty implementation of the ASM visitor interfaces. * * @author Eric Bruneton */ public class EmptyVisitor implements ClassVisitor, FieldVisitor, MethodVisitor, AnnotationVisitor { public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { } public void visitSource(final String source, final String debug) { } public void visitOuterClass( final String owner, final String name, final String desc) { } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return this; } public void visitAttribute(final Attribute attr) { } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { return this; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return this; } public void visitEnd() { } public AnnotationVisitor visitAnnotationDefault() { return this; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { return this; } public void visitCode() { } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { } public void visitInsn(final int opcode) { } public void visitIntInsn(final int opcode, final int operand) { } public void visitVarInsn(final int opcode, final int var) { } public void visitTypeInsn(final int opcode, final String type) { } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { } public void visitJumpInsn(final int opcode, final Label label) { } public void visitLabel(final Label label) { } public void visitLdcInsn(final Object cst) { } public void visitIincInsn(final int var, final int increment) { } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { } public void visitMultiANewArrayInsn(final String desc, final int dims) { } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { } public void visitLineNumber(final int line, final Label start) { } public void visitMaxs(final int maxStack, final int maxLocals) { } public void visit(final String name, final Object value) { } public void visitEnum( final String name, final String desc, final String value) { } public AnnotationVisitor visitAnnotation( final String name, final String desc) { return this; } public AnnotationVisitor visitArray(final String name) { return this; } } asm-3.3.2/src/org/objectweb/asm/commons/GeneratorAdapter.java0000644000175000017500000013540411211477631024116 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate * code. For example, using this adapter, the class below * *
 * public class Example {
 *     public static void main(String[] args) {
 *         System.out.println("Hello world!");
 *     }
 * }
 * 
* * can be generated as follows: * *
 * ClassWriter cw = new ClassWriter(true);
 * cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);
 * 
 * Method m = Method.getMethod("void <init> ()");
 * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
 * mg.loadThis();
 * mg.invokeConstructor(Type.getType(Object.class), m);
 * mg.returnValue();
 * mg.endMethod();
 * 
 * m = Method.getMethod("void main (String[])");
 * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
 * mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
 * mg.push("Hello world!");
 * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)"));
 * mg.returnValue();
 * mg.endMethod();
 * 
 * cw.visitEnd();
 * 
* * @author Juozas Baliuka * @author Chris Nokleberg * @author Eric Bruneton */ public class GeneratorAdapter extends LocalVariablesSorter { private static final String CLDESC = "Ljava/lang/Class;"; private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte"); private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean"); private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short"); private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character"); private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer"); private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float"); private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long"); private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double"); private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number"); private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()"); private static final Method CHAR_VALUE = Method.getMethod("char charValue()"); private static final Method INT_VALUE = Method.getMethod("int intValue()"); private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()"); private static final Method LONG_VALUE = Method.getMethod("long longValue()"); private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()"); /** * Constant for the {@link #math math} method. */ public static final int ADD = Opcodes.IADD; /** * Constant for the {@link #math math} method. */ public static final int SUB = Opcodes.ISUB; /** * Constant for the {@link #math math} method. */ public static final int MUL = Opcodes.IMUL; /** * Constant for the {@link #math math} method. */ public static final int DIV = Opcodes.IDIV; /** * Constant for the {@link #math math} method. */ public static final int REM = Opcodes.IREM; /** * Constant for the {@link #math math} method. */ public static final int NEG = Opcodes.INEG; /** * Constant for the {@link #math math} method. */ public static final int SHL = Opcodes.ISHL; /** * Constant for the {@link #math math} method. */ public static final int SHR = Opcodes.ISHR; /** * Constant for the {@link #math math} method. */ public static final int USHR = Opcodes.IUSHR; /** * Constant for the {@link #math math} method. */ public static final int AND = Opcodes.IAND; /** * Constant for the {@link #math math} method. */ public static final int OR = Opcodes.IOR; /** * Constant for the {@link #math math} method. */ public static final int XOR = Opcodes.IXOR; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int EQ = Opcodes.IFEQ; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int NE = Opcodes.IFNE; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int LT = Opcodes.IFLT; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int GE = Opcodes.IFGE; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int GT = Opcodes.IFGT; /** * Constant for the {@link #ifCmp ifCmp} method. */ public static final int LE = Opcodes.IFLE; /** * Access flags of the method visited by this adapter. */ private final int access; /** * Return type of the method visited by this adapter. */ private final Type returnType; /** * Argument types of the method visited by this adapter. */ private final Type[] argumentTypes; /** * Types of the local variables of the method visited by this adapter. */ private final List localTypes = new ArrayList(); /** * Creates a new {@link GeneratorAdapter}. * * @param mv the method visitor to which this adapter delegates calls. * @param access the method's access flags (see {@link Opcodes}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). */ public GeneratorAdapter( final MethodVisitor mv, final int access, final String name, final String desc) { super(access, desc, mv); this.access = access; this.returnType = Type.getReturnType(desc); this.argumentTypes = Type.getArgumentTypes(desc); } /** * Creates a new {@link GeneratorAdapter}. * * @param access access flags of the adapted method. * @param method the adapted method. * @param mv the method visitor to which this adapter delegates calls. */ public GeneratorAdapter( final int access, final Method method, final MethodVisitor mv) { super(access, method.getDescriptor(), mv); this.access = access; this.returnType = method.getReturnType(); this.argumentTypes = method.getArgumentTypes(); } /** * Creates a new {@link GeneratorAdapter}. * * @param access access flags of the adapted method. * @param method the adapted method. * @param signature the signature of the adapted method (may be * null). * @param exceptions the exceptions thrown by the adapted method (may be * null). * @param cv the class visitor to which this adapter delegates calls. */ public GeneratorAdapter( final int access, final Method method, final String signature, final Type[] exceptions, final ClassVisitor cv) { this(access, method, cv.visitMethod(access, method.getName(), method.getDescriptor(), signature, getInternalNames(exceptions))); } /** * Returns the internal names of the given types. * * @param types a set of types. * @return the internal names of the given types. */ private static String[] getInternalNames(final Type[] types) { if (types == null) { return null; } String[] names = new String[types.length]; for (int i = 0; i < names.length; ++i) { names[i] = types[i].getInternalName(); } return names; } // ------------------------------------------------------------------------ // Instructions to push constants on the stack // ------------------------------------------------------------------------ /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final boolean value) { push(value ? 1 : 0); } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final int value) { if (value >= -1 && value <= 5) { mv.visitInsn(Opcodes.ICONST_0 + value); } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { mv.visitIntInsn(Opcodes.BIPUSH, value); } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { mv.visitIntInsn(Opcodes.SIPUSH, value); } else { mv.visitLdcInsn(new Integer(value)); } } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final long value) { if (value == 0L || value == 1L) { mv.visitInsn(Opcodes.LCONST_0 + (int) value); } else { mv.visitLdcInsn(new Long(value)); } } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final float value) { int bits = Float.floatToIntBits(value); if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 mv.visitInsn(Opcodes.FCONST_0 + (int) value); } else { mv.visitLdcInsn(new Float(value)); } } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final double value) { long bits = Double.doubleToLongBits(value); if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d mv.visitInsn(Opcodes.DCONST_0 + (int) value); } else { mv.visitLdcInsn(new Double(value)); } } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. May be null. */ public void push(final String value) { if (value == null) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.visitLdcInsn(value); } } /** * Generates the instruction to push the given value on the stack. * * @param value the value to be pushed on the stack. */ public void push(final Type value) { if (value == null) { mv.visitInsn(Opcodes.ACONST_NULL); } else { switch (value.getSort()) { case Type.BOOLEAN: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLDESC); break; case Type.CHAR: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLDESC); break; case Type.BYTE: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLDESC); break; case Type.SHORT: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLDESC); break; case Type.INT: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLDESC); break; case Type.FLOAT: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLDESC); break; case Type.LONG: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLDESC); break; case Type.DOUBLE: mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLDESC); break; default: mv.visitLdcInsn(value); } } } // ------------------------------------------------------------------------ // Instructions to load and store method arguments // ------------------------------------------------------------------------ /** * Returns the index of the given method argument in the frame's local * variables array. * * @param arg the index of a method argument. * @return the index of the given method argument in the frame's local * variables array. */ private int getArgIndex(final int arg) { int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; for (int i = 0; i < arg; i++) { index += argumentTypes[i].getSize(); } return index; } /** * Generates the instruction to push a local variable on the stack. * * @param type the type of the local variable to be loaded. * @param index an index in the frame's local variables array. */ private void loadInsn(final Type type, final int index) { mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); } /** * Generates the instruction to store the top stack value in a local * variable. * * @param type the type of the local variable to be stored. * @param index an index in the frame's local variables array. */ private void storeInsn(final Type type, final int index) { mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); } /** * Generates the instruction to load 'this' on the stack. */ public void loadThis() { if ((access & Opcodes.ACC_STATIC) != 0) { throw new IllegalStateException("no 'this' pointer within static method"); } mv.visitVarInsn(Opcodes.ALOAD, 0); } /** * Generates the instruction to load the given method argument on the stack. * * @param arg the index of a method argument. */ public void loadArg(final int arg) { loadInsn(argumentTypes[arg], getArgIndex(arg)); } /** * Generates the instructions to load the given method arguments on the * stack. * * @param arg the index of the first method argument to be loaded. * @param count the number of method arguments to be loaded. */ public void loadArgs(final int arg, final int count) { int index = getArgIndex(arg); for (int i = 0; i < count; ++i) { Type t = argumentTypes[arg + i]; loadInsn(t, index); index += t.getSize(); } } /** * Generates the instructions to load all the method arguments on the stack. */ public void loadArgs() { loadArgs(0, argumentTypes.length); } /** * Generates the instructions to load all the method arguments on the stack, * as a single object array. */ public void loadArgArray() { push(argumentTypes.length); newArray(OBJECT_TYPE); for (int i = 0; i < argumentTypes.length; i++) { dup(); push(i); loadArg(i); box(argumentTypes[i]); arrayStore(OBJECT_TYPE); } } /** * Generates the instruction to store the top stack value in the given * method argument. * * @param arg the index of a method argument. */ public void storeArg(final int arg) { storeInsn(argumentTypes[arg], getArgIndex(arg)); } // ------------------------------------------------------------------------ // Instructions to load and store local variables // ------------------------------------------------------------------------ /** * Returns the type of the given local variable. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. * @return the type of the given local variable. */ public Type getLocalType(final int local) { return (Type) localTypes.get(local - firstLocal); } protected void setLocalType(final int local, final Type type) { int index = local - firstLocal; while (localTypes.size() < index + 1) { localTypes.add(null); } localTypes.set(index, type); } /** * Generates the instruction to load the given local variable on the stack. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. */ public void loadLocal(final int local) { loadInsn(getLocalType(local), local); } /** * Generates the instruction to load the given local variable on the stack. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. * @param type the type of this local variable. */ public void loadLocal(final int local, final Type type) { setLocalType(local, type); loadInsn(type, local); } /** * Generates the instruction to store the top stack value in the given local * variable. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. */ public void storeLocal(final int local) { storeInsn(getLocalType(local), local); } /** * Generates the instruction to store the top stack value in the given local * variable. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. * @param type the type of this local variable. */ public void storeLocal(final int local, final Type type) { setLocalType(local, type); storeInsn(type, local); } /** * Generates the instruction to load an element from an array. * * @param type the type of the array element to be loaded. */ public void arrayLoad(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); } /** * Generates the instruction to store an element in an array. * * @param type the type of the array element to be stored. */ public void arrayStore(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); } // ------------------------------------------------------------------------ // Instructions to manage the stack // ------------------------------------------------------------------------ /** * Generates a POP instruction. */ public void pop() { mv.visitInsn(Opcodes.POP); } /** * Generates a POP2 instruction. */ public void pop2() { mv.visitInsn(Opcodes.POP2); } /** * Generates a DUP instruction. */ public void dup() { mv.visitInsn(Opcodes.DUP); } /** * Generates a DUP2 instruction. */ public void dup2() { mv.visitInsn(Opcodes.DUP2); } /** * Generates a DUP_X1 instruction. */ public void dupX1() { mv.visitInsn(Opcodes.DUP_X1); } /** * Generates a DUP_X2 instruction. */ public void dupX2() { mv.visitInsn(Opcodes.DUP_X2); } /** * Generates a DUP2_X1 instruction. */ public void dup2X1() { mv.visitInsn(Opcodes.DUP2_X1); } /** * Generates a DUP2_X2 instruction. */ public void dup2X2() { mv.visitInsn(Opcodes.DUP2_X2); } /** * Generates a SWAP instruction. */ public void swap() { mv.visitInsn(Opcodes.SWAP); } /** * Generates the instructions to swap the top two stack values. * * @param prev type of the top - 1 stack value. * @param type type of the top stack value. */ public void swap(final Type prev, final Type type) { if (type.getSize() == 1) { if (prev.getSize() == 1) { swap(); // same as dupX1(), pop(); } else { dupX2(); pop(); } } else { if (prev.getSize() == 1) { dup2X1(); pop2(); } else { dup2X2(); pop2(); } } } // ------------------------------------------------------------------------ // Instructions to do mathematical and logical operations // ------------------------------------------------------------------------ /** * Generates the instruction to do the specified mathematical or logical * operation. * * @param op a mathematical or logical operation. Must be one of ADD, SUB, * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR. * @param type the type of the operand(s) for this operation. */ public void math(final int op, final Type type) { mv.visitInsn(type.getOpcode(op)); } /** * Generates the instructions to compute the bitwise negation of the top * stack value. */ public void not() { mv.visitInsn(Opcodes.ICONST_1); mv.visitInsn(Opcodes.IXOR); } /** * Generates the instruction to increment the given local variable. * * @param local the local variable to be incremented. * @param amount the amount by which the local variable must be incremented. */ public void iinc(final int local, final int amount) { mv.visitIincInsn(local, amount); } /** * Generates the instructions to cast a numerical value from one type to * another. * * @param from the type of the top stack value * @param to the type into which this value must be cast. */ public void cast(final Type from, final Type to) { if (from != to) { if (from == Type.DOUBLE_TYPE) { if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.D2F); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.D2L); } else { mv.visitInsn(Opcodes.D2I); cast(Type.INT_TYPE, to); } } else if (from == Type.FLOAT_TYPE) { if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.F2D); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.F2L); } else { mv.visitInsn(Opcodes.F2I); cast(Type.INT_TYPE, to); } } else if (from == Type.LONG_TYPE) { if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.L2D); } else if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.L2F); } else { mv.visitInsn(Opcodes.L2I); cast(Type.INT_TYPE, to); } } else { if (to == Type.BYTE_TYPE) { mv.visitInsn(Opcodes.I2B); } else if (to == Type.CHAR_TYPE) { mv.visitInsn(Opcodes.I2C); } else if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.I2D); } else if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.I2F); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.I2L); } else if (to == Type.SHORT_TYPE) { mv.visitInsn(Opcodes.I2S); } } } } // ------------------------------------------------------------------------ // Instructions to do boxing and unboxing operations // ------------------------------------------------------------------------ private static Type getBoxedType(final Type type) { switch (type.getSort()) { case Type.BYTE: return BYTE_TYPE; case Type.BOOLEAN: return BOOLEAN_TYPE; case Type.SHORT: return SHORT_TYPE; case Type.CHAR: return CHARACTER_TYPE; case Type.INT: return INTEGER_TYPE; case Type.FLOAT: return FLOAT_TYPE; case Type.LONG: return LONG_TYPE; case Type.DOUBLE: return DOUBLE_TYPE; } return type; } /** * Generates the instructions to box the top stack value. This value is * replaced by its boxed equivalent on top of the stack. * * @param type the type of the top stack value. */ public void box(final Type type) { if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { return; } if (type == Type.VOID_TYPE) { push((String) null); } else { Type boxed = getBoxedType(type); newInstance(boxed); if (type.getSize() == 2) { // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o dupX2(); dupX2(); pop(); } else { // p -> po -> opo -> oop -> o dupX1(); swap(); } invokeConstructor(boxed, new Method("", Type.VOID_TYPE, new Type[] { type })); } } /** * Generates the instructions to box the top stack value using Java 5's * valueOf() method. This value is replaced by its boxed equivalent on top * of the stack. * * @param type the type of the top stack value. * @author Prashant Deva */ public void valueOf(final Type type) { if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { return; } if (type == Type.VOID_TYPE) { push((String) null); } else { Type boxed = getBoxedType(type); invokeStatic(boxed, new Method("valueOf", boxed, new Type[] { type })); } } /** * Generates the instructions to unbox the top stack value. This value is * replaced by its unboxed equivalent on top of the stack. * * @param type the type of the top stack value. */ public void unbox(final Type type) { Type t = NUMBER_TYPE; Method sig = null; switch (type.getSort()) { case Type.VOID: return; case Type.CHAR: t = CHARACTER_TYPE; sig = CHAR_VALUE; break; case Type.BOOLEAN: t = BOOLEAN_TYPE; sig = BOOLEAN_VALUE; break; case Type.DOUBLE: sig = DOUBLE_VALUE; break; case Type.FLOAT: sig = FLOAT_VALUE; break; case Type.LONG: sig = LONG_VALUE; break; case Type.INT: case Type.SHORT: case Type.BYTE: sig = INT_VALUE; } if (sig == null) { checkCast(type); } else { checkCast(t); invokeVirtual(t, sig); } } // ------------------------------------------------------------------------ // Instructions to jump to other instructions // ------------------------------------------------------------------------ /** * Creates a new {@link Label}. * * @return a new {@link Label}. */ public Label newLabel() { return new Label(); } /** * Marks the current code position with the given label. * * @param label a label. */ public void mark(final Label label) { mv.visitLabel(label); } /** * Marks the current code position with a new label. * * @return the label that was created to mark the current code position. */ public Label mark() { Label label = new Label(); mv.visitLabel(label); return label; } /** * Generates the instructions to jump to a label based on the comparison of * the top two stack values. * * @param type the type of the top two stack values. * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, * LE. * @param label where to jump if the comparison result is true. */ public void ifCmp(final Type type, final int mode, final Label label) { switch (type.getSort()) { case Type.LONG: mv.visitInsn(Opcodes.LCMP); break; case Type.DOUBLE: mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPG : Opcodes.DCMPL); break; case Type.FLOAT: mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPG : Opcodes.FCMPL); break; case Type.ARRAY: case Type.OBJECT: switch (mode) { case EQ: mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); return; case NE: mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); return; } throw new IllegalArgumentException("Bad comparison for type " + type); default: int intOp = -1; switch (mode) { case EQ: intOp = Opcodes.IF_ICMPEQ; break; case NE: intOp = Opcodes.IF_ICMPNE; break; case GE: intOp = Opcodes.IF_ICMPGE; break; case LT: intOp = Opcodes.IF_ICMPLT; break; case LE: intOp = Opcodes.IF_ICMPLE; break; case GT: intOp = Opcodes.IF_ICMPGT; break; } mv.visitJumpInsn(intOp, label); return; } mv.visitJumpInsn(mode, label); } /** * Generates the instructions to jump to a label based on the comparison of * the top two integer stack values. * * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, * LE. * @param label where to jump if the comparison result is true. */ public void ifICmp(final int mode, final Label label) { ifCmp(Type.INT_TYPE, mode, label); } /** * Generates the instructions to jump to a label based on the comparison of * the top integer stack value with zero. * * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, * LE. * @param label where to jump if the comparison result is true. */ public void ifZCmp(final int mode, final Label label) { mv.visitJumpInsn(mode, label); } /** * Generates the instruction to jump to the given label if the top stack * value is null. * * @param label where to jump if the condition is true. */ public void ifNull(final Label label) { mv.visitJumpInsn(Opcodes.IFNULL, label); } /** * Generates the instruction to jump to the given label if the top stack * value is not null. * * @param label where to jump if the condition is true. */ public void ifNonNull(final Label label) { mv.visitJumpInsn(Opcodes.IFNONNULL, label); } /** * Generates the instruction to jump to the given label. * * @param label where to jump if the condition is true. */ public void goTo(final Label label) { mv.visitJumpInsn(Opcodes.GOTO, label); } /** * Generates a RET instruction. * * @param local a local variable identifier, as returned by * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. */ public void ret(final int local) { mv.visitVarInsn(Opcodes.RET, local); } /** * Generates the instructions for a switch statement. * * @param keys the switch case keys. * @param generator a generator to generate the code for the switch cases. */ public void tableSwitch( final int[] keys, final TableSwitchGenerator generator) { float density; if (keys.length == 0) { density = 0; } else { density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1); } tableSwitch(keys, generator, density >= 0.5f); } /** * Generates the instructions for a switch statement. * * @param keys the switch case keys. * @param generator a generator to generate the code for the switch cases. * @param useTable true to use a TABLESWITCH instruction, or * false to use a LOOKUPSWITCH instruction. */ public void tableSwitch( final int[] keys, final TableSwitchGenerator generator, final boolean useTable) { for (int i = 1; i < keys.length; ++i) { if (keys[i] < keys[i - 1]) { throw new IllegalArgumentException("keys must be sorted ascending"); } } Label def = newLabel(); Label end = newLabel(); if (keys.length > 0) { int len = keys.length; int min = keys[0]; int max = keys[len - 1]; int range = max - min + 1; if (useTable) { Label[] labels = new Label[range]; Arrays.fill(labels, def); for (int i = 0; i < len; ++i) { labels[keys[i] - min] = newLabel(); } mv.visitTableSwitchInsn(min, max, def, labels); for (int i = 0; i < range; ++i) { Label label = labels[i]; if (label != def) { mark(label); generator.generateCase(i + min, end); } } } else { Label[] labels = new Label[len]; for (int i = 0; i < len; ++i) { labels[i] = newLabel(); } mv.visitLookupSwitchInsn(def, keys, labels); for (int i = 0; i < len; ++i) { mark(labels[i]); generator.generateCase(keys[i], end); } } } mark(def); generator.generateDefault(); mark(end); } /** * Generates the instruction to return the top stack value to the caller. */ public void returnValue() { mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); } // ------------------------------------------------------------------------ // Instructions to load and store fields // ------------------------------------------------------------------------ /** * Generates a get field or set field instruction. * * @param opcode the instruction's opcode. * @param ownerType the class in which the field is defined. * @param name the name of the field. * @param fieldType the type of the field. */ private void fieldInsn( final int opcode, final Type ownerType, final String name, final Type fieldType) { mv.visitFieldInsn(opcode, ownerType.getInternalName(), name, fieldType.getDescriptor()); } /** * Generates the instruction to push the value of a static field on the * stack. * * @param owner the class in which the field is defined. * @param name the name of the field. * @param type the type of the field. */ public void getStatic(final Type owner, final String name, final Type type) { fieldInsn(Opcodes.GETSTATIC, owner, name, type); } /** * Generates the instruction to store the top stack value in a static field. * * @param owner the class in which the field is defined. * @param name the name of the field. * @param type the type of the field. */ public void putStatic(final Type owner, final String name, final Type type) { fieldInsn(Opcodes.PUTSTATIC, owner, name, type); } /** * Generates the instruction to push the value of a non static field on the * stack. * * @param owner the class in which the field is defined. * @param name the name of the field. * @param type the type of the field. */ public void getField(final Type owner, final String name, final Type type) { fieldInsn(Opcodes.GETFIELD, owner, name, type); } /** * Generates the instruction to store the top stack value in a non static * field. * * @param owner the class in which the field is defined. * @param name the name of the field. * @param type the type of the field. */ public void putField(final Type owner, final String name, final Type type) { fieldInsn(Opcodes.PUTFIELD, owner, name, type); } // ------------------------------------------------------------------------ // Instructions to invoke methods // ------------------------------------------------------------------------ /** * Generates an invoke method instruction. * * @param opcode the instruction's opcode. * @param type the class in which the method is defined. * @param method the method to be invoked. */ private void invokeInsn( final int opcode, final Type type, final Method method) { String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName(); mv.visitMethodInsn(opcode, owner, method.getName(), method.getDescriptor()); } /** * Generates the instruction to invoke a normal method. * * @param owner the class in which the method is defined. * @param method the method to be invoked. */ public void invokeVirtual(final Type owner, final Method method) { invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); } /** * Generates the instruction to invoke a constructor. * * @param type the class in which the constructor is defined. * @param method the constructor to be invoked. */ public void invokeConstructor(final Type type, final Method method) { invokeInsn(Opcodes.INVOKESPECIAL, type, method); } /** * Generates the instruction to invoke a static method. * * @param owner the class in which the method is defined. * @param method the method to be invoked. */ public void invokeStatic(final Type owner, final Method method) { invokeInsn(Opcodes.INVOKESTATIC, owner, method); } /** * Generates the instruction to invoke an interface method. * * @param owner the class in which the method is defined. * @param method the method to be invoked. */ public void invokeInterface(final Type owner, final Method method) { invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); } /** * Generates the instruction to invoke a dynamic method. * * @param method the method to be invoked. */ public void invokeDynamic(final Method method) { invokeInsn(Opcodes.INVOKEDYNAMIC, Type.getObjectType(Opcodes.INVOKEDYNAMIC_OWNER), method); } // ------------------------------------------------------------------------ // Instructions to create objects and arrays // ------------------------------------------------------------------------ /** * Generates a type dependent instruction. * * @param opcode the instruction's opcode. * @param type the instruction's operand. */ private void typeInsn(final int opcode, final Type type) { mv.visitTypeInsn(opcode, type.getInternalName()); } /** * Generates the instruction to create a new object. * * @param type the class of the object to be created. */ public void newInstance(final Type type) { typeInsn(Opcodes.NEW, type); } /** * Generates the instruction to create a new array. * * @param type the type of the array elements. */ public void newArray(final Type type) { int typ; switch (type.getSort()) { case Type.BOOLEAN: typ = Opcodes.T_BOOLEAN; break; case Type.CHAR: typ = Opcodes.T_CHAR; break; case Type.BYTE: typ = Opcodes.T_BYTE; break; case Type.SHORT: typ = Opcodes.T_SHORT; break; case Type.INT: typ = Opcodes.T_INT; break; case Type.FLOAT: typ = Opcodes.T_FLOAT; break; case Type.LONG: typ = Opcodes.T_LONG; break; case Type.DOUBLE: typ = Opcodes.T_DOUBLE; break; default: typeInsn(Opcodes.ANEWARRAY, type); return; } mv.visitIntInsn(Opcodes.NEWARRAY, typ); } // ------------------------------------------------------------------------ // Miscelaneous instructions // ------------------------------------------------------------------------ /** * Generates the instruction to compute the length of an array. */ public void arrayLength() { mv.visitInsn(Opcodes.ARRAYLENGTH); } /** * Generates the instruction to throw an exception. */ public void throwException() { mv.visitInsn(Opcodes.ATHROW); } /** * Generates the instructions to create and throw an exception. The * exception class must have a constructor with a single String argument. * * @param type the class of the exception to be thrown. * @param msg the detailed message of the exception. */ public void throwException(final Type type, final String msg) { newInstance(type); dup(); push(msg); invokeConstructor(type, Method.getMethod("void (String)")); throwException(); } /** * Generates the instruction to check that the top stack value is of the * given type. * * @param type a class or interface type. */ public void checkCast(final Type type) { if (!type.equals(OBJECT_TYPE)) { typeInsn(Opcodes.CHECKCAST, type); } } /** * Generates the instruction to test if the top stack value is of the given * type. * * @param type a class or interface type. */ public void instanceOf(final Type type) { typeInsn(Opcodes.INSTANCEOF, type); } /** * Generates the instruction to get the monitor of the top stack value. */ public void monitorEnter() { mv.visitInsn(Opcodes.MONITORENTER); } /** * Generates the instruction to release the monitor of the top stack value. */ public void monitorExit() { mv.visitInsn(Opcodes.MONITOREXIT); } // ------------------------------------------------------------------------ // Non instructions // ------------------------------------------------------------------------ /** * Marks the end of the visited method. */ public void endMethod() { if ((access & Opcodes.ACC_ABSTRACT) == 0) { mv.visitMaxs(0, 0); } mv.visitEnd(); } /** * Marks the start of an exception handler. * * @param start beginning of the exception handler's scope (inclusive). * @param end end of the exception handler's scope (exclusive). * @param exception internal name of the type of exceptions handled by the * handler. */ public void catchException( final Label start, final Label end, final Type exception) { if (exception == null) { mv.visitTryCatchBlock(start, end, mark(), null); } else { mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName()); } } } asm-3.3.2/src/org/objectweb/asm/commons/AnalyzerAdapter.java0000644000175000017500000006712411435451242023756 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * A {@link MethodAdapter} that keeps track of stack map frame changes between * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This * adapter must be used with the * {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visitX * instruction delegates to the next visitor in the chain, if any, and then * simulates the effect of this instruction on the stack map frame, represented * by {@link #locals} and {@link #stack}. The next visitor in the chain can get * the state of the stack map frame before each instruction by reading * the value of these fields in its visitX methods (this requires a * reference to the AnalyzerAdapter that is before it in the chain). * If this adapter is used with a class that does not contain stack map table * attributes (i.e., pre Java 6 classes) then this adapter may not be able to * compute the stack map frame for each instruction. In this case no exception * is thrown but the {@link #locals} and {@link #stack} fields will be null for * these instructions. * * @author Eric Bruneton */ public class AnalyzerAdapter extends MethodAdapter { /** * List of the local variable slots for current execution * frame. Primitive types are represented by {@link Opcodes#TOP}, * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a * two elements, the second one being TOP). Reference types are represented * by String objects (representing internal names), and uninitialized types * by Label objects (this label designates the NEW instruction that created * this uninitialized value). This field is null for unreacheable * instructions. */ public List locals; /** * List of the operand stack slots for current execution * frame. Primitive types are represented by {@link Opcodes#TOP}, * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a * two elements, the second one being TOP). Reference types are represented * by String objects (representing internal names), and uninitialized types * by Label objects (this label designates the NEW instruction that created * this uninitialized value). This field is null for unreacheable * instructions. */ public List stack; /** * The labels that designate the next instruction to be visited. May be * null. */ private List labels; /** * Information about uninitialized types in the current execution frame. * This map associates internal names to Label objects. Each label * designates a NEW instruction that created the currently uninitialized * types, and the associated internal name represents the NEW operand, i.e. * the final, initialized type value. */ public Map uninitializedTypes; /** * The maximum stack size of this method. */ private int maxStack; /** * The maximum number of local variables of this method. */ private int maxLocals; /** * The owner's class name. */ private String owner; /** * Creates a new {@link AnalyzerAdapter}. * * @param owner the owner's class name. * @param access the method's access flags (see {@link Opcodes}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param mv the method visitor to which this adapter delegates calls. May * be null. */ public AnalyzerAdapter( final String owner, final int access, final String name, final String desc, final MethodVisitor mv) { super(mv); this.owner = owner; locals = new ArrayList(); stack = new ArrayList(); uninitializedTypes = new HashMap(); if ((access & Opcodes.ACC_STATIC) == 0) { if ("".equals(name)) { locals.add(Opcodes.UNINITIALIZED_THIS); } else { locals.add(owner); } } Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; ++i) { Type type = types[i]; switch (type.getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: locals.add(Opcodes.INTEGER); break; case Type.FLOAT: locals.add(Opcodes.FLOAT); break; case Type.LONG: locals.add(Opcodes.LONG); locals.add(Opcodes.TOP); break; case Type.DOUBLE: locals.add(Opcodes.DOUBLE); locals.add(Opcodes.TOP); break; case Type.ARRAY: locals.add(types[i].getDescriptor()); break; // case Type.OBJECT: default: locals.add(types[i].getInternalName()); } } } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { if (type != Opcodes.F_NEW) { // uncompressed frame throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag"); } if (mv != null) { mv.visitFrame(type, nLocal, local, nStack, stack); } if (this.locals != null) { this.locals.clear(); this.stack.clear(); } else { this.locals = new ArrayList(); this.stack = new ArrayList(); } visitFrameTypes(nLocal, local, this.locals); visitFrameTypes(nStack, stack, this.stack); maxStack = Math.max(maxStack, this.stack.size()); } private static void visitFrameTypes( final int n, final Object[] types, final List result) { for (int i = 0; i < n; ++i) { Object type = types[i]; result.add(type); if (type == Opcodes.LONG || type == Opcodes.DOUBLE) { result.add(Opcodes.TOP); } } } public void visitInsn(final int opcode) { if (mv != null) { mv.visitInsn(opcode); } execute(opcode, 0, null); if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { this.locals = null; this.stack = null; } } public void visitIntInsn(final int opcode, final int operand) { if (mv != null) { mv.visitIntInsn(opcode, operand); } execute(opcode, operand, null); } public void visitVarInsn(final int opcode, final int var) { if (mv != null) { mv.visitVarInsn(opcode, var); } execute(opcode, var, null); } public void visitTypeInsn(final int opcode, final String type) { if (opcode == Opcodes.NEW) { if (labels == null) { Label l = new Label(); labels = new ArrayList(3); labels.add(l); if (mv != null) { mv.visitLabel(l); } } for (int i = 0; i < labels.size(); ++i) { uninitializedTypes.put(labels.get(i), type); } } if (mv != null) { mv.visitTypeInsn(opcode, type); } execute(opcode, 0, type); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { if (mv != null) { mv.visitFieldInsn(opcode, owner, name, desc); } execute(opcode, 0, desc); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } if (this.locals == null) { labels = null; return; } pop(desc); if (opcode != Opcodes.INVOKESTATIC && opcode != Opcodes.INVOKEDYNAMIC) { Object t = pop(); if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') { Object u; if (t == Opcodes.UNINITIALIZED_THIS) { u = this.owner; } else { u = uninitializedTypes.get(t); } for (int i = 0; i < locals.size(); ++i) { if (locals.get(i) == t) { locals.set(i, u); } } for (int i = 0; i < stack.size(); ++i) { if (stack.get(i) == t) { stack.set(i, u); } } } } pushDesc(desc); labels = null; } public void visitJumpInsn(final int opcode, final Label label) { if (mv != null) { mv.visitJumpInsn(opcode, label); } execute(opcode, 0, null); if (opcode == Opcodes.GOTO) { this.locals = null; this.stack = null; } } public void visitLabel(final Label label) { if (mv != null) { mv.visitLabel(label); } if (labels == null) { labels = new ArrayList(3); } labels.add(label); } public void visitLdcInsn(final Object cst) { if (mv != null) { mv.visitLdcInsn(cst); } if (this.locals == null) { labels = null; return; } if (cst instanceof Integer) { push(Opcodes.INTEGER); } else if (cst instanceof Long) { push(Opcodes.LONG); push(Opcodes.TOP); } else if (cst instanceof Float) { push(Opcodes.FLOAT); } else if (cst instanceof Double) { push(Opcodes.DOUBLE); push(Opcodes.TOP); } else if (cst instanceof String) { push("java/lang/String"); } else if (cst instanceof Type) { push("java/lang/Class"); } else { throw new IllegalArgumentException(); } labels = null; } public void visitIincInsn(final int var, final int increment) { if (mv != null) { mv.visitIincInsn(var, increment); } execute(Opcodes.IINC, var, null); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { if (mv != null) { mv.visitTableSwitchInsn(min, max, dflt, labels); } execute(Opcodes.TABLESWITCH, 0, null); this.locals = null; this.stack = null; } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { if (mv != null) { mv.visitLookupSwitchInsn(dflt, keys, labels); } execute(Opcodes.LOOKUPSWITCH, 0, null); this.locals = null; this.stack = null; } public void visitMultiANewArrayInsn(final String desc, final int dims) { if (mv != null) { mv.visitMultiANewArrayInsn(desc, dims); } execute(Opcodes.MULTIANEWARRAY, dims, desc); } public void visitMaxs(final int maxStack, final int maxLocals) { if (mv != null) { this.maxStack = Math.max(this.maxStack, maxStack); this.maxLocals = Math.max(this.maxLocals, maxLocals); mv.visitMaxs(this.maxStack, this.maxLocals); } } // ------------------------------------------------------------------------ private Object get(final int local) { maxLocals = Math.max(maxLocals, local); return local < locals.size() ? locals.get(local) : Opcodes.TOP; } private void set(final int local, final Object type) { maxLocals = Math.max(maxLocals, local); while (local >= locals.size()) { locals.add(Opcodes.TOP); } locals.set(local, type); } private void push(final Object type) { stack.add(type); maxStack = Math.max(maxStack, stack.size()); } private void pushDesc(final String desc) { int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; switch (desc.charAt(index)) { case 'V': return; case 'Z': case 'C': case 'B': case 'S': case 'I': push(Opcodes.INTEGER); return; case 'F': push(Opcodes.FLOAT); return; case 'J': push(Opcodes.LONG); push(Opcodes.TOP); return; case 'D': push(Opcodes.DOUBLE); push(Opcodes.TOP); return; case '[': if (index == 0) { push(desc); } else { push(desc.substring(index, desc.length())); } break; // case 'L': default: if (index == 0) { push(desc.substring(1, desc.length() - 1)); } else { push(desc.substring(index + 1, desc.length() - 1)); } } } private Object pop() { return stack.remove(stack.size() - 1); } private void pop(final int n) { int size = stack.size(); int end = size - n; for (int i = size - 1; i >= end; --i) { stack.remove(i); } } private void pop(final String desc) { char c = desc.charAt(0); if (c == '(') { int n = 0; Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; ++i) { n += types[i].getSize(); } pop(n); } else if (c == 'J' || c == 'D') { pop(2); } else { pop(1); } } private void execute(final int opcode, final int iarg, final String sarg) { if (this.locals == null) { labels = null; return; } Object t1, t2, t3, t4; switch (opcode) { case Opcodes.NOP: case Opcodes.INEG: case Opcodes.LNEG: case Opcodes.FNEG: case Opcodes.DNEG: case Opcodes.I2B: case Opcodes.I2C: case Opcodes.I2S: case Opcodes.GOTO: case Opcodes.RETURN: break; case Opcodes.ACONST_NULL: push(Opcodes.NULL); break; case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: case Opcodes.BIPUSH: case Opcodes.SIPUSH: push(Opcodes.INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: push(Opcodes.FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.ILOAD: case Opcodes.FLOAD: case Opcodes.ALOAD: push(get(iarg)); break; case Opcodes.LLOAD: case Opcodes.DLOAD: push(get(iarg)); push(Opcodes.TOP); break; case Opcodes.IALOAD: case Opcodes.BALOAD: case Opcodes.CALOAD: case Opcodes.SALOAD: pop(2); push(Opcodes.INTEGER); break; case Opcodes.LALOAD: case Opcodes.D2L: pop(2); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.FALOAD: pop(2); push(Opcodes.FLOAT); break; case Opcodes.DALOAD: case Opcodes.L2D: pop(2); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.AALOAD: pop(1); t1 = pop(); if (t1 instanceof String) { pushDesc(((String) t1).substring(1)); } else { push("java/lang/Object"); } break; case Opcodes.ISTORE: case Opcodes.FSTORE: case Opcodes.ASTORE: t1 = pop(); set(iarg, t1); if (iarg > 0) { t2 = get(iarg - 1); if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { set(iarg - 1, Opcodes.TOP); } } break; case Opcodes.LSTORE: case Opcodes.DSTORE: pop(1); t1 = pop(); set(iarg, t1); set(iarg + 1, Opcodes.TOP); if (iarg > 0) { t2 = get(iarg - 1); if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { set(iarg - 1, Opcodes.TOP); } } break; case Opcodes.IASTORE: case Opcodes.BASTORE: case Opcodes.CASTORE: case Opcodes.SASTORE: case Opcodes.FASTORE: case Opcodes.AASTORE: pop(3); break; case Opcodes.LASTORE: case Opcodes.DASTORE: pop(4); break; case Opcodes.POP: case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IFLE: case Opcodes.IRETURN: case Opcodes.FRETURN: case Opcodes.ARETURN: case Opcodes.TABLESWITCH: case Opcodes.LOOKUPSWITCH: case Opcodes.ATHROW: case Opcodes.MONITORENTER: case Opcodes.MONITOREXIT: case Opcodes.IFNULL: case Opcodes.IFNONNULL: pop(1); break; case Opcodes.POP2: case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ICMPLE: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: case Opcodes.LRETURN: case Opcodes.DRETURN: pop(2); break; case Opcodes.DUP: t1 = pop(); push(t1); push(t1); break; case Opcodes.DUP_X1: t1 = pop(); t2 = pop(); push(t1); push(t2); push(t1); break; case Opcodes.DUP_X2: t1 = pop(); t2 = pop(); t3 = pop(); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2: t1 = pop(); t2 = pop(); push(t2); push(t1); push(t2); push(t1); break; case Opcodes.DUP2_X1: t1 = pop(); t2 = pop(); t3 = pop(); push(t2); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2_X2: t1 = pop(); t2 = pop(); t3 = pop(); t4 = pop(); push(t2); push(t1); push(t4); push(t3); push(t2); push(t1); break; case Opcodes.SWAP: t1 = pop(); t2 = pop(); push(t1); push(t2); break; case Opcodes.IADD: case Opcodes.ISUB: case Opcodes.IMUL: case Opcodes.IDIV: case Opcodes.IREM: case Opcodes.IAND: case Opcodes.IOR: case Opcodes.IXOR: case Opcodes.ISHL: case Opcodes.ISHR: case Opcodes.IUSHR: case Opcodes.L2I: case Opcodes.D2I: case Opcodes.FCMPL: case Opcodes.FCMPG: pop(2); push(Opcodes.INTEGER); break; case Opcodes.LADD: case Opcodes.LSUB: case Opcodes.LMUL: case Opcodes.LDIV: case Opcodes.LREM: case Opcodes.LAND: case Opcodes.LOR: case Opcodes.LXOR: pop(4); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.FADD: case Opcodes.FSUB: case Opcodes.FMUL: case Opcodes.FDIV: case Opcodes.FREM: case Opcodes.L2F: case Opcodes.D2F: pop(2); push(Opcodes.FLOAT); break; case Opcodes.DADD: case Opcodes.DSUB: case Opcodes.DMUL: case Opcodes.DDIV: case Opcodes.DREM: pop(4); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.LSHL: case Opcodes.LSHR: case Opcodes.LUSHR: pop(3); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.IINC: set(iarg, Opcodes.INTEGER); break; case Opcodes.I2L: case Opcodes.F2L: pop(1); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.I2F: pop(1); push(Opcodes.FLOAT); break; case Opcodes.I2D: case Opcodes.F2D: pop(1); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.F2I: case Opcodes.ARRAYLENGTH: case Opcodes.INSTANCEOF: pop(1); push(Opcodes.INTEGER); break; case Opcodes.LCMP: case Opcodes.DCMPL: case Opcodes.DCMPG: pop(4); push(Opcodes.INTEGER); break; case Opcodes.JSR: case Opcodes.RET: throw new RuntimeException("JSR/RET are not supported"); case Opcodes.GETSTATIC: pushDesc(sarg); break; case Opcodes.PUTSTATIC: pop(sarg); break; case Opcodes.GETFIELD: pop(1); pushDesc(sarg); break; case Opcodes.PUTFIELD: pop(sarg); pop(); break; case Opcodes.NEW: push(labels.get(0)); break; case Opcodes.NEWARRAY: pop(); switch (iarg) { case Opcodes.T_BOOLEAN: pushDesc("[Z"); break; case Opcodes.T_CHAR: pushDesc("[C"); break; case Opcodes.T_BYTE: pushDesc("[B"); break; case Opcodes.T_SHORT: pushDesc("[S"); break; case Opcodes.T_INT: pushDesc("[I"); break; case Opcodes.T_FLOAT: pushDesc("[F"); break; case Opcodes.T_DOUBLE: pushDesc("[D"); break; // case Opcodes.T_LONG: default: pushDesc("[J"); break; } break; case Opcodes.ANEWARRAY: pop(); pushDesc("[" + Type.getObjectType(sarg)); break; case Opcodes.CHECKCAST: pop(); pushDesc(Type.getObjectType(sarg).getDescriptor()); break; // case Opcodes.MULTIANEWARRAY: default: pop(iarg); pushDesc(sarg); break; } labels = null; } } asm-3.3.2/src/org/objectweb/asm/commons/package.html0000644000175000017500000000547710452754520022314 0ustar twernertwerner Provides some useful class and method adapters. The preferred way of using these adapters is by chaining them together and to custom adapters (instead of inheriting from them). Indeed this approach provides more combination possibilities than inheritance. For instance, suppose you want to implement an adapter MyAdapter than needs sorted local variables and intermediate stack map frame values taking into account the local variables sort. By using inheritance, this would require MyAdapter to extend AnalyzerAdapter, itself extending LocalVariablesSorter. But AnalyzerAdapter is not a subclass of LocalVariablesSorter, so this is not possible. On the contrary, by using delegation, you can make LocalVariablesSorter delegate to AnalyzerAdapter, itself delegating to MyAdapter. In this case AnalyzerAdapter computes intermediate frames based on the output of LocalVariablesSorter, and MyAdapter can add new locals by calling the newLocal method on LocalVariablesSorter, and can get the stack map frame state before each instruction by reading the locals and stack fields in AnalyzerAdapter (this requires references from MyAdapter back to LocalVariablesSorter and AnalyzerAdapter). asm-3.3.2/src/org/objectweb/asm/commons/RemappingMethodAdapter.java0000644000175000017500000001270011302173367025244 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * A MethodAdapter for type mapping. * * @author Eugene Kuleshov */ public class RemappingMethodAdapter extends LocalVariablesSorter { protected final Remapper remapper; public RemappingMethodAdapter( int access, String desc, MethodVisitor mv, Remapper renamer) { super(access, desc, mv); this.remapper = renamer; } public void visitFieldInsn( int opcode, String owner, String name, String desc) { super.visitFieldInsn(opcode, remapper.mapType(owner), remapper.mapFieldName(owner, name, desc), remapper.mapDesc(desc)); } public void visitMethodInsn( int opcode, String owner, String name, String desc) { super.visitMethodInsn(opcode, remapper.mapType(owner), remapper.mapMethodName(owner, name, desc), remapper.mapMethodDesc(desc)); } public void visitTypeInsn(int opcode, String type) { super.visitTypeInsn(opcode, remapper.mapType(type)); } public void visitLdcInsn(Object cst) { super.visitLdcInsn(remapper.mapValue(cst)); } public void visitMultiANewArrayInsn(String desc, int dims) { super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); } public void visitTryCatchBlock( Label start, Label end, Label handler, String type) { super.visitTryCatchBlock(start, end, handler, // type == null ? null : remapper.mapType(type)); } public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index) { super.visitLocalVariable(name, remapper.mapDesc(desc), remapper.mapSignature(signature, true), start, end, index); } public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av = mv.visitAnnotation(remapper.mapDesc(desc), visible); return av == null ? av : new RemappingAnnotationAdapter(av, remapper); } public AnnotationVisitor visitAnnotationDefault() { AnnotationVisitor av = mv.visitAnnotationDefault(); return av == null ? av : new RemappingAnnotationAdapter(av, remapper); } public AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { AnnotationVisitor av = mv.visitParameterAnnotation(parameter, remapper.mapDesc(desc), visible); return av == null ? av : new RemappingAnnotationAdapter(av, remapper); } public void visitFrame( int type, int nLocal, Object[] local, int nStack, Object[] stack) { super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, remapEntries(nStack, stack)); } private Object[] remapEntries(int n, Object[] entries) { for (int i = 0; i < n; i++) { if (entries[i] instanceof String) { Object[] newEntries = new Object[n]; if (i > 0) { System.arraycopy(entries, 0, newEntries, 0, i); } do { Object t = entries[i]; newEntries[i++] = t instanceof String ? remapper.mapType((String) t) : t; } while (i < n); return newEntries; } } return entries; } } asm-3.3.2/src/org/objectweb/asm/commons/SimpleRemapper.java0000644000175000017500000000464510701747173023622 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.Collections; import java.util.Map; public class SimpleRemapper extends Remapper { private final Map mapping; public SimpleRemapper(Map mapping) { this.mapping = mapping; } public SimpleRemapper(String oldName, String newName) { this.mapping = Collections.singletonMap(oldName, newName); } public String mapMethodName(String owner, String name, String desc) { String s = map(owner + '.' + name + desc); return s == null ? name : s; } public String mapFieldName(String owner, String name, String desc) { String s = map(owner + '.' + name); return s == null ? name : s; } public String map(String key) { return (String) mapping.get(key); } } asm-3.3.2/src/org/objectweb/asm/commons/LocalVariablesSorter.java0000644000175000017500000002501311442701300024730 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * A {@link MethodAdapter} that renumbers local variables in their order of * appearance. This adapter allows one to easily add new local variables to a * method. It may be used by inheriting from this class, but the preferred way * of using it is via delegation: the next visitor in the chain can indeed add * new locals when needed by calling {@link #newLocal} on this adapter (this * requires a reference back to this {@link LocalVariablesSorter}). * * @author Chris Nokleberg * @author Eugene Kuleshov * @author Eric Bruneton */ public class LocalVariablesSorter extends MethodAdapter { private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); /** * Mapping from old to new local variable indexes. A local variable at index * i of size 1 is remapped to 'mapping[2*i]', while a local variable at * index i of size 2 is remapped to 'mapping[2*i+1]'. */ private int[] mapping = new int[40]; /** * Array used to store stack map local variable types after remapping. */ private Object[] newLocals = new Object[20]; /** * Index of the first local variable, after formal parameters. */ protected final int firstLocal; /** * Index of the next local variable to be created by {@link #newLocal}. */ protected int nextLocal; /** * Indicates if at least one local variable has moved due to remapping. */ private boolean changed; /** * Creates a new {@link LocalVariablesSorter}. * * @param access access flags of the adapted method. * @param desc the method's descriptor (see {@link Type Type}). * @param mv the method visitor to which this adapter delegates calls. */ public LocalVariablesSorter( final int access, final String desc, final MethodVisitor mv) { super(mv); Type[] args = Type.getArgumentTypes(desc); nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0; for (int i = 0; i < args.length; i++) { nextLocal += args[i].getSize(); } firstLocal = nextLocal; } public void visitVarInsn(final int opcode, final int var) { Type type; switch (opcode) { case Opcodes.LLOAD: case Opcodes.LSTORE: type = Type.LONG_TYPE; break; case Opcodes.DLOAD: case Opcodes.DSTORE: type = Type.DOUBLE_TYPE; break; case Opcodes.FLOAD: case Opcodes.FSTORE: type = Type.FLOAT_TYPE; break; case Opcodes.ILOAD: case Opcodes.ISTORE: type = Type.INT_TYPE; break; default: // case Opcodes.ALOAD: // case Opcodes.ASTORE: // case RET: type = OBJECT_TYPE; break; } mv.visitVarInsn(opcode, remap(var, type)); } public void visitIincInsn(final int var, final int increment) { mv.visitIincInsn(remap(var, Type.INT_TYPE), increment); } public void visitMaxs(final int maxStack, final int maxLocals) { mv.visitMaxs(maxStack, nextLocal); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { int newIndex = remap(index, Type.getType(desc)); mv.visitLocalVariable(name, desc, signature, start, end, newIndex); } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { if (type != Opcodes.F_NEW) { // uncompressed frame throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag"); } if (!changed) { // optimization for the case where mapping = identity mv.visitFrame(type, nLocal, local, nStack, stack); return; } // creates a copy of newLocals Object[] oldLocals = new Object[newLocals.length]; System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); // copies types from 'local' to 'newLocals' // 'newLocals' already contains the variables added with 'newLocal' int index = 0; // old local variable index int number = 0; // old local variable number for (; number < nLocal; ++number) { Object t = local[number]; int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1; if (t != Opcodes.TOP) { Type typ = OBJECT_TYPE; if (t == Opcodes.INTEGER) { typ = Type.INT_TYPE; } else if (t == Opcodes.FLOAT) { typ = Type.FLOAT_TYPE; } else if (t == Opcodes.LONG) { typ = Type.LONG_TYPE; } else if (t == Opcodes.DOUBLE) { typ = Type.DOUBLE_TYPE; } else if (t instanceof String) { typ = Type.getObjectType((String) t); } setFrameLocal(remap(index, typ), t); } index += size; } // removes TOP after long and double types as well as trailing TOPs index = 0; number = 0; for (int i = 0; index < newLocals.length; ++i) { Object t = newLocals[index++]; if (t != null && t != Opcodes.TOP) { newLocals[i] = t; number = i + 1; if (t == Opcodes.LONG || t == Opcodes.DOUBLE) { index += 1; } } else { newLocals[i] = Opcodes.TOP; } } // visits remapped frame mv.visitFrame(type, number, newLocals, nStack, stack); // restores original value of 'newLocals' newLocals = oldLocals; } // ------------- /** * Creates a new local variable of the given type. * * @param type the type of the local variable to be created. * @return the identifier of the newly created local variable. */ public int newLocal(final Type type) { Object t; switch (type.getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: t = Opcodes.INTEGER; break; case Type.FLOAT: t = Opcodes.FLOAT; break; case Type.LONG: t = Opcodes.LONG; break; case Type.DOUBLE: t = Opcodes.DOUBLE; break; case Type.ARRAY: t = type.getDescriptor(); break; // case Type.OBJECT: default: t = type.getInternalName(); break; } int local = nextLocal; nextLocal += type.getSize(); setLocalType(local, type); setFrameLocal(local, t); return local; } /** * Sets the current type of the given local variable. The default * implementation of this method does nothing. * * @param local a local variable identifier, as returned by {@link #newLocal * newLocal()}. * @param type the type of the value being stored in the local variable */ protected void setLocalType(final int local, final Type type) { } private void setFrameLocal(final int local, final Object type) { int l = newLocals.length; if (local >= l) { Object[] a = new Object[Math.max(2 * l, local + 1)]; System.arraycopy(newLocals, 0, a, 0, l); newLocals = a; } newLocals[local] = type; } private int remap(final int var, final Type type) { if (var + type.getSize() <= firstLocal) { return var; } int key = 2 * var + type.getSize() - 1; int size = mapping.length; if (key >= size) { int[] newMapping = new int[Math.max(2 * size, key + 1)]; System.arraycopy(mapping, 0, newMapping, 0, size); mapping = newMapping; } int value = mapping[key]; if (value == 0) { value = newLocalMapping(type); setLocalType(value, type); mapping[key] = value + 1; } else { value--; } if (value != var) { changed = true; } return value; } protected int newLocalMapping(final Type type) { int local = nextLocal; nextLocal += type.getSize(); return local; } } asm-3.3.2/src/org/objectweb/asm/commons/RemappingSignatureAdapter.java0000644000175000017500000000757010635277351026004 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.signature.SignatureVisitor; /** * A SignatureVisitor adapter for type mapping. * * @author Eugene Kuleshov */ public class RemappingSignatureAdapter implements SignatureVisitor { private final SignatureVisitor v; private final Remapper remapper; private String className; public RemappingSignatureAdapter(SignatureVisitor v, Remapper remapper) { this.v = v; this.remapper = remapper; } public void visitClassType(String name) { className = name; v.visitClassType(remapper.mapType(name)); } public void visitInnerClassType(String name) { className = className + '$' + name; String remappedName = remapper.mapType(className); v.visitInnerClassType(remappedName.substring(remappedName.lastIndexOf('$') + 1)); } public void visitFormalTypeParameter(String name) { v.visitFormalTypeParameter(name); } public void visitTypeVariable(String name) { v.visitTypeVariable(name); } public SignatureVisitor visitArrayType() { v.visitArrayType(); return this; } public void visitBaseType(char descriptor) { v.visitBaseType(descriptor); } public SignatureVisitor visitClassBound() { v.visitClassBound(); return this; } public SignatureVisitor visitExceptionType() { v.visitExceptionType(); return this; } public SignatureVisitor visitInterface() { v.visitInterface(); return this; } public SignatureVisitor visitInterfaceBound() { v.visitInterfaceBound(); return this; } public SignatureVisitor visitParameterType() { v.visitParameterType(); return this; } public SignatureVisitor visitReturnType() { v.visitReturnType(); return this; } public SignatureVisitor visitSuperclass() { v.visitSuperclass(); return this; } public void visitTypeArgument() { v.visitTypeArgument(); } public SignatureVisitor visitTypeArgument(char wildcard) { v.visitTypeArgument(wildcard); return this; } public void visitEnd() { v.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/commons/AdviceAdapter.java0000644000175000017500000004431611221652577023371 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A {@link org.objectweb.asm.MethodAdapter} to insert before, after and around * advices in methods and constructors.

The behavior for constructors is * like this:

    * *
  1. as long as the INVOKESPECIAL for the object initialization has not been * reached, every bytecode instruction is dispatched in the ctor code visitor
  2. * *
  3. when this one is reached, it is only added in the ctor code visitor and * a JP invoke is added
  4. * *
  5. after that, only the other code visitor receives the instructions
  6. * *
* * @author Eugene Kuleshov * @author Eric Bruneton */ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { private static final Object THIS = new Object(); private static final Object OTHER = new Object(); protected int methodAccess; protected String methodDesc; private boolean constructor; private boolean superInitialized; private List stackFrame; private Map branches; /** * Creates a new {@link AdviceAdapter}. * * @param mv the method visitor to which this adapter delegates calls. * @param access the method's access flags (see {@link Opcodes}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). */ protected AdviceAdapter( final MethodVisitor mv, final int access, final String name, final String desc) { super(mv, access, name, desc); methodAccess = access; methodDesc = desc; constructor = "".equals(name); } public void visitCode() { mv.visitCode(); if (constructor) { stackFrame = new ArrayList(); branches = new HashMap(); } else { superInitialized = true; onMethodEnter(); } } public void visitLabel(final Label label) { mv.visitLabel(label); if (constructor && branches != null) { List frame = (List) branches.get(label); if (frame != null) { stackFrame = frame; branches.remove(label); } } } public void visitInsn(final int opcode) { if (constructor) { int s; switch (opcode) { case RETURN: // empty stack onMethodExit(opcode); break; case IRETURN: // 1 before n/a after case FRETURN: // 1 before n/a after case ARETURN: // 1 before n/a after case ATHROW: // 1 before n/a after popValue(); onMethodExit(opcode); break; case LRETURN: // 2 before n/a after case DRETURN: // 2 before n/a after popValue(); popValue(); onMethodExit(opcode); break; case NOP: case LALOAD: // remove 2 add 2 case DALOAD: // remove 2 add 2 case LNEG: case DNEG: case FNEG: case INEG: case L2D: case D2L: case F2I: case I2B: case I2C: case I2S: case I2F: case ARRAYLENGTH: break; case ACONST_NULL: case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: case FCONST_0: case FCONST_1: case FCONST_2: case F2L: // 1 before 2 after case F2D: case I2L: case I2D: pushValue(OTHER); break; case LCONST_0: case LCONST_1: case DCONST_0: case DCONST_1: pushValue(OTHER); pushValue(OTHER); break; case IALOAD: // remove 2 add 1 case FALOAD: // remove 2 add 1 case AALOAD: // remove 2 add 1 case BALOAD: // remove 2 add 1 case CALOAD: // remove 2 add 1 case SALOAD: // remove 2 add 1 case POP: case IADD: case FADD: case ISUB: case LSHL: // 3 before 2 after case LSHR: // 3 before 2 after case LUSHR: // 3 before 2 after case L2I: // 2 before 1 after case L2F: // 2 before 1 after case D2I: // 2 before 1 after case D2F: // 2 before 1 after case FSUB: case FMUL: case FDIV: case FREM: case FCMPL: // 2 before 1 after case FCMPG: // 2 before 1 after case IMUL: case IDIV: case IREM: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case IXOR: case MONITORENTER: case MONITOREXIT: popValue(); break; case POP2: case LSUB: case LMUL: case LDIV: case LREM: case LADD: case LAND: case LOR: case LXOR: case DADD: case DMUL: case DSUB: case DDIV: case DREM: popValue(); popValue(); break; case IASTORE: case FASTORE: case AASTORE: case BASTORE: case CASTORE: case SASTORE: case LCMP: // 4 before 1 after case DCMPL: case DCMPG: popValue(); popValue(); popValue(); break; case LASTORE: case DASTORE: popValue(); popValue(); popValue(); popValue(); break; case DUP: pushValue(peekValue()); break; case DUP_X1: s = stackFrame.size(); stackFrame.add(s - 2, stackFrame.get(s - 1)); break; case DUP_X2: s = stackFrame.size(); stackFrame.add(s - 3, stackFrame.get(s - 1)); break; case DUP2: s = stackFrame.size(); stackFrame.add(s - 2, stackFrame.get(s - 1)); stackFrame.add(s - 2, stackFrame.get(s - 1)); break; case DUP2_X1: s = stackFrame.size(); stackFrame.add(s - 3, stackFrame.get(s - 1)); stackFrame.add(s - 3, stackFrame.get(s - 1)); break; case DUP2_X2: s = stackFrame.size(); stackFrame.add(s - 4, stackFrame.get(s - 1)); stackFrame.add(s - 4, stackFrame.get(s - 1)); break; case SWAP: s = stackFrame.size(); stackFrame.add(s - 2, stackFrame.get(s - 1)); stackFrame.remove(s); break; } } else { switch (opcode) { case RETURN: case IRETURN: case FRETURN: case ARETURN: case LRETURN: case DRETURN: case ATHROW: onMethodExit(opcode); break; } } mv.visitInsn(opcode); } public void visitVarInsn(final int opcode, final int var) { super.visitVarInsn(opcode, var); if (constructor) { switch (opcode) { case ILOAD: case FLOAD: pushValue(OTHER); break; case LLOAD: case DLOAD: pushValue(OTHER); pushValue(OTHER); break; case ALOAD: pushValue(var == 0 ? THIS : OTHER); break; case ASTORE: case ISTORE: case FSTORE: popValue(); break; case LSTORE: case DSTORE: popValue(); popValue(); break; } } } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { mv.visitFieldInsn(opcode, owner, name, desc); if (constructor) { char c = desc.charAt(0); boolean longOrDouble = c == 'J' || c == 'D'; switch (opcode) { case GETSTATIC: pushValue(OTHER); if (longOrDouble) { pushValue(OTHER); } break; case PUTSTATIC: popValue(); if (longOrDouble) { popValue(); } break; case PUTFIELD: popValue(); if (longOrDouble) { popValue(); popValue(); } break; // case GETFIELD: default: if (longOrDouble) { pushValue(OTHER); } } } } public void visitIntInsn(final int opcode, final int operand) { mv.visitIntInsn(opcode, operand); if (constructor && opcode!=NEWARRAY) { pushValue(OTHER); } } public void visitLdcInsn(final Object cst) { mv.visitLdcInsn(cst); if (constructor) { pushValue(OTHER); if (cst instanceof Double || cst instanceof Long) { pushValue(OTHER); } } } public void visitMultiANewArrayInsn(final String desc, final int dims) { mv.visitMultiANewArrayInsn(desc, dims); if (constructor) { for (int i = 0; i < dims; i++) { popValue(); } pushValue(OTHER); } } public void visitTypeInsn(final int opcode, final String type) { mv.visitTypeInsn(opcode, type); // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack if (constructor && opcode == NEW) { pushValue(OTHER); } } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { mv.visitMethodInsn(opcode, owner, name, desc); if (constructor) { Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; i++) { popValue(); if (types[i].getSize() == 2) { popValue(); } } switch (opcode) { // case INVOKESTATIC: // case INVOKEDYNAMIC // break; case INVOKEINTERFACE: case INVOKEVIRTUAL: popValue(); // objectref break; case INVOKESPECIAL: Object type = popValue(); // objectref if (type == THIS && !superInitialized) { onMethodEnter(); superInitialized = true; // once super has been initialized it is no longer // necessary to keep track of stack state constructor = false; } break; } Type returnType = Type.getReturnType(desc); if (returnType != Type.VOID_TYPE) { pushValue(OTHER); if (returnType.getSize() == 2) { pushValue(OTHER); } } } } public void visitJumpInsn(final int opcode, final Label label) { mv.visitJumpInsn(opcode, label); if (constructor) { switch (opcode) { case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case IFNULL: case IFNONNULL: popValue(); break; case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE: popValue(); popValue(); break; case JSR: pushValue(OTHER); break; } addBranch(label); } } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { mv.visitLookupSwitchInsn(dflt, keys, labels); if (constructor) { popValue(); addBranches(dflt, labels); } } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { mv.visitTableSwitchInsn(min, max, dflt, labels); if (constructor) { popValue(); addBranches(dflt, labels); } } private void addBranches(final Label dflt, final Label[] labels) { addBranch(dflt); for (int i = 0; i < labels.length; i++) { addBranch(labels[i]); } } private void addBranch(final Label label) { if (branches.containsKey(label)) { return; } branches.put(label, new ArrayList(stackFrame)); } private Object popValue() { return stackFrame.remove(stackFrame.size() - 1); } private Object peekValue() { return stackFrame.get(stackFrame.size() - 1); } private void pushValue(final Object o) { stackFrame.add(o); } /** * Called at the beginning of the method or after super class class call in * the constructor.

* * Custom code can use or change all the local variables, but should not * change state of the stack. */ protected void onMethodEnter() { } /** * Called before explicit exit from the method using either return or throw. * Top element on the stack contains the return value or exception instance. * For example: * *
     *   public void onMethodExit(int opcode) {
     *     if(opcode==RETURN) {
     *         visitInsn(ACONST_NULL);
     *     } else if(opcode==ARETURN || opcode==ATHROW) {
     *         dup();
     *     } else {
     *         if(opcode==LRETURN || opcode==DRETURN) {
     *             dup2();
     *         } else {
     *             dup();
     *         }
     *         box(Type.getReturnType(this.methodDesc));
     *     }
     *     visitIntInsn(SIPUSH, opcode);
     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
     *   }
     *
     *   // an actual call back method
     *   public static void onExit(Object param, int opcode) {
     *     ...
     * 
* *

* * Custom code can use or change all the local variables, but should not * change state of the stack. * * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, * DRETURN or ATHROW * */ protected void onMethodExit(int opcode) { } // TODO onException, onMethodCall } asm-3.3.2/src/org/objectweb/asm/commons/TryCatchBlockSorter.java0000644000175000017500000000366511327100072024553 0ustar twernertwernerpackage org.objectweb.asm.commons; import java.util.Collections; import java.util.Comparator; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; /** * Sorts the exception handlers in a method innermost-to-outermost. This allows * the programmer to add handlers without worrying about ordering them correctly * with respect to existing, in-code handlers. * * Behavior is only defined for properly-nested handlers. If any "try" blocks * overlap (something that isn't possible in Java code) then this may not do * what you want. In fact, this adapter just sorts by the length of the "try" * block, taking advantage of the fact that a given try block must be larger * than any block it contains). * * @author Adrian Sampson */ public class TryCatchBlockSorter extends MethodNode { private final MethodVisitor mv; public TryCatchBlockSorter( final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { super(access, name, desc, signature, exceptions); this.mv = mv; } public void visitEnd() { // Compares TryCatchBlockNodes by the length of their "try" block. Comparator comp = new Comparator() { public int compare(Object o1, Object o2) { int len1 = blockLength((TryCatchBlockNode) o1); int len2 = blockLength((TryCatchBlockNode) o2); return len1 - len2; } private int blockLength(TryCatchBlockNode block) { int startidx = instructions.indexOf(block.start); int endidx = instructions.indexOf(block.end); return endidx - startidx; } }; Collections.sort(tryCatchBlocks, comp); if (mv != null) { accept(mv); } } } asm-3.3.2/src/org/objectweb/asm/commons/RemappingAnnotationAdapter.java0000644000175000017500000000563711302173367026151 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; /** * An AnnotationVisitor adapter for type remapping. * * @author Eugene Kuleshov */ public class RemappingAnnotationAdapter implements AnnotationVisitor { private final AnnotationVisitor av; private final Remapper renamer; public RemappingAnnotationAdapter(AnnotationVisitor av, Remapper renamer) { this.av = av; this.renamer = renamer; } public void visit(String name, Object value) { av.visit(name, renamer.mapValue(value)); } public void visitEnum(String name, String desc, String value) { av.visitEnum(name, renamer.mapDesc(desc), value); } public AnnotationVisitor visitAnnotation(String name, String desc) { AnnotationVisitor v = av.visitAnnotation(name, renamer.mapDesc(desc)); return v == null ? null : (v == av ? this : new RemappingAnnotationAdapter(v, renamer)); } public AnnotationVisitor visitArray(String name) { AnnotationVisitor v = av.visitArray(name); return v == null ? null : (v == av ? this : new RemappingAnnotationAdapter(v, renamer)); } public void visitEnd() { av.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/commons/TableSwitchGenerator.java0000644000175000017500000000427310635277351024754 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Label; /** * A code generator for switch statements. * * @author Juozas Baliuka * @author Chris Nokleberg * @author Eric Bruneton */ public interface TableSwitchGenerator { /** * Generates the code for a switch case. * * @param key the switch case key. * @param end a label that corresponds to the end of the switch statement. */ void generateCase(int key, Label end); /** * Generates the code for the default switch case. */ void generateDefault(); } asm-3.3.2/src/org/objectweb/asm/commons/Method.java0000644000175000017500000002205610760572331022106 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.HashMap; import java.util.Map; import org.objectweb.asm.Type; /** * A named method descriptor. * * @author Juozas Baliuka * @author Chris Nokleberg * @author Eric Bruneton */ public class Method { /** * The method name. */ private final String name; /** * The method descriptor. */ private final String desc; /** * Maps primitive Java type names to their descriptors. */ private static final Map DESCRIPTORS; static { DESCRIPTORS = new HashMap(); DESCRIPTORS.put("void", "V"); DESCRIPTORS.put("byte", "B"); DESCRIPTORS.put("char", "C"); DESCRIPTORS.put("double", "D"); DESCRIPTORS.put("float", "F"); DESCRIPTORS.put("int", "I"); DESCRIPTORS.put("long", "J"); DESCRIPTORS.put("short", "S"); DESCRIPTORS.put("boolean", "Z"); } /** * Creates a new {@link Method}. * * @param name the method's name. * @param desc the method's descriptor. */ public Method(final String name, final String desc) { this.name = name; this.desc = desc; } /** * Creates a new {@link Method}. * * @param name the method's name. * @param returnType the method's return type. * @param argumentTypes the method's argument types. */ public Method( final String name, final Type returnType, final Type[] argumentTypes) { this(name, Type.getMethodDescriptor(returnType, argumentTypes)); } /** * Creates a new {@link Method}. * * @param m a java.lang.reflect method descriptor * @return a {@link Method} corresponding to the given Java method * declaration. */ public static Method getMethod(java.lang.reflect.Method m) { return new Method(m.getName(), Type.getMethodDescriptor(m)); } /** * Creates a new {@link Method}. * * @param c a java.lang.reflect constructor descriptor * @return a {@link Method} corresponding to the given Java constructor * declaration. */ public static Method getMethod(java.lang.reflect.Constructor c) { return new Method("", Type.getConstructorDescriptor(c)); } /** * Returns a {@link Method} corresponding to the given Java method * declaration. * * @param method a Java method declaration, without argument names, of the * form "returnType name (argumentType1, ... argumentTypeN)", where * the types are in plain Java (e.g. "int", "float", * "java.util.List", ...). Classes of the java.lang package can be * specified by their unqualified name; all other classes names must * be fully qualified. * @return a {@link Method} corresponding to the given Java method * declaration. * @throws IllegalArgumentException if method could not get * parsed. */ public static Method getMethod(final String method) throws IllegalArgumentException { return getMethod(method, false); } /** * Returns a {@link Method} corresponding to the given Java method * declaration. * * @param method a Java method declaration, without argument names, of the * form "returnType name (argumentType1, ... argumentTypeN)", where * the types are in plain Java (e.g. "int", "float", * "java.util.List", ...). Classes of the java.lang package may be * specified by their unqualified name, depending on the * defaultPackage argument; all other classes names must be fully * qualified. * @param defaultPackage true if unqualified class names belong to the * default package, or false if they correspond to java.lang classes. * For instance "Object" means "Object" if this option is true, or * "java.lang.Object" otherwise. * @return a {@link Method} corresponding to the given Java method * declaration. * @throws IllegalArgumentException if method could not get * parsed. */ public static Method getMethod( final String method, final boolean defaultPackage) throws IllegalArgumentException { int space = method.indexOf(' '); int start = method.indexOf('(', space) + 1; int end = method.indexOf(')', start); if (space == -1 || start == -1 || end == -1) { throw new IllegalArgumentException(); } String returnType = method.substring(0, space); String methodName = method.substring(space + 1, start - 1).trim(); StringBuffer sb = new StringBuffer(); sb.append('('); int p; do { String s; p = method.indexOf(',', start); if (p == -1) { s = map(method.substring(start, end).trim(), defaultPackage); } else { s = map(method.substring(start, p).trim(), defaultPackage); start = p + 1; } sb.append(s); } while (p != -1); sb.append(')'); sb.append(map(returnType, defaultPackage)); return new Method(methodName, sb.toString()); } private static String map(final String type, final boolean defaultPackage) { if ("".equals(type)) { return type; } StringBuffer sb = new StringBuffer(); int index = 0; while ((index = type.indexOf("[]", index) + 1) > 0) { sb.append('['); } String t = type.substring(0, type.length() - sb.length() * 2); String desc = (String) DESCRIPTORS.get(t); if (desc != null) { sb.append(desc); } else { sb.append('L'); if (t.indexOf('.') < 0) { if (!defaultPackage) { sb.append("java/lang/"); } sb.append(t); } else { sb.append(t.replace('.', '/')); } sb.append(';'); } return sb.toString(); } /** * Returns the name of the method described by this object. * * @return the name of the method described by this object. */ public String getName() { return name; } /** * Returns the descriptor of the method described by this object. * * @return the descriptor of the method described by this object. */ public String getDescriptor() { return desc; } /** * Returns the return type of the method described by this object. * * @return the return type of the method described by this object. */ public Type getReturnType() { return Type.getReturnType(desc); } /** * Returns the argument types of the method described by this object. * * @return the argument types of the method described by this object. */ public Type[] getArgumentTypes() { return Type.getArgumentTypes(desc); } public String toString() { return name + desc; } public boolean equals(final Object o) { if (!(o instanceof Method)) { return false; } Method other = (Method) o; return name.equals(other.name) && desc.equals(other.desc); } public int hashCode() { return name.hashCode() ^ desc.hashCode(); } }asm-3.3.2/src/org/objectweb/asm/commons/StaticInitMerger.java0000644000175000017500000000667210701747173024114 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@link ClassAdapter} that merges clinit methods into a single one. * * @author Eric Bruneton */ public class StaticInitMerger extends ClassAdapter { private String name; private MethodVisitor clinit; private final String prefix; private int counter; public StaticInitMerger(final String prefix, final ClassVisitor cv) { super(cv); this.prefix = prefix; } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { cv.visit(version, access, name, signature, superName, interfaces); this.name = name; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv; if ("".equals(name)) { int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC; String n = prefix + counter++; mv = cv.visitMethod(a, n, desc, signature, exceptions); if (clinit == null) { clinit = cv.visitMethod(a, name, desc, null, null); } clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc); } else { mv = cv.visitMethod(access, name, desc, signature, exceptions); } return mv; } public void visitEnd() { if (clinit != null) { clinit.visitInsn(Opcodes.RETURN); clinit.visitMaxs(0, 0); } cv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/commons/RemappingClassAdapter.java0000644000175000017500000001217211302173367025074 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; /** * A ClassAdapter for type remapping. * * @author Eugene Kuleshov */ public class RemappingClassAdapter extends ClassAdapter { protected final Remapper remapper; protected String className; public RemappingClassAdapter(ClassVisitor cv, Remapper remapper) { super(cv); this.remapper = remapper; } public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { this.className = name; super.visit(version, access, remapper.mapType(name), remapper.mapSignature(signature, false), remapper.mapType(superName), interfaces == null ? null : remapper.mapTypes(interfaces)); } public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av; av = super.visitAnnotation(remapper.mapDesc(desc), visible); return av == null ? null : createRemappingAnnotationAdapter(av); } public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { FieldVisitor fv = super.visitField(access, remapper.mapFieldName(className, name, desc), remapper.mapDesc(desc), remapper.mapSignature(signature, true), remapper.mapValue(value)); return fv == null ? null : createRemappingFieldAdapter(fv); } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { String newDesc = remapper.mapMethodDesc(desc); MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(className, name, desc), newDesc, remapper.mapSignature(signature, false), exceptions == null ? null : remapper.mapTypes(exceptions)); return mv == null ? null : createRemappingMethodAdapter(access, newDesc, mv); } public void visitInnerClass( String name, String outerName, String innerName, int access) { super.visitInnerClass(remapper.mapType(name), outerName == null ? null : remapper.mapType(outerName), innerName, // TODO should it be changed? access); } public void visitOuterClass(String owner, String name, String desc) { super.visitOuterClass(remapper.mapType(owner), name == null ? null : remapper.mapMethodName(owner, name, desc), desc == null ? null : remapper.mapMethodDesc(desc)); } protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) { return new RemappingFieldAdapter(fv, remapper); } protected MethodVisitor createRemappingMethodAdapter( int access, String newDesc, MethodVisitor mv) { return new RemappingMethodAdapter(access, newDesc, mv, remapper); } protected AnnotationVisitor createRemappingAnnotationAdapter( AnnotationVisitor av) { return new RemappingAnnotationAdapter(av, remapper); } } asm-3.3.2/src/org/objectweb/asm/commons/InstructionAdapter.java0000644000175000017500000010101711327100072024470 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2005 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class InstructionAdapter extends MethodAdapter { public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); public InstructionAdapter(MethodVisitor mv) { super(mv); } public void visitInsn(final int opcode) { switch (opcode) { case Opcodes.NOP: nop(); break; case Opcodes.ACONST_NULL: aconst(null); break; case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: iconst(opcode - Opcodes.ICONST_0); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: lconst(opcode - Opcodes.LCONST_0); break; case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: fconst(opcode - Opcodes.FCONST_0); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: dconst(opcode - Opcodes.DCONST_0); break; case Opcodes.IALOAD: aload(Type.INT_TYPE); break; case Opcodes.LALOAD: aload(Type.LONG_TYPE); break; case Opcodes.FALOAD: aload(Type.FLOAT_TYPE); break; case Opcodes.DALOAD: aload(Type.DOUBLE_TYPE); break; case Opcodes.AALOAD: aload(OBJECT_TYPE); break; case Opcodes.BALOAD: aload(Type.BYTE_TYPE); break; case Opcodes.CALOAD: aload(Type.CHAR_TYPE); break; case Opcodes.SALOAD: aload(Type.SHORT_TYPE); break; case Opcodes.IASTORE: astore(Type.INT_TYPE); break; case Opcodes.LASTORE: astore(Type.LONG_TYPE); break; case Opcodes.FASTORE: astore(Type.FLOAT_TYPE); break; case Opcodes.DASTORE: astore(Type.DOUBLE_TYPE); break; case Opcodes.AASTORE: astore(OBJECT_TYPE); break; case Opcodes.BASTORE: astore(Type.BYTE_TYPE); break; case Opcodes.CASTORE: astore(Type.CHAR_TYPE); break; case Opcodes.SASTORE: astore(Type.SHORT_TYPE); break; case Opcodes.POP: pop(); break; case Opcodes.POP2: pop2(); break; case Opcodes.DUP: dup(); break; case Opcodes.DUP_X1: dupX1(); break; case Opcodes.DUP_X2: dupX2(); break; case Opcodes.DUP2: dup2(); break; case Opcodes.DUP2_X1: dup2X1(); break; case Opcodes.DUP2_X2: dup2X2(); break; case Opcodes.SWAP: swap(); break; case Opcodes.IADD: add(Type.INT_TYPE); break; case Opcodes.LADD: add(Type.LONG_TYPE); break; case Opcodes.FADD: add(Type.FLOAT_TYPE); break; case Opcodes.DADD: add(Type.DOUBLE_TYPE); break; case Opcodes.ISUB: sub(Type.INT_TYPE); break; case Opcodes.LSUB: sub(Type.LONG_TYPE); break; case Opcodes.FSUB: sub(Type.FLOAT_TYPE); break; case Opcodes.DSUB: sub(Type.DOUBLE_TYPE); break; case Opcodes.IMUL: mul(Type.INT_TYPE); break; case Opcodes.LMUL: mul(Type.LONG_TYPE); break; case Opcodes.FMUL: mul(Type.FLOAT_TYPE); break; case Opcodes.DMUL: mul(Type.DOUBLE_TYPE); break; case Opcodes.IDIV: div(Type.INT_TYPE); break; case Opcodes.LDIV: div(Type.LONG_TYPE); break; case Opcodes.FDIV: div(Type.FLOAT_TYPE); break; case Opcodes.DDIV: div(Type.DOUBLE_TYPE); break; case Opcodes.IREM: rem(Type.INT_TYPE); break; case Opcodes.LREM: rem(Type.LONG_TYPE); break; case Opcodes.FREM: rem(Type.FLOAT_TYPE); break; case Opcodes.DREM: rem(Type.DOUBLE_TYPE); break; case Opcodes.INEG: neg(Type.INT_TYPE); break; case Opcodes.LNEG: neg(Type.LONG_TYPE); break; case Opcodes.FNEG: neg(Type.FLOAT_TYPE); break; case Opcodes.DNEG: neg(Type.DOUBLE_TYPE); break; case Opcodes.ISHL: shl(Type.INT_TYPE); break; case Opcodes.LSHL: shl(Type.LONG_TYPE); break; case Opcodes.ISHR: shr(Type.INT_TYPE); break; case Opcodes.LSHR: shr(Type.LONG_TYPE); break; case Opcodes.IUSHR: ushr(Type.INT_TYPE); break; case Opcodes.LUSHR: ushr(Type.LONG_TYPE); break; case Opcodes.IAND: and(Type.INT_TYPE); break; case Opcodes.LAND: and(Type.LONG_TYPE); break; case Opcodes.IOR: or(Type.INT_TYPE); break; case Opcodes.LOR: or(Type.LONG_TYPE); break; case Opcodes.IXOR: xor(Type.INT_TYPE); break; case Opcodes.LXOR: xor(Type.LONG_TYPE); break; case Opcodes.I2L: cast(Type.INT_TYPE, Type.LONG_TYPE); break; case Opcodes.I2F: cast(Type.INT_TYPE, Type.FLOAT_TYPE); break; case Opcodes.I2D: cast(Type.INT_TYPE, Type.DOUBLE_TYPE); break; case Opcodes.L2I: cast(Type.LONG_TYPE, Type.INT_TYPE); break; case Opcodes.L2F: cast(Type.LONG_TYPE, Type.FLOAT_TYPE); break; case Opcodes.L2D: cast(Type.LONG_TYPE, Type.DOUBLE_TYPE); break; case Opcodes.F2I: cast(Type.FLOAT_TYPE, Type.INT_TYPE); break; case Opcodes.F2L: cast(Type.FLOAT_TYPE, Type.LONG_TYPE); break; case Opcodes.F2D: cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE); break; case Opcodes.D2I: cast(Type.DOUBLE_TYPE, Type.INT_TYPE); break; case Opcodes.D2L: cast(Type.DOUBLE_TYPE, Type.LONG_TYPE); break; case Opcodes.D2F: cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE); break; case Opcodes.I2B: cast(Type.INT_TYPE, Type.BYTE_TYPE); break; case Opcodes.I2C: cast(Type.INT_TYPE, Type.CHAR_TYPE); break; case Opcodes.I2S: cast(Type.INT_TYPE, Type.SHORT_TYPE); break; case Opcodes.LCMP: lcmp(); break; case Opcodes.FCMPL: cmpl(Type.FLOAT_TYPE); break; case Opcodes.FCMPG: cmpg(Type.FLOAT_TYPE); break; case Opcodes.DCMPL: cmpl(Type.DOUBLE_TYPE); break; case Opcodes.DCMPG: cmpg(Type.DOUBLE_TYPE); break; case Opcodes.IRETURN: areturn(Type.INT_TYPE); break; case Opcodes.LRETURN: areturn(Type.LONG_TYPE); break; case Opcodes.FRETURN: areturn(Type.FLOAT_TYPE); break; case Opcodes.DRETURN: areturn(Type.DOUBLE_TYPE); break; case Opcodes.ARETURN: areturn(OBJECT_TYPE); break; case Opcodes.RETURN: areturn(Type.VOID_TYPE); break; case Opcodes.ARRAYLENGTH: arraylength(); break; case Opcodes.ATHROW: athrow(); break; case Opcodes.MONITORENTER: monitorenter(); break; case Opcodes.MONITOREXIT: monitorexit(); break; default: throw new IllegalArgumentException(); } } public void visitIntInsn(final int opcode, final int operand) { switch (opcode) { case Opcodes.BIPUSH: iconst(operand); break; case Opcodes.SIPUSH: iconst(operand); break; case Opcodes.NEWARRAY: switch (operand) { case Opcodes.T_BOOLEAN: newarray(Type.BOOLEAN_TYPE); break; case Opcodes.T_CHAR: newarray(Type.CHAR_TYPE); break; case Opcodes.T_BYTE: newarray(Type.BYTE_TYPE); break; case Opcodes.T_SHORT: newarray(Type.SHORT_TYPE); break; case Opcodes.T_INT: newarray(Type.INT_TYPE); break; case Opcodes.T_FLOAT: newarray(Type.FLOAT_TYPE); break; case Opcodes.T_LONG: newarray(Type.LONG_TYPE); break; case Opcodes.T_DOUBLE: newarray(Type.DOUBLE_TYPE); break; default: throw new IllegalArgumentException(); } break; default: throw new IllegalArgumentException(); } } public void visitVarInsn(final int opcode, final int var) { switch (opcode) { case Opcodes.ILOAD: load(var, Type.INT_TYPE); break; case Opcodes.LLOAD: load(var, Type.LONG_TYPE); break; case Opcodes.FLOAD: load(var, Type.FLOAT_TYPE); break; case Opcodes.DLOAD: load(var, Type.DOUBLE_TYPE); break; case Opcodes.ALOAD: load(var, OBJECT_TYPE); break; case Opcodes.ISTORE: store(var, Type.INT_TYPE); break; case Opcodes.LSTORE: store(var, Type.LONG_TYPE); break; case Opcodes.FSTORE: store(var, Type.FLOAT_TYPE); break; case Opcodes.DSTORE: store(var, Type.DOUBLE_TYPE); break; case Opcodes.ASTORE: store(var, OBJECT_TYPE); break; case Opcodes.RET: ret(var); break; default: throw new IllegalArgumentException(); } } public void visitTypeInsn(final int opcode, final String type) { Type t = Type.getObjectType(type); switch (opcode) { case Opcodes.NEW: anew(t); break; case Opcodes.ANEWARRAY: newarray(t); break; case Opcodes.CHECKCAST: checkcast(t); break; case Opcodes.INSTANCEOF: instanceOf(t); break; default: throw new IllegalArgumentException(); } } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { switch (opcode) { case Opcodes.GETSTATIC: getstatic(owner, name, desc); break; case Opcodes.PUTSTATIC: putstatic(owner, name, desc); break; case Opcodes.GETFIELD: getfield(owner, name, desc); break; case Opcodes.PUTFIELD: putfield(owner, name, desc); break; default: throw new IllegalArgumentException(); } } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { switch (opcode) { case Opcodes.INVOKESPECIAL: invokespecial(owner, name, desc); break; case Opcodes.INVOKEVIRTUAL: invokevirtual(owner, name, desc); break; case Opcodes.INVOKESTATIC: invokestatic(owner, name, desc); break; case Opcodes.INVOKEINTERFACE: invokeinterface(owner, name, desc); break; default: throw new IllegalArgumentException(); } } public void visitJumpInsn(final int opcode, final Label label) { switch (opcode) { case Opcodes.IFEQ: ifeq(label); break; case Opcodes.IFNE: ifne(label); break; case Opcodes.IFLT: iflt(label); break; case Opcodes.IFGE: ifge(label); break; case Opcodes.IFGT: ifgt(label); break; case Opcodes.IFLE: ifle(label); break; case Opcodes.IF_ICMPEQ: ificmpeq(label); break; case Opcodes.IF_ICMPNE: ificmpne(label); break; case Opcodes.IF_ICMPLT: ificmplt(label); break; case Opcodes.IF_ICMPGE: ificmpge(label); break; case Opcodes.IF_ICMPGT: ificmpgt(label); break; case Opcodes.IF_ICMPLE: ificmple(label); break; case Opcodes.IF_ACMPEQ: ifacmpeq(label); break; case Opcodes.IF_ACMPNE: ifacmpne(label); break; case Opcodes.GOTO: goTo(label); break; case Opcodes.JSR: jsr(label); break; case Opcodes.IFNULL: ifnull(label); break; case Opcodes.IFNONNULL: ifnonnull(label); break; default: throw new IllegalArgumentException(); } } public void visitLabel(final Label label) { mark(label); } public void visitLdcInsn(final Object cst) { if (cst instanceof Integer) { int val = ((Integer) cst).intValue(); iconst(val); } else if (cst instanceof Byte) { int val = ((Byte) cst).intValue(); iconst(val); } else if (cst instanceof Character) { int val = ((Character) cst).charValue(); iconst(val); } else if (cst instanceof Short) { int val = ((Short) cst).intValue(); iconst(val); } else if (cst instanceof Boolean) { int val = ((Boolean) cst).booleanValue() ? 1 : 0; iconst(val); } else if (cst instanceof Float) { float val = ((Float) cst).floatValue(); fconst(val); } else if (cst instanceof Long) { long val = ((Long) cst).longValue(); lconst(val); } else if (cst instanceof Double) { double val = ((Double) cst).doubleValue(); dconst(val); } else if (cst instanceof String) { aconst(cst); } else if (cst instanceof Type) { tconst((Type) cst); } else { throw new IllegalArgumentException(); } } public void visitIincInsn(final int var, final int increment) { iinc(var, increment); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { tableswitch(min, max, dflt, labels); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { lookupswitch(dflt, keys, labels); } public void visitMultiANewArrayInsn(final String desc, final int dims) { multianewarray(desc, dims); } // ----------------------------------------------------------------------- public void nop() { mv.visitInsn(Opcodes.NOP); } public void aconst(final Object cst) { if (cst == null) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.visitLdcInsn(cst); } } public void iconst(final int cst) { if (cst >= -1 && cst <= 5) { mv.visitInsn(Opcodes.ICONST_0 + cst); } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { mv.visitIntInsn(Opcodes.BIPUSH, cst); } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { mv.visitIntInsn(Opcodes.SIPUSH, cst); } else { mv.visitLdcInsn(new Integer(cst)); } } public void lconst(final long cst) { if (cst == 0L || cst == 1L) { mv.visitInsn(Opcodes.LCONST_0 + (int) cst); } else { mv.visitLdcInsn(new Long(cst)); } } public void fconst(final float cst) { int bits = Float.floatToIntBits(cst); if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 mv.visitInsn(Opcodes.FCONST_0 + (int) cst); } else { mv.visitLdcInsn(new Float(cst)); } } public void dconst(final double cst) { long bits = Double.doubleToLongBits(cst); if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d mv.visitInsn(Opcodes.DCONST_0 + (int) cst); } else { mv.visitLdcInsn(new Double(cst)); } } public void tconst(final Type type) { mv.visitLdcInsn(type); } public void load(final int var, final Type type) { mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var); } public void aload(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); } public void store(final int var, final Type type) { mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var); } public void astore(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); } public void pop() { mv.visitInsn(Opcodes.POP); } public void pop2() { mv.visitInsn(Opcodes.POP2); } public void dup() { mv.visitInsn(Opcodes.DUP); } public void dup2() { mv.visitInsn(Opcodes.DUP2); } public void dupX1() { mv.visitInsn(Opcodes.DUP_X1); } public void dupX2() { mv.visitInsn(Opcodes.DUP_X2); } public void dup2X1() { mv.visitInsn(Opcodes.DUP2_X1); } public void dup2X2() { mv.visitInsn(Opcodes.DUP2_X2); } public void swap() { mv.visitInsn(Opcodes.SWAP); } public void add(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IADD)); } public void sub(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.ISUB)); } public void mul(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IMUL)); } public void div(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IDIV)); } public void rem(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IREM)); } public void neg(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.INEG)); } public void shl(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.ISHL)); } public void shr(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.ISHR)); } public void ushr(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IUSHR)); } public void and(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IAND)); } public void or(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IOR)); } public void xor(final Type type) { mv.visitInsn(type.getOpcode(Opcodes.IXOR)); } public void iinc(final int var, final int increment) { mv.visitIincInsn(var, increment); } public void cast(final Type from, final Type to) { if (from != to) { if (from == Type.DOUBLE_TYPE) { if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.D2F); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.D2L); } else { mv.visitInsn(Opcodes.D2I); cast(Type.INT_TYPE, to); } } else if (from == Type.FLOAT_TYPE) { if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.F2D); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.F2L); } else { mv.visitInsn(Opcodes.F2I); cast(Type.INT_TYPE, to); } } else if (from == Type.LONG_TYPE) { if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.L2D); } else if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.L2F); } else { mv.visitInsn(Opcodes.L2I); cast(Type.INT_TYPE, to); } } else { if (to == Type.BYTE_TYPE) { mv.visitInsn(Opcodes.I2B); } else if (to == Type.CHAR_TYPE) { mv.visitInsn(Opcodes.I2C); } else if (to == Type.DOUBLE_TYPE) { mv.visitInsn(Opcodes.I2D); } else if (to == Type.FLOAT_TYPE) { mv.visitInsn(Opcodes.I2F); } else if (to == Type.LONG_TYPE) { mv.visitInsn(Opcodes.I2L); } else if (to == Type.SHORT_TYPE) { mv.visitInsn(Opcodes.I2S); } } } } public void lcmp() { mv.visitInsn(Opcodes.LCMP); } public void cmpl(final Type type) { mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL); } public void cmpg(final Type type) { mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG); } public void ifeq(final Label label) { mv.visitJumpInsn(Opcodes.IFEQ, label); } public void ifne(final Label label) { mv.visitJumpInsn(Opcodes.IFNE, label); } public void iflt(final Label label) { mv.visitJumpInsn(Opcodes.IFLT, label); } public void ifge(final Label label) { mv.visitJumpInsn(Opcodes.IFGE, label); } public void ifgt(final Label label) { mv.visitJumpInsn(Opcodes.IFGT, label); } public void ifle(final Label label) { mv.visitJumpInsn(Opcodes.IFLE, label); } public void ificmpeq(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label); } public void ificmpne(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPNE, label); } public void ificmplt(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPLT, label); } public void ificmpge(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPGE, label); } public void ificmpgt(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPGT, label); } public void ificmple(final Label label) { mv.visitJumpInsn(Opcodes.IF_ICMPLE, label); } public void ifacmpeq(final Label label) { mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); } public void ifacmpne(final Label label) { mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); } public void goTo(final Label label) { mv.visitJumpInsn(Opcodes.GOTO, label); } public void jsr(final Label label) { mv.visitJumpInsn(Opcodes.JSR, label); } public void ret(final int var) { mv.visitVarInsn(Opcodes.RET, var); } public void tableswitch( final int min, final int max, final Label dflt, final Label[] labels) { mv.visitTableSwitchInsn(min, max, dflt, labels); } public void lookupswitch( final Label dflt, final int[] keys, final Label[] labels) { mv.visitLookupSwitchInsn(dflt, keys, labels); } public void areturn(final Type t) { mv.visitInsn(t.getOpcode(Opcodes.IRETURN)); } public void getstatic( final String owner, final String name, final String desc) { mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc); } public void putstatic( final String owner, final String name, final String desc) { mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc); } public void getfield( final String owner, final String name, final String desc) { mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc); } public void putfield( final String owner, final String name, final String desc) { mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); } public void invokevirtual( final String owner, final String name, final String desc) { mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc); } public void invokespecial( final String owner, final String name, final String desc) { mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc); } public void invokestatic( final String owner, final String name, final String desc) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc); } public void invokeinterface( final String owner, final String name, final String desc) { mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc); } public void anew(final Type type) { mv.visitTypeInsn(Opcodes.NEW, type.getInternalName()); } public void newarray(final Type type) { int typ; switch (type.getSort()) { case Type.BOOLEAN: typ = Opcodes.T_BOOLEAN; break; case Type.CHAR: typ = Opcodes.T_CHAR; break; case Type.BYTE: typ = Opcodes.T_BYTE; break; case Type.SHORT: typ = Opcodes.T_SHORT; break; case Type.INT: typ = Opcodes.T_INT; break; case Type.FLOAT: typ = Opcodes.T_FLOAT; break; case Type.LONG: typ = Opcodes.T_LONG; break; case Type.DOUBLE: typ = Opcodes.T_DOUBLE; break; default: mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName()); return; } mv.visitIntInsn(Opcodes.NEWARRAY, typ); } public void arraylength() { mv.visitInsn(Opcodes.ARRAYLENGTH); } public void athrow() { mv.visitInsn(Opcodes.ATHROW); } public void checkcast(final Type type) { mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName()); } public void instanceOf(final Type type) { mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName()); } public void monitorenter() { mv.visitInsn(Opcodes.MONITORENTER); } public void monitorexit() { mv.visitInsn(Opcodes.MONITOREXIT); } public void multianewarray(final String desc, final int dims) { mv.visitMultiANewArrayInsn(desc, dims); } public void ifnull(final Label label) { mv.visitJumpInsn(Opcodes.IFNULL, label); } public void ifnonnull(final Label label) { mv.visitJumpInsn(Opcodes.IFNONNULL, label); } public void mark(final Label label) { mv.visitLabel(label); } } asm-3.3.2/src/org/objectweb/asm/commons/Remapper.java0000644000175000017500000001430010701747173022435 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; /** * A class responsible for remapping types and names. * Subclasses can override the following methods: * *
    *
  • {@link #map(String)} - map type
  • *
  • {@link #mapFieldName(String, String, String)} - map field name
  • *
  • {@link #mapMethodName(String, String, String)} - map method name
  • *
* * @author Eugene Kuleshov */ public abstract class Remapper { public String mapDesc(String desc) { Type t = Type.getType(desc); switch (t.getSort()) { case Type.ARRAY: String s = mapDesc(t.getElementType().getDescriptor()); for (int i = 0; i < t.getDimensions(); ++i) { s = '[' + s; } return s; case Type.OBJECT: String newType = map(t.getInternalName()); if (newType != null) { return 'L' + newType + ';'; } } return desc; } private Type mapType(Type t) { switch (t.getSort()) { case Type.ARRAY: String s = mapDesc(t.getElementType().getDescriptor()); for (int i = 0; i < t.getDimensions(); ++i) { s = '[' + s; } return Type.getType(s); case Type.OBJECT: s = map(t.getInternalName()); if(s != null) { return Type.getObjectType(s); } } return t; } public String mapType(String type) { if (type == null) { return null; } return mapType(Type.getObjectType(type)).getInternalName(); } public String[] mapTypes(String[] types) { String[] newTypes = null; boolean needMapping = false; for (int i = 0; i < types.length; i++) { String type = types[i]; String newType = map(type); if (newType != null && newTypes == null) { newTypes = new String[types.length]; if (i > 0) { System.arraycopy(types, 0, newTypes, 0, i); } needMapping = true; } if (needMapping) { newTypes[i] = newType == null ? type : newType; } } return needMapping ? newTypes : types; } public String mapMethodDesc(String desc) { if("()V".equals(desc)) { return desc; } Type[] args = Type.getArgumentTypes(desc); String s = "("; for (int i = 0; i < args.length; i++) { s += mapDesc(args[i].getDescriptor()); } Type returnType = Type.getReturnType(desc); if(returnType == Type.VOID_TYPE) { return s + ")V"; } return s + ')' + mapDesc(returnType.getDescriptor()); } public Object mapValue(Object value) { return value instanceof Type ? mapType((Type) value) : value; } /** * * @param typeSignature true if signature is a FieldTypeSignature, such as * the signature parameter of the ClassVisitor.visitField or * MethodVisitor.visitLocalVariable methods */ public String mapSignature(String signature, boolean typeSignature) { if (signature == null) { return null; } SignatureReader r = new SignatureReader(signature); SignatureWriter w = new SignatureWriter(); SignatureVisitor a = createRemappingSignatureAdapter(w); if (typeSignature) { r.acceptType(a); } else { r.accept(a); } return w.toString(); } protected SignatureVisitor createRemappingSignatureAdapter( SignatureVisitor v) { return new RemappingSignatureAdapter(v, this); } /** * Map method name to the new name. Subclasses can override. */ public String mapMethodName(String owner, String name, String desc) { return name; } /** * Map field name to the new name. Subclasses can override. */ public String mapFieldName(String owner, String name, String desc) { return name; } /** * Map type name to the new name. Subclasses can override. */ public String map(String typeName) { return typeName; } } asm-3.3.2/src/org/objectweb/asm/commons/JSRInlinerAdapter.java0000644000175000017500000007140611224532001024133 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.AbstractMap; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.LocalVariableNode; /** * A {@link org.objectweb.asm.MethodAdapter} that removes JSR instructions and * inlines the referenced subroutines. * * Explanation of how it works TODO * * @author Niko Matsakis */ public class JSRInlinerAdapter extends MethodNode implements Opcodes { private static final boolean LOGGING = false; /** * The visitor to which we will emit a translation of this method without * internal subroutines. */ private final MethodVisitor mv; /** * For each label that is jumped to by a JSR, we create a Subroutine * instance. Map is the generic type. */ private final Map subroutineHeads = new HashMap(); /** * This subroutine instance denotes the line of execution that is not * contained within any subroutine; i.e., the "subroutine" that is executing * when a method first begins. */ private final Subroutine mainSubroutine = new Subroutine(); /** * This BitSet contains the index of every instruction that belongs to more * than one subroutine. This should not happen often. */ final BitSet dualCitizens = new BitSet(); /** * Creates a new JSRInliner. * * @param mv the MethodVisitor to send the resulting inlined * method code to (use null for none). * @param access the method's access flags (see {@link Opcodes}). This * parameter also indicates if the method is synthetic and/or * deprecated. * @param name the method's name. * @param desc the method's descriptor (see {@link Type}). * @param signature the method's signature. May be null. * @param exceptions the internal names of the method's exception classes * (see {@link Type#getInternalName() getInternalName}). May be * null. */ public JSRInlinerAdapter( final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { super(access, name, desc, signature, exceptions); this.mv = mv; } /** * Detects a JSR instruction and sets a flag to indicate we will need to do * inlining. */ public void visitJumpInsn(final int opcode, final Label lbl) { super.visitJumpInsn(opcode, lbl); LabelNode ln = ((JumpInsnNode) instructions.getLast()).label; if (opcode == JSR && !subroutineHeads.containsKey(ln)) { subroutineHeads.put(ln, new Subroutine()); } } /** * If any JSRs were seen, triggers the inlining process. Otherwise, forwards * the byte codes untouched. */ public void visitEnd() { if (!subroutineHeads.isEmpty()) { markSubroutines(); if (LOGGING) { log(mainSubroutine.toString()); Iterator it = subroutineHeads.values().iterator(); while (it.hasNext()) { Subroutine sub = (Subroutine) it.next(); log(sub.toString()); } } emitCode(); } // Forward the translate opcodes on if appropriate: if (mv != null) { accept(mv); } } /** * Walks the method and determines which internal subroutine(s), if any, * each instruction is a method of. */ private void markSubroutines() { BitSet anyvisited = new BitSet(); // First walk the main subroutine and find all those instructions which // can be reached without invoking any JSR at all markSubroutineWalk(mainSubroutine, 0, anyvisited); // Go through the head of each subroutine and find any nodes reachable // to that subroutine without following any JSR links. for (Iterator it = subroutineHeads.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); LabelNode lab = (LabelNode) entry.getKey(); Subroutine sub = (Subroutine) entry.getValue(); int index = instructions.indexOf(lab); markSubroutineWalk(sub, index, anyvisited); } } /** * Performs a depth first search walking the normal byte code path starting * at index, and adding each instruction encountered into * the subroutine sub. After this walk is complete, iterates * over the exception handlers to ensure that we also include those byte * codes which are reachable through an exception that may be thrown during * the execution of the subroutine. Invoked from * markSubroutines(). * * @param sub the subroutine whose instructions must be computed. * @param index an instruction of this subroutine. * @param anyvisited indexes of the already visited instructions, i.e. * marked as part of this subroutine or any previously computed * subroutine. */ private void markSubroutineWalk( final Subroutine sub, final int index, final BitSet anyvisited) { if (LOGGING) { log("markSubroutineWalk: sub=" + sub + " index=" + index); } // First find those instructions reachable via normal execution markSubroutineWalkDFS(sub, index, anyvisited); // Now, make sure we also include any applicable exception handlers boolean loop = true; while (loop) { loop = false; for (Iterator it = tryCatchBlocks.iterator(); it.hasNext();) { TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next(); if (LOGGING) { // TODO use of default toString(). log("Scanning try/catch " + trycatch); } // If the handler has already been processed, skip it. int handlerindex = instructions.indexOf(trycatch.handler); if (sub.instructions.get(handlerindex)) { continue; } int startindex = instructions.indexOf(trycatch.start); int endindex = instructions.indexOf(trycatch.end); int nextbit = sub.instructions.nextSetBit(startindex); if (nextbit != -1 && nextbit < endindex) { if (LOGGING) { log("Adding exception handler: " + startindex + '-' + endindex + " due to " + nextbit + " handler " + handlerindex); } markSubroutineWalkDFS(sub, handlerindex, anyvisited); loop = true; } } } } /** * Performs a simple DFS of the instructions, assigning each to the * subroutine sub. Starts from index. * Invoked only by markSubroutineWalk(). * * @param sub the subroutine whose instructions must be computed. * @param index an instruction of this subroutine. * @param anyvisited indexes of the already visited instructions, i.e. * marked as part of this subroutine or any previously computed * subroutine. */ private void markSubroutineWalkDFS( final Subroutine sub, int index, final BitSet anyvisited) { while (true) { AbstractInsnNode node = instructions.get(index); // don't visit a node twice if (sub.instructions.get(index)) { return; } sub.instructions.set(index); // check for those nodes already visited by another subroutine if (anyvisited.get(index)) { dualCitizens.set(index); if (LOGGING) { log("Instruction #" + index + " is dual citizen."); } } anyvisited.set(index); if (node.getType() == AbstractInsnNode.JUMP_INSN && node.getOpcode() != JSR) { // we do not follow recursively called subroutines here; but any // other sort of branch we do follow JumpInsnNode jnode = (JumpInsnNode) node; int destidx = instructions.indexOf(jnode.label); markSubroutineWalkDFS(sub, destidx, anyvisited); } if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) { TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node; int destidx = instructions.indexOf(tsnode.dflt); markSubroutineWalkDFS(sub, destidx, anyvisited); for (int i = tsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) tsnode.labels.get(i); destidx = instructions.indexOf(l); markSubroutineWalkDFS(sub, destidx, anyvisited); } } if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) { LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node; int destidx = instructions.indexOf(lsnode.dflt); markSubroutineWalkDFS(sub, destidx, anyvisited); for (int i = lsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) lsnode.labels.get(i); destidx = instructions.indexOf(l); markSubroutineWalkDFS(sub, destidx, anyvisited); } } // check to see if this opcode falls through to the next instruction // or not; if not, return. switch (instructions.get(index).getOpcode()) { case GOTO: case RET: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: case ATHROW: /* * note: this either returns from this subroutine, or a * parent subroutine which invoked it */ return; } // Use tail recursion here in the form of an outer while loop to // avoid our stack growing needlessly: index++; } } /** * Creates the new instructions, inlining each instantiation of each * subroutine until the code is fully elaborated. */ private void emitCode() { LinkedList worklist = new LinkedList(); // Create an instantiation of the "root" subroutine, which is just the // main routine worklist.add(new Instantiation(null, mainSubroutine)); // Emit instantiations of each subroutine we encounter, including the // main subroutine InsnList newInstructions = new InsnList(); List newTryCatchBlocks = new ArrayList(); List newLocalVariables = new ArrayList(); while (!worklist.isEmpty()) { Instantiation inst = (Instantiation) worklist.removeFirst(); emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks, newLocalVariables); } instructions = newInstructions; tryCatchBlocks = newTryCatchBlocks; localVariables = newLocalVariables; } /** * Emits one instantiation of one subroutine, specified by * instant. May add new instantiations that are invoked by * this one to the worklist parameter, and new try/catch * blocks to newTryCatchBlocks. * * @param instant the instantiation that must be performed. * @param worklist list of the instantiations that remain to be done. * @param newInstructions the instruction list to which the instantiated * code must be appended. * @param newTryCatchBlocks the exception handler list to which the * instantiated handlers must be appended. */ private void emitSubroutine( final Instantiation instant, final List worklist, final InsnList newInstructions, final List newTryCatchBlocks, final List newLocalVariables) { LabelNode duplbl = null; if (LOGGING) { log("--------------------------------------------------------"); log("Emitting instantiation of subroutine " + instant.subroutine); } // Emit the relevant instructions for this instantiation, translating // labels and jump targets as we go: for (int i = 0, c = instructions.size(); i < c; i++) { AbstractInsnNode insn = instructions.get(i); Instantiation owner = instant.findOwner(i); // Always remap labels: if (insn.getType() == AbstractInsnNode.LABEL) { // Translate labels into their renamed equivalents. // Avoid adding the same label more than once. Note // that because we own this instruction the gotoTable // and the rangeTable will always agree. LabelNode ilbl = (LabelNode) insn; LabelNode remap = instant.rangeLabel(ilbl); if (LOGGING) { // TODO use of default toString(). log("Translating lbl #" + i + ':' + ilbl + " to " + remap); } if (remap != duplbl) { newInstructions.add(remap); duplbl = remap; } continue; } // We don't want to emit instructions that were already // emitted by a subroutine higher on the stack. Note that // it is still possible for a given instruction to be // emitted twice because it may belong to two subroutines // that do not invoke each other. if (owner != instant) { continue; } if (LOGGING) { log("Emitting inst #" + i); } if (insn.getOpcode() == RET) { // Translate RET instruction(s) to a jump to the return label // for the appropriate instantiation. The problem is that the // subroutine may "fall through" to the ret of a parent // subroutine; therefore, to find the appropriate ret label we // find the lowest subroutine on the stack that claims to own // this instruction. See the class javadoc comment for an // explanation on why this technique is safe (note: it is only // safe if the input is verifiable). LabelNode retlabel = null; for (Instantiation p = instant; p != null; p = p.previous) { if (p.subroutine.ownsInstruction(i)) { retlabel = p.returnLabel; } } if (retlabel == null) { // This is only possible if the mainSubroutine owns a RET // instruction, which should never happen for verifiable // code. throw new RuntimeException("Instruction #" + i + " is a RET not owned by any subroutine"); } newInstructions.add(new JumpInsnNode(GOTO, retlabel)); } else if (insn.getOpcode() == JSR) { LabelNode lbl = ((JumpInsnNode) insn).label; Subroutine sub = (Subroutine) subroutineHeads.get(lbl); Instantiation newinst = new Instantiation(instant, sub); LabelNode startlbl = newinst.gotoLabel(lbl); if (LOGGING) { log(" Creating instantiation of subr " + sub); } // Rather than JSRing, we will jump to the inline version and // push NULL for what was once the return value. This hack // allows us to avoid doing any sort of data flow analysis to // figure out which instructions manipulate the old return value // pointer which is now known to be unneeded. newInstructions.add(new InsnNode(ACONST_NULL)); newInstructions.add(new JumpInsnNode(GOTO, startlbl)); newInstructions.add(newinst.returnLabel); // Insert this new instantiation into the queue to be emitted // later. worklist.add(newinst); } else { newInstructions.add(insn.clone(instant)); } } // Emit try/catch blocks that are relevant to this method. for (Iterator it = tryCatchBlocks.iterator(); it.hasNext();) { TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next(); if (LOGGING) { // TODO use of default toString(). log("try catch block original labels=" + trycatch.start + '-' + trycatch.end + "->" + trycatch.handler); } final LabelNode start = instant.rangeLabel(trycatch.start); final LabelNode end = instant.rangeLabel(trycatch.end); // Ignore empty try/catch regions if (start == end) { if (LOGGING) { log(" try catch block empty in this subroutine"); } continue; } final LabelNode handler = instant.gotoLabel(trycatch.handler); if (LOGGING) { // TODO use of default toString(). log(" try catch block new labels=" + start + '-' + end + "->" + handler); } if (start == null || end == null || handler == null) { throw new RuntimeException("Internal error!"); } newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, trycatch.type)); } for (Iterator it = localVariables.iterator(); it.hasNext();) { LocalVariableNode lvnode = (LocalVariableNode) it.next(); if (LOGGING) { log("local var " + lvnode.name); } final LabelNode start = instant.rangeLabel(lvnode.start); final LabelNode end = instant.rangeLabel(lvnode.end); if (start == end) { if (LOGGING) { log(" local variable empty in this sub"); } continue; } newLocalVariables.add(new LocalVariableNode(lvnode.name, lvnode.desc, lvnode.signature, start, end, lvnode.index)); } } private static void log(final String str) { System.err.println(str); } protected static class Subroutine { public final BitSet instructions = new BitSet(); public void addInstruction(final int idx) { instructions.set(idx); } public boolean ownsInstruction(final int idx) { return instructions.get(idx); } public String toString() { return "Subroutine: " + instructions; } } /** * A class that represents an instantiation of a subroutine. Each * instantiation has an associate "stack" --- which is a listing of those * instantiations that were active when this particular instance of this * subroutine was invoked. Each instantiation also has a map from the * original labels of the program to the labels appropriate for this * instantiation, and finally a label to return to. */ private class Instantiation extends AbstractMap { /** * Previous instantiations; the stack must be statically predictable to * be inlinable. */ final Instantiation previous; /** * The subroutine this is an instantiation of. */ public final Subroutine subroutine; /** * This table maps Labels from the original source to Labels pointing at * code specific to this instantiation, for use in remapping try/catch * blocks,as well as gotos. * * Note that in the presence of dual citizens instructions, that is, * instructions which belong to more than one subroutine due to the * merging of control flow without a RET instruction, we will map the * target label of a GOTO to the label used by the instantiation lowest * on the stack. This avoids code duplication during inlining in most * cases. * * @see #findOwner(int) */ public final Map rangeTable = new HashMap(); /** * All returns for this instantiation will be mapped to this label */ public final LabelNode returnLabel; Instantiation(final Instantiation prev, final Subroutine sub) { previous = prev; subroutine = sub; for (Instantiation p = prev; p != null; p = p.previous) { if (p.subroutine == sub) { throw new RuntimeException("Recursive invocation of " + sub); } } // Determine the label to return to when this subroutine terminates // via RET: note that the main subroutine never terminates via RET. if (prev != null) { returnLabel = new LabelNode(); } else { returnLabel = null; } // Each instantiation will remap the labels from the code above to // refer to its particular copy of its own instructions. Note that // we collapse labels which point at the same instruction into one: // this is fairly common as we are often ignoring large chunks of // instructions, so what were previously distinct labels become // duplicates. LabelNode duplbl = null; for (int i = 0, c = instructions.size(); i < c; i++) { AbstractInsnNode insn = instructions.get(i); if (insn.getType() == AbstractInsnNode.LABEL) { LabelNode ilbl = (LabelNode) insn; if (duplbl == null) { // if we already have a label pointing at this spot, // don't recreate it. duplbl = new LabelNode(); } // Add an entry in the rangeTable for every label // in the original code which points at the next // instruction of our own to be emitted. rangeTable.put(ilbl, duplbl); } else if (findOwner(i) == this) { // We will emit this instruction, so clear the 'duplbl' flag // since the next Label will refer to a distinct // instruction. duplbl = null; } } } /** * Returns the "owner" of a particular instruction relative to this * instantiation: the owner referes to the Instantiation which will emit * the version of this instruction that we will execute. * * Typically, the return value is either this or * null. this indicates that this * instantiation will generate the version of this instruction that we * will execute, and null indicates that this * instantiation never executes the given instruction. * * Sometimes, however, an instruction can belong to multiple * subroutines; this is called a "dual citizen" instruction (though it * may belong to more than 2 subroutines), and occurs when multiple * subroutines branch to common points of control. In this case, the * owner is the subroutine that appears lowest on the stack, and which * also owns the instruction in question. * * @param i the index of the instruction in the original code * @return the "owner" of a particular instruction relative to this * instantiation. */ public Instantiation findOwner(final int i) { if (!subroutine.ownsInstruction(i)) { return null; } if (!dualCitizens.get(i)) { return this; } Instantiation own = this; for (Instantiation p = previous; p != null; p = p.previous) { if (p.subroutine.ownsInstruction(i)) { own = p; } } return own; } /** * Looks up the label l in the gotoTable, * thus translating it from a Label in the original code, to a Label in * the inlined code that is appropriate for use by an instruction that * branched to the original label. * * @param l The label we will be translating * @return a label for use by a branch instruction in the inlined code * @see #rangeLabel */ public LabelNode gotoLabel(final LabelNode l) { // owner should never be null, because owner is only null // if an instruction cannot be reached from this subroutine Instantiation owner = findOwner(instructions.indexOf(l)); return (LabelNode) owner.rangeTable.get(l); } /** * Looks up the label l in the rangeTable, * thus translating it from a Label in the original code, to a Label in * the inlined code that is appropriate for use by an try/catch or * variable use annotation. * * @param l The label we will be translating * @return a label for use by a try/catch or variable annotation in the * original code * @see #rangeTable */ public LabelNode rangeLabel(final LabelNode l) { return (LabelNode) rangeTable.get(l); } // AbstractMap implementation public Set entrySet() { return null; } public Object get(final Object o) { return gotoLabel((LabelNode) o); } } } asm-3.3.2/src/org/objectweb/asm/commons/CodeSizeEvaluator.java0000644000175000017500000001351111211477631024251 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@link MethodAdapter} that can be used to approximate method size. * * @author Eugene Kuleshov */ public class CodeSizeEvaluator extends MethodAdapter implements Opcodes { private int minSize; private int maxSize; public CodeSizeEvaluator(final MethodVisitor mv) { super(mv); } public int getMinSize() { return this.minSize; } public int getMaxSize() { return this.maxSize; } public void visitInsn(final int opcode) { minSize += 1; maxSize += 1; if (mv != null) { mv.visitInsn(opcode); } } public void visitIntInsn(final int opcode, final int operand) { if (opcode == SIPUSH) { minSize += 3; maxSize += 3; } else { minSize += 2; maxSize += 2; } if (mv != null) { mv.visitIntInsn(opcode, operand); } } public void visitVarInsn(final int opcode, final int var) { if (var < 4 && opcode != RET) { minSize += 1; maxSize += 1; } else if (var >= 256) { minSize += 4; maxSize += 4; } else { minSize += 2; maxSize += 2; } if (mv != null) { mv.visitVarInsn(opcode, var); } } public void visitTypeInsn(final int opcode, final String type) { minSize += 3; maxSize += 3; if (mv != null) { mv.visitTypeInsn(opcode, type); } } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { minSize += 3; maxSize += 3; if (mv != null) { mv.visitFieldInsn(opcode, owner, name, desc); } } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { if (opcode == INVOKEINTERFACE || opcode == INVOKEDYNAMIC) { minSize += 5; maxSize += 5; } else { minSize += 3; maxSize += 3; } if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } } public void visitJumpInsn(final int opcode, final Label label) { minSize += 3; if (opcode == GOTO || opcode == JSR) { maxSize += 5; } else { maxSize += 8; } if (mv != null) { mv.visitJumpInsn(opcode, label); } } public void visitLdcInsn(final Object cst) { if (cst instanceof Long || cst instanceof Double) { minSize += 3; maxSize += 3; } else { minSize += 2; maxSize += 3; } if (mv != null) { mv.visitLdcInsn(cst); } } public void visitIincInsn(final int var, final int increment) { if (var > 255 || increment > 127 || increment < -128) { minSize += 6; maxSize += 6; } else { minSize += 3; maxSize += 3; } if (mv != null) { mv.visitIincInsn(var, increment); } } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { minSize += 13 + labels.length * 4; maxSize += 16 + labels.length * 4; if (mv != null) { mv.visitTableSwitchInsn(min, max, dflt, labels); } } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { minSize += 9 + keys.length * 8; maxSize += 12 + keys.length * 8; if (mv != null) { mv.visitLookupSwitchInsn(dflt, keys, labels); } } public void visitMultiANewArrayInsn(final String desc, final int dims) { minSize += 4; maxSize += 4; if (mv != null) { mv.visitMultiANewArrayInsn(desc, dims); } } } asm-3.3.2/src/org/objectweb/asm/MethodVisitor.java0000644000175000017500000004460211342504140022002 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A visitor to visit a Java method. The methods of this interface must be * called in the following order: [ visitAnnotationDefault ] ( * visitAnnotation | visitParameterAnnotation | * visitAttribute )* [ visitCode ( visitFrame | * visitXInsn | visitLabel | visitTryCatchBlock | * visitLocalVariable | visitLineNumber)* visitMaxs ] * visitEnd. In addition, the visitXInsn * and visitLabel methods must be called in the sequential order of * the bytecode instructions of the visited code, visitTryCatchBlock * must be called before the labels passed as arguments have been * visited, and the visitLocalVariable and visitLineNumber * methods must be called after the labels passed as arguments have been * visited. * * @author Eric Bruneton */ public interface MethodVisitor { // ------------------------------------------------------------------------- // Annotations and non standard attributes // ------------------------------------------------------------------------- /** * Visits the default value of this annotation interface method. * * @return a visitor to the visit the actual default value of this * annotation interface method, or null if this visitor * is not interested in visiting this default value. The 'name' * parameters passed to the methods of this annotation visitor are * ignored. Moreover, exacly one visit method must be called on this * annotation visitor, followed by visitEnd. */ AnnotationVisitor visitAnnotationDefault(); /** * Visits an annotation of this method. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ AnnotationVisitor visitAnnotation(String desc, boolean visible); /** * Visits an annotation of a parameter this method. * * @param parameter the parameter index. * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible); /** * Visits a non standard attribute of this method. * * @param attr an attribute. */ void visitAttribute(Attribute attr); /** * Starts the visit of the method's code, if any (i.e. non abstract method). */ void visitCode(); /** * Visits the current state of the local variables and operand stack * elements. This method must(*) be called just before any * instruction i that follows an unconditional branch instruction * such as GOTO or THROW, that is the target of a jump instruction, or that * starts an exception handler block. The visited types must describe the * values of the local variables and of the operand stack elements just * before i is executed.

(*) this is mandatory only * for classes whose version is greater than or equal to * {@link Opcodes#V1_6 V1_6}.

Packed frames are basically * "deltas" from the state of the previous frame (very first frame is * implicitly defined by the method's parameters and access flags):
    *
  • {@link Opcodes#F_SAME} representing frame with exactly the same * locals as the previous frame and with the empty stack.
  • {@link Opcodes#F_SAME1} * representing frame with exactly the same locals as the previous frame and * with single value on the stack (nStack is 1 and * stack[0] contains value for the type of the stack item).
  • *
  • {@link Opcodes#F_APPEND} representing frame with current locals are * the same as the locals in the previous frame, except that additional * locals are defined (nLocal is 1, 2 or 3 and * local elements contains values representing added types).
  • *
  • {@link Opcodes#F_CHOP} representing frame with current locals are * the same as the locals in the previous frame, except that the last 1-3 * locals are absent and with the empty stack (nLocals is 1, * 2 or 3).
  • {@link Opcodes#F_FULL} representing complete frame * data.
* * @param type the type of this stack map frame. Must be * {@link Opcodes#F_NEW} for expanded frames, or * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed * frames. * @param nLocal the number of local variables in the visited frame. * @param local the local variable types in this frame. This array must not * be modified. Primitive types are represented by * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or * {@link Opcodes#UNINITIALIZED_THIS} (long and double are * represented by a single element). Reference types are represented * by String objects (representing internal names), and uninitialized * types by Label objects (this label designates the NEW instruction * that created this uninitialized value). * @param nStack the number of operand stack elements in the visited frame. * @param stack the operand stack types in this frame. This array must not * be modified. Its content has the same format as the "local" array. * @throw IllegalStateException if a frame is visited just after another * one, without any instruction between the two (unless this frame * is a Opcodes#F_SAME frame, in which case it is silently ignored). */ void visitFrame( int type, int nLocal, Object[] local, int nStack, Object[] stack); // ------------------------------------------------------------------------- // Normal instructions // ------------------------------------------------------------------------- /** * Visits a zero operand instruction. * * @param opcode the opcode of the instruction to be visited. This opcode is * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, * FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, * DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, * DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, * DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, * DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, * LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, * I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, * MONITORENTER, or MONITOREXIT. */ void visitInsn(int opcode); /** * Visits an instruction with a single int operand. * * @param opcode the opcode of the instruction to be visited. This opcode is * either BIPUSH, SIPUSH or NEWARRAY. * @param operand the operand of the instruction to be visited.
When * opcode is BIPUSH, operand value should be between Byte.MIN_VALUE * and Byte.MAX_VALUE.
When opcode is SIPUSH, operand value * should be between Short.MIN_VALUE and Short.MAX_VALUE.
When * opcode is NEWARRAY, operand value should be one of * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ void visitIntInsn(int opcode, int operand); /** * Visits a local variable instruction. A local variable instruction is an * instruction that loads or stores the value of a local variable. * * @param opcode the opcode of the local variable instruction to be visited. * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, * LSTORE, FSTORE, DSTORE, ASTORE or RET. * @param var the operand of the instruction to be visited. This operand is * the index of a local variable. */ void visitVarInsn(int opcode, int var); /** * Visits a type instruction. A type instruction is an instruction that * takes the internal name of a class as parameter. * * @param opcode the opcode of the type instruction to be visited. This * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. * @param type the operand of the instruction to be visited. This operand * must be the internal name of an object or array class (see {@link * Type#getInternalName() getInternalName}). */ void visitTypeInsn(int opcode, String type); /** * 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, * INVOKEINTERFACE or INVOKEDYNAMIC. * @param owner the internal name of the method's owner class (see {@link * Type#getInternalName() getInternalName}) * or {@link org.objectweb.asm.Opcodes#INVOKEDYNAMIC_OWNER}. * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). */ void visitMethodInsn(int opcode, String owner, String name, String desc); /** * Visits a jump instruction. A jump instruction is an instruction that may * jump to another instruction. * * @param opcode the opcode of the type instruction to be visited. This * opcode is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. * @param label the operand of the instruction to be visited. This operand * is a label that designates the instruction to which the jump * instruction may jump. */ void visitJumpInsn(int opcode, Label label); /** * Visits a label. A label designates the instruction that will be visited * just after it. * * @param label a {@link Label Label} object. */ void visitLabel(Label label); // ------------------------------------------------------------------------- // Special instructions // ------------------------------------------------------------------------- /** * Visits a LDC instruction. * * @param cst the constant to be loaded on the stack. This parameter must be * a non null {@link Integer}, a {@link Float}, a {@link Long}, a * {@link Double} a {@link String} (or a {@link Type} for * .class constants, for classes whose version is 49.0 or * more). */ void visitLdcInsn(Object cst); /** * Visits an IINC instruction. * * @param var index of the local variable to be incremented. * @param increment amount to increment the local variable by. */ void visitIincInsn(int var, int increment); /** * Visits a TABLESWITCH instruction. * * @param min the minimum key value. * @param max the maximum key value. * @param dflt beginning of the default handler block. * @param labels beginnings of the handler blocks. 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, debug information, max stack 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 already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ void visitTryCatchBlock(Label start, Label end, Label handler, String type); /** * Visits a local variable declaration. * * @param name the name of a local variable. * @param desc the type descriptor of this local variable. * @param signature the type signature of this local variable. May be * null if the local variable type does not use generic * types. * @param start the first instruction corresponding to the scope of this * local variable (inclusive). * @param end the last instruction corresponding to the scope of this local * variable (exclusive). * @param index the local variable's index. * @throws IllegalArgumentException if one of the labels has not already * been visited by this visitor (by the * {@link #visitLabel visitLabel} method). */ void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index); /** * Visits a line number declaration. * * @param line a line number. This number refers to the source file from * which the class was compiled. * @param start the first instruction corresponding to this line number. * @throws IllegalArgumentException if start has not already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ void visitLineNumber(int line, Label start); /** * Visits the maximum stack size and the maximum number of local variables * of the method. * * @param maxStack maximum stack size of the method. * @param maxLocals maximum number of local variables for the method. */ void visitMaxs(int maxStack, int maxLocals); /** * Visits the end of the method. This method, which is the last one to be * called, is used to inform the visitor that all the annotations and * attributes of the method have been visited. */ void visitEnd(); } asm-3.3.2/src/org/objectweb/asm/Label.java0000644000175000017500000005315211302220175020220 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * 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. A label * designates the instruction that is just after. Note however that * there can be other elements between a label and the instruction it * designates (such as other labels, stack map frames, line numbers, etc.). * * @author Eric Bruneton */ public class Label { /** * Indicates if this label is only used for debug attributes. Such a label * is not the start of a basic block, the target of a jump instruction, or * an exception handler. It can be safely ignored in control flow graph * analysis algorithms (for optimization purposes). */ static final int DEBUG = 1; /** * Indicates if the position of this label is known. */ static final int RESOLVED = 2; /** * Indicates if this label has been updated, after instruction resizing. */ static final int RESIZED = 4; /** * Indicates if this basic block has been pushed in the basic block stack. * See {@link MethodWriter#visitMaxs visitMaxs}. */ static final int PUSHED = 8; /** * Indicates if this label is the target of a jump instruction, or the start * of an exception handler. */ static final int TARGET = 16; /** * Indicates if a stack map frame must be stored for this label. */ static final int STORE = 32; /** * Indicates if this label corresponds to a reachable basic block. */ static final int REACHABLE = 64; /** * Indicates if this basic block ends with a JSR instruction. */ static final int JSR = 128; /** * Indicates if this basic block ends with a RET instruction. */ static final int RET = 256; /** * Indicates if this basic block is the start of a subroutine. */ static final int SUBROUTINE = 512; /** * Indicates if this subroutine basic block has been visited by a * visitSubroutine(null, ...) call. */ static final int VISITED = 1024; /** * Indicates if this subroutine basic block has been visited by a * visitSubroutine(!null, ...) call. */ static final int VISITED2 = 2048; /** * Field used to associate user information to a label. Warning: this field * is used by the ASM tree package. In order to use it with the ASM tree * package you must override the {@link * org.objectweb.asm.tree.MethodNode#getLabelNode} method. */ public Object info; /** * Flags that indicate the status of this label. * * @see #DEBUG * @see #RESOLVED * @see #RESIZED * @see #PUSHED * @see #TARGET * @see #STORE * @see #REACHABLE * @see #JSR * @see #RET */ int status; /** * The line number corresponding to this label, if known. */ int line; /** * 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. This array is also used * as a bitset to store the subroutines to which a basic block belongs. This * information is needed in {@linked MethodWriter#visitMaxs}, after all * forward references have been resolved. Hence the same array can be used * for both purposes without problems. */ private int[] srcAndRefPositions; // ------------------------------------------------------------------------ /* * Fields for the control flow and data flow graph analysis algorithms (used * to compute the maximum stack size or the stack map frames). 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. * * The control flow analysis algorithms used to compute the maximum stack * size or the stack map frames are similar and use two steps. The first * step, during the visit of each instruction, builds information about the * state of the local variables and the operand stack at the end of each * basic block, called the "output frame", relatively to the frame * state at the beginning of the basic block, which is called the "input * frame", and which is unknown during this step. The second step, * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that * computes information about the input frame of each basic block, from the * input state of the first basic block (known from the method signature), * and by the using the previously computed relative output frames. * * The algorithm used to compute the maximum stack size only computes the * relative output and absolute input stack heights, while the algorithm * used to compute stack map frames computes relative output frames and * absolute input frames. */ /** * Start of the output stack relatively to the input stack. The exact * semantics of this field depends on the algorithm that is used. * * When only the maximum stack size is computed, this field is the number of * elements in the input stack. * * When the stack map frames are completely computed, this field is the * offset of the first output stack element relatively to the top of the * input stack. This offset is always negative or null. A null offset means * that the output stack must be appended to the input stack. A -n offset * means that the first n output stack elements must replace the top n input * stack elements, and that the other elements must be appended to the input * stack. */ int inputStackTop; /** * Maximum height reached by the output stack, relatively to the top of the * input stack. This maximum is always positive or null. */ int outputStackMax; /** * Information about the input and output stack map frames of this basic * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES} * option is used. */ Frame frame; /** * The successor of this label, in the order they are visited. This linked * list does not include labels used for debug info only. If * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it * does not contain successive labels that denote the same bytecode position * (in this case only the first label appears in this list). */ Label successor; /** * 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. This stack is used in the * main loop of the fix point algorithm used in the second step of the * control flow analysis algorithms. It is also used in * {@link #visitSubroutine} to avoid using a recursive method. * * @see MethodWriter#visitMaxs */ Label next; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructs a new label. */ public Label() { } // ------------------------------------------------------------------------ // Methods to compute offsets and to manage forward references // ------------------------------------------------------------------------ /** * Returns the offset corresponding to this label. This offset is computed * from the start of the method's bytecode. This method is intended for * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters. * * @return the offset corresponding to this label. * @throws IllegalStateException if this label is not resolved yet. */ public int getOffset() { if ((status & RESOLVED) == 0) { throw new IllegalStateException("Label offset position has not been resolved yet"); } return position; } /** * Puts a reference to this label in the bytecode of a method. If the * position of the label is known, the offset is computed and written * directly. Otherwise, a null offset is written and a new forward reference * is declared for this label. * * @param owner the code writer that calls this method. * @param out the bytecode of the method. * @param source the position of first byte of the bytecode instruction that * contains this label. * @param wideOffset 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 MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) { if ((status & RESOLVED) == 0) { if (wideOffset) { addReference(-1 - source, out.length); out.putInt(-1); } else { addReference(source, out.length); out.putShort(-1); } } else { if (wideOffset) { out.putInt(position - source); } else { out.putShort(position - source); } } } /** * 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 MethodWriter#resizeInstructions}. * @throws IllegalArgumentException if this label has already been resolved, * or if it has not been created by the given code writer. */ boolean resolve( final MethodWriter owner, final int position, final byte[] data) { boolean needUpdate = false; this.status |= RESOLVED; this.position = position; int i = 0; while (i < referenceCount) { int source = srcAndRefPositions[i++]; int reference = srcAndRefPositions[i++]; int offset; if (source >= 0) { offset = position - source; if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { /* * changes the opcode of the jump instruction, in order to * be able to find it later (see resizeInstructions in * MethodWriter). These temporary opcodes are similar to * jump instruction opcodes, except that the 2 bytes offset * is unsigned (and can therefore represent values from 0 to * 65535, which is sufficient since the size of a method is * limited to 65535 bytes). */ int opcode = data[reference - 1] & 0xFF; if (opcode <= Opcodes.JSR) { // changes IFEQ ... JSR to opcodes 202 to 217 data[reference - 1] = (byte) (opcode + 49); } else { // changes IFNULL and IFNONNULL to opcodes 218 and 219 data[reference - 1] = (byte) (opcode + 20); } needUpdate = true; } data[reference++] = (byte) (offset >>> 8); data[reference] = (byte) offset; } else { offset = position + source + 1; data[reference++] = (byte) (offset >>> 24); data[reference++] = (byte) (offset >>> 16); data[reference++] = (byte) (offset >>> 8); data[reference] = (byte) offset; } } return needUpdate; } /** * Returns the first label of the series to which this label belongs. For an * isolated label or for the first label in a series of successive labels, * this method returns the label itself. For other labels it returns the * first label of the series. * * @return the first label of the series to which this label belongs. */ Label getFirst() { return !ClassReader.FRAMES || frame == null ? this : frame.owner; } // ------------------------------------------------------------------------ // Methods related to subroutines // ------------------------------------------------------------------------ /** * Returns true is this basic block belongs to the given subroutine. * * @param id a subroutine id. * @return true is this basic block belongs to the given subroutine. */ boolean inSubroutine(final long id) { if ((status & Label.VISITED) != 0) { return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; } return false; } /** * Returns true if this basic block and the given one belong to a common * subroutine. * * @param block another basic block. * @return true if this basic block and the given one belong to a common * subroutine. */ boolean inSameSubroutine(final Label block) { if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { return false; } for (int i = 0; i < srcAndRefPositions.length; ++i) { if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { return true; } } return false; } /** * Marks this basic block as belonging to the given subroutine. * * @param id a subroutine id. * @param nbSubroutines the total number of subroutines in the method. */ void addToSubroutine(final long id, final int nbSubroutines) { if ((status & VISITED) == 0) { status |= VISITED; srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1]; } srcAndRefPositions[(int) (id >>> 32)] |= (int) id; } /** * Finds the basic blocks that belong to a given subroutine, and marks these * blocks as belonging to this subroutine. This method follows the control * flow graph to find all the blocks that are reachable from the current * block WITHOUT following any JSR target. * * @param JSR a JSR block that jumps to this subroutine. If this JSR is not * null it is added to the successor of the RET blocks found in the * subroutine. * @param id the id of this subroutine. * @param nbSubroutines the total number of subroutines in the method. */ void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { // user managed stack of labels, to avoid using a recursive method // (recursivity can lead to stack overflow with very large methods) Label stack = this; while (stack != null) { // removes a label l from the stack Label l = stack; stack = l.next; l.next = null; if (JSR != null) { if ((l.status & VISITED2) != 0) { continue; } l.status |= VISITED2; // adds JSR to the successors of l, if it is a RET block if ((l.status & RET) != 0) { if (!l.inSameSubroutine(JSR)) { Edge e = new Edge(); e.info = l.inputStackTop; e.successor = JSR.successors.successor; e.next = l.successors; l.successors = e; } } } else { // if the l block already belongs to subroutine 'id', continue if (l.inSubroutine(id)) { continue; } // marks the l block as belonging to subroutine 'id' l.addToSubroutine(id, nbSubroutines); } // pushes each successor of l on the stack, except JSR targets Edge e = l.successors; while (e != null) { // if the l block is a JSR block, then 'l.successors.next' leads // to the JSR target (see {@link #visitJumpInsn}) and must // therefore not be followed if ((l.status & Label.JSR) == 0 || e != l.successors.next) { // pushes e.successor on the stack if it not already added if (e.successor.next == null) { e.successor.next = stack; stack = e.successor; } } e = e.next; } } } // ------------------------------------------------------------------------ // Overriden Object methods // ------------------------------------------------------------------------ /** * Returns a string representation of this label. * * @return a string representation of this label. */ public String toString() { return "L" + System.identityHashCode(this); } } asm-3.3.2/src/org/objectweb/asm/Edge.java0000644000175000017500000000614210701747173020060 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * An edge in the control flow graph of a method body. See {@link Label Label}. * * @author Eric Bruneton */ class Edge { /** * Denotes a normal control flow graph edge. */ static final int NORMAL = 0; /** * Denotes a control flow graph edge corresponding to an exception handler. * More precisely any {@link Edge} whose {@link #info} is strictly positive * corresponds to an exception handler. The actual value of {@link #info} is * the index, in the {@link ClassWriter} type table, of the exception that * is catched. */ static final int EXCEPTION = 0x7FFFFFFF; /** * Information about this control flow graph edge. If * {@link ClassWriter#COMPUTE_MAXS} is used this field is 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. If {@link ClassWriter#COMPUTE_FRAMES} is used, * this field is the kind of this control flow graph edge (i.e. NORMAL or * EXCEPTION). */ int info; /** * 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; } asm-3.3.2/src/org/objectweb/asm/ClassVisitor.java0000644000175000017500000002074710635277351021652 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A visitor to visit a Java class. The methods of this interface must be called * in the following order: visit [ visitSource ] [ * visitOuterClass ] ( visitAnnotation | * visitAttribute )* (visitInnerClass | * visitField | visitMethod )* visitEnd. * * @author Eric Bruneton */ public interface ClassVisitor { /** * Visits the header of the class. * * @param version the class version. * @param access the class's access flags (see {@link Opcodes}). This * parameter also indicates if the class is deprecated. * @param name the internal name of the class (see * {@link Type#getInternalName() getInternalName}). * @param signature the signature of this class. May be null if * the class is not a generic one, and does not extend or implement * generic classes or interfaces. * @param superName the internal of name of the super class (see * {@link Type#getInternalName() getInternalName}). For interfaces, * the super class is {@link Object}. May be null, but * only for the {@link Object} class. * @param interfaces the internal names of the class's interfaces (see * {@link Type#getInternalName() getInternalName}). May be * null. */ void visit( int version, int access, String name, String signature, String superName, String[] interfaces); /** * Visits the source of the class. * * @param source the name of the source file from which the class was * compiled. May be null. * @param debug additional debug information to compute the correspondance * between source and compiled elements of the class. May be * null. */ void visitSource(String source, String debug); /** * Visits the enclosing class of the class. This method must be called only * if the class has an enclosing class. * * @param owner internal name of the enclosing class of the class. * @param name the name of the method that contains the class, or * null if the class is not enclosed in a method of its * enclosing class. * @param desc the descriptor of the method that contains the class, or * null if the class is not enclosed in a method of its * enclosing class. */ void visitOuterClass(String owner, String name, String desc); /** * Visits an annotation of the class. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ AnnotationVisitor visitAnnotation(String desc, boolean visible); /** * Visits a non standard attribute of the class. * * @param attr an attribute. */ void visitAttribute(Attribute attr); /** * Visits information about an inner class. This inner class is not * necessarily a member of the class being visited. * * @param name the internal name of an inner class (see * {@link Type#getInternalName() getInternalName}). * @param outerName the internal name of the class to which the inner class * belongs (see {@link Type#getInternalName() getInternalName}). May * be null for not member classes. * @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 Opcodes}). This * parameter also indicates if the field is synthetic and/or * deprecated. * @param name the field's name. * @param desc the field's descriptor (see {@link Type Type}). * @param signature the field's signature. May be null if the * field's type does not use generic types. * @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 Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String} (for int, * float, long or String fields * respectively). This parameter is only used for static fields. * Its value is ignored for non static fields, which must be * initialized through bytecode instructions in constructors or * methods. * @return a visitor to visit field annotations and attributes, or * null if this class visitor is not interested in * visiting these annotations and attributes. */ FieldVisitor visitField( int access, String name, String desc, String signature, Object value); /** * Visits a method of the class. This method must return a new * {@link MethodVisitor} 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 Opcodes}). This * parameter also indicates if the method is synthetic and/or * deprecated. * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param signature the method's signature. May be null if the * method parameters, return type and exceptions do not use generic * types. * @param exceptions the internal names of the method's exception classes * (see {@link Type#getInternalName() getInternalName}). May be * 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. */ MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions); /** * Visits the end of the class. This method, which is the last one to be * called, is used to inform the visitor that all the fields and methods of * the class have been visited. */ void visitEnd(); } asm-3.3.2/src/org/objectweb/asm/xml/0000755000175000017500000000000011633370220017134 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/xml/SAXFieldAdapter.java0000644000175000017500000000453610701747173022721 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; /** * SAXFieldAdapter * * @author Eugene Kuleshov */ public class SAXFieldAdapter extends SAXAdapter implements FieldVisitor { public SAXFieldAdapter(final ContentHandler h, final Attributes att) { super(h); addStart("field", att); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return new SAXAnnotationAdapter(getContentHandler(), "annotation", visible ? 1 : -1, null, desc); } public void visitEnd() { addEnd("field"); } } asm-3.3.2/src/org/objectweb/asm/xml/SAXClassAdapter.java0000644000175000017500000002705610701747173022745 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.xml.sax.ContentHandler; import org.xml.sax.helpers.AttributesImpl; /** * A {@link org.objectweb.asm.ClassVisitor ClassVisitor} that generates SAX 2.0 * events from the visited class. It can feed any kind of * {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT * or XQuery engines. * * @see org.objectweb.asm.xml.Processor * @see org.objectweb.asm.xml.ASMContentHandler * * @author Eugene Kuleshov */ public final class SAXClassAdapter extends SAXAdapter implements ClassVisitor { private final boolean singleDocument; /** * Pseudo access flag used to distinguish class access flags. */ private static final int ACCESS_CLASS = 262144; /** * Pseudo access flag used to distinguish field access flags. */ private static final int ACCESS_FIELD = 524288; /** * Pseudo access flag used to distinguish inner class flags. */ private static final int ACCESS_INNER = 1048576; /** * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object. * * @param h content handler that will be used to send SAX 2.0 events. * @param singleDocument if true adapter will not produce * {@link ContentHandler#startDocument() startDocument()} and * {@link ContentHandler#endDocument() endDocument()} events. */ public SAXClassAdapter(final ContentHandler h, boolean singleDocument) { super(h); this.singleDocument = singleDocument; if (!singleDocument) { addDocumentStart(); } } public void visitSource(final String source, final String debug) { AttributesImpl att = new AttributesImpl(); if (source != null) { att.addAttribute("", "file", "file", "", encode(source)); } if (debug != null) { att.addAttribute("", "debug", "debug", "", encode(debug)); } addElement("source", att); } public void visitOuterClass( final String owner, final String name, final String desc) { AttributesImpl att = new AttributesImpl(); att.addAttribute("", "owner", "owner", "", owner); if (name != null) { att.addAttribute("", "name", "name", "", name); } if (desc != null) { att.addAttribute("", "desc", "desc", "", desc); } addElement("outerclass", att); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return new SAXAnnotationAdapter(getContentHandler(), "annotation", visible ? 1 : -1, null, desc); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { StringBuffer sb = new StringBuffer(); appendAccess(access | ACCESS_CLASS, sb); AttributesImpl att = new AttributesImpl(); att.addAttribute("", "access", "access", "", sb.toString()); if (name != null) { att.addAttribute("", "name", "name", "", name); } if (signature != null) { att.addAttribute("", "signature", "signature", "", encode(signature)); } if (superName != null) { att.addAttribute("", "parent", "parent", "", superName); } att.addAttribute("", "major", "major", "", Integer.toString(version & 0xFFFF)); att.addAttribute("", "minor", "minor", "", Integer.toString(version >>> 16)); addStart("class", att); addStart("interfaces", new AttributesImpl()); if (interfaces != null && interfaces.length > 0) { for (int i = 0; i < interfaces.length; i++) { AttributesImpl att2 = new AttributesImpl(); att2.addAttribute("", "name", "name", "", interfaces[i]); addElement("interface", att2); } } addEnd("interfaces"); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { StringBuffer sb = new StringBuffer(); appendAccess(access | ACCESS_FIELD, sb); AttributesImpl att = new AttributesImpl(); att.addAttribute("", "access", "access", "", sb.toString()); att.addAttribute("", "name", "name", "", name); att.addAttribute("", "desc", "desc", "", desc); if (signature != null) { att.addAttribute("", "signature", "signature", "", encode(signature)); } if (value != null) { att.addAttribute("", "value", "value", "", encode(value.toString())); } return new SAXFieldAdapter(getContentHandler(), att); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { StringBuffer sb = new StringBuffer(); appendAccess(access, sb); AttributesImpl att = new AttributesImpl(); att.addAttribute("", "access", "access", "", sb.toString()); att.addAttribute("", "name", "name", "", name); att.addAttribute("", "desc", "desc", "", desc); if (signature != null) { att.addAttribute("", "signature", "signature", "", signature); } addStart("method", att); addStart("exceptions", new AttributesImpl()); if (exceptions != null && exceptions.length > 0) { for (int i = 0; i < exceptions.length; i++) { AttributesImpl att2 = new AttributesImpl(); att2.addAttribute("", "name", "name", "", exceptions[i]); addElement("exception", att2); } } addEnd("exceptions"); return new SAXCodeAdapter(getContentHandler(), access); } public final void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { StringBuffer sb = new StringBuffer(); appendAccess(access | ACCESS_INNER, sb); AttributesImpl att = new AttributesImpl(); att.addAttribute("", "access", "access", "", sb.toString()); if (name != null) { att.addAttribute("", "name", "name", "", name); } if (outerName != null) { att.addAttribute("", "outerName", "outerName", "", outerName); } if (innerName != null) { att.addAttribute("", "innerName", "innerName", "", innerName); } addElement("innerclass", att); } public final void visitEnd() { addEnd("class"); if (!singleDocument) { addDocumentEnd(); } } static final String encode(final String s) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '\\') { sb.append("\\\\"); } else if (c < 0x20 || c > 0x7f) { sb.append("\\u"); if (c < 0x10) { sb.append("000"); } else if (c < 0x100) { sb.append("00"); } else if (c < 0x1000) { sb.append('0'); } sb.append(Integer.toString(c, 16)); } else { sb.append(c); } } return sb.toString(); } static void appendAccess(final int access, final StringBuffer sb) { if ((access & Opcodes.ACC_PUBLIC) != 0) { sb.append("public "); } if ((access & Opcodes.ACC_PRIVATE) != 0) { sb.append("private "); } if ((access & Opcodes.ACC_PROTECTED) != 0) { sb.append("protected "); } if ((access & Opcodes.ACC_FINAL) != 0) { sb.append("final "); } if ((access & Opcodes.ACC_STATIC) != 0) { sb.append("static "); } if ((access & Opcodes.ACC_SUPER) != 0) { if ((access & ACCESS_CLASS) == 0) { sb.append("synchronized "); } else { sb.append("super "); } } if ((access & Opcodes.ACC_VOLATILE) != 0) { if ((access & ACCESS_FIELD) == 0) { sb.append("bridge "); } else { sb.append("volatile "); } } if ((access & Opcodes.ACC_TRANSIENT) != 0) { if ((access & ACCESS_FIELD) == 0) { sb.append("varargs "); } else { sb.append("transient "); } } if ((access & Opcodes.ACC_NATIVE) != 0) { sb.append("native "); } if ((access & Opcodes.ACC_STRICT) != 0) { sb.append("strict "); } if ((access & Opcodes.ACC_INTERFACE) != 0) { sb.append("interface "); } if ((access & Opcodes.ACC_ABSTRACT) != 0) { sb.append("abstract "); } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { sb.append("synthetic "); } if ((access & Opcodes.ACC_ANNOTATION) != 0) { sb.append("annotation "); } if ((access & Opcodes.ACC_ENUM) != 0) { sb.append("enum "); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { sb.append("deprecated "); } } } asm-3.3.2/src/org/objectweb/asm/xml/SAXCodeAdapter.java0000644000175000017500000003350111211477631022536 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.util.HashMap; import java.util.Map; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.util.AbstractVisitor; import org.xml.sax.ContentHandler; import org.xml.sax.helpers.AttributesImpl; /** * A {@link MethodVisitor} that generates SAX 2.0 events from the visited * method. * * @see org.objectweb.asm.xml.SAXClassAdapter * @see org.objectweb.asm.xml.Processor * * @author Eugene Kuleshov */ public final class SAXCodeAdapter extends SAXAdapter implements MethodVisitor { static final String[] TYPES = { "top", "int", "float", "double", "long", "null", "uninitializedThis" }; private final Map labelNames; /** * Constructs a new {@link SAXCodeAdapter SAXCodeAdapter} object. * * @param h content handler that will be used to send SAX 2.0 events. */ public SAXCodeAdapter(final ContentHandler h, final int access) { super(h); labelNames = new HashMap(); if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) { addStart("code", new AttributesImpl()); } } public final void visitCode() { } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { AttributesImpl attrs = new AttributesImpl(); switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: if (type == Opcodes.F_NEW) { attrs.addAttribute("", "type", "type", "", "NEW"); } else { attrs.addAttribute("", "type", "type", "", "FULL"); } addStart("frame", attrs); appendFrameTypes(true, nLocal, local); appendFrameTypes(false, nStack, stack); break; case Opcodes.F_APPEND: attrs.addAttribute("", "type", "type", "", "APPEND"); addStart("frame", attrs); appendFrameTypes(true, nLocal, local); break; case Opcodes.F_CHOP: attrs.addAttribute("", "type", "type", "", "CHOP"); attrs.addAttribute("", "count", "count", "", Integer.toString(nLocal)); addStart("frame", attrs); break; case Opcodes.F_SAME: attrs.addAttribute("", "type", "type", "", "SAME"); addStart("frame", attrs); break; case Opcodes.F_SAME1: attrs.addAttribute("", "type", "type", "", "SAME1"); addStart("frame", attrs); appendFrameTypes(false, 1, stack); break; } addEnd("frame"); } private void appendFrameTypes( final boolean local, final int n, final Object[] types) { for (int i = 0; i < n; ++i) { Object type = types[i]; AttributesImpl attrs = new AttributesImpl(); if (type instanceof String) { attrs.addAttribute("", "type", "type", "", (String) type); } else if (type instanceof Integer) { attrs.addAttribute("", "type", "type", "", TYPES[((Integer) type).intValue()]); } else { attrs.addAttribute("", "type", "type", "", "uninitialized"); attrs.addAttribute("", "label", "label", "", getLabel((Label) type)); } addElement(local ? "local" : "stack", attrs); } } public final void visitInsn(final int opcode) { addElement(AbstractVisitor.OPCODES[opcode], new AttributesImpl()); } public final void visitIntInsn(final int opcode, final int operand) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "value", "value", "", Integer.toString(operand)); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitVarInsn(final int opcode, final int var) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "var", "var", "", Integer.toString(var)); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitTypeInsn(final int opcode, final String type) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "desc", "desc", "", type); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "owner", "owner", "", owner); attrs.addAttribute("", "name", "name", "", name); attrs.addAttribute("", "desc", "desc", "", desc); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { AttributesImpl attrs = new AttributesImpl(); if (opcode != Opcodes.INVOKEDYNAMIC) { attrs.addAttribute("", "owner", "owner", "", owner); } attrs.addAttribute("", "name", "name", "", name); attrs.addAttribute("", "desc", "desc", "", desc); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitJumpInsn(final int opcode, final Label label) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "label", "label", "", getLabel(label)); addElement(AbstractVisitor.OPCODES[opcode], attrs); } public final void visitLabel(final Label label) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "name", "name", "", getLabel(label)); addElement("Label", attrs); } public final void visitLdcInsn(final Object cst) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "cst", "cst", "", SAXClassAdapter.encode(cst.toString())); attrs.addAttribute("", "desc", "desc", "", Type.getDescriptor(cst.getClass())); addElement(AbstractVisitor.OPCODES[Opcodes.LDC], attrs); } public final void visitIincInsn(final int var, final int increment) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "var", "var", "", Integer.toString(var)); attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment)); addElement(AbstractVisitor.OPCODES[Opcodes.IINC], attrs); } public final void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "min", "min", "", Integer.toString(min)); attrs.addAttribute("", "max", "max", "", Integer.toString(max)); attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt)); String o = AbstractVisitor.OPCODES[Opcodes.TABLESWITCH]; addStart(o, attrs); for (int i = 0; i < labels.length; i++) { AttributesImpl att2 = new AttributesImpl(); att2.addAttribute("", "name", "name", "", getLabel(labels[i])); addElement("label", att2); } addEnd(o); } public final void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { AttributesImpl att = new AttributesImpl(); att.addAttribute("", "dflt", "dflt", "", getLabel(dflt)); String o = AbstractVisitor.OPCODES[Opcodes.LOOKUPSWITCH]; addStart(o, att); for (int i = 0; i < labels.length; i++) { AttributesImpl att2 = new AttributesImpl(); att2.addAttribute("", "name", "name", "", getLabel(labels[i])); att2.addAttribute("", "key", "key", "", Integer.toString(keys[i])); addElement("label", att2); } addEnd(o); } public final void visitMultiANewArrayInsn(final String desc, final int dims) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "desc", "desc", "", desc); attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims)); addElement(AbstractVisitor.OPCODES[Opcodes.MULTIANEWARRAY], attrs); } public final void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "start", "start", "", getLabel(start)); attrs.addAttribute("", "end", "end", "", getLabel(end)); attrs.addAttribute("", "handler", "handler", "", getLabel(handler)); if (type != null) { attrs.addAttribute("", "type", "type", "", type); } addElement("TryCatch", attrs); } public final void visitMaxs(final int maxStack, final int maxLocals) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "maxStack", "maxStack", "", Integer.toString(maxStack)); attrs.addAttribute("", "maxLocals", "maxLocals", "", Integer.toString(maxLocals)); addElement("Max", attrs); addEnd("code"); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "name", "name", "", name); attrs.addAttribute("", "desc", "desc", "", desc); if (signature != null) { attrs.addAttribute("", "signature", "signature", "", SAXClassAdapter.encode(signature)); } attrs.addAttribute("", "start", "start", "", getLabel(start)); attrs.addAttribute("", "end", "end", "", getLabel(end)); attrs.addAttribute("", "var", "var", "", Integer.toString(index)); addElement("LocalVar", attrs); } public final void visitLineNumber(final int line, final Label start) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "line", "line", "", Integer.toString(line)); attrs.addAttribute("", "start", "start", "", getLabel(start)); addElement("LineNumber", attrs); } public AnnotationVisitor visitAnnotationDefault() { return new SAXAnnotationAdapter(getContentHandler(), "annotationDefault", 0, null, null); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return new SAXAnnotationAdapter(getContentHandler(), "annotation", visible ? 1 : -1, null, desc); } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { return new SAXAnnotationAdapter(getContentHandler(), "parameterAnnotation", visible ? 1 : -1, parameter, desc); } public void visitEnd() { addEnd("method"); } private final String getLabel(final Label label) { String name = (String) labelNames.get(label); if (name == null) { name = Integer.toString(labelNames.size()); labelNames.put(label, name); } return name; } } asm-3.3.2/src/org/objectweb/asm/xml/package.html0000644000175000017500000000651510135753312021427 0ustar twernertwerner Provides SAX 2.0 adapters for ASM visitors to convert classes to and from XML. These adapters can be chained with other SAX compliant content handlers and filters, eg. XSLT or XQuery engines. This package is bundled as a separate asm-xml.jar library and requires asm.jar.

ASMContentHandler and SAXClassAdapter/SAXCodeAdapter are using asm-xml.dtd. Here is the example of bytecode to bytecode XSLT transformation.

    SAXTransformerFactory saxtf = ( SAXTransformerFactory) TransformerFactory.newInstance();
    Templates templates = saxtf.newTemplates( xsltSource);

    TransformerHandler handler = saxtf.newTransformerHandler( templates);
    handler.setResult( new SAXResult( new ASMContentHandler( outputStream, computeMax)));

    ClassReader cr = new ClassReader( bytecode);
    cr.accept( new SAXClassAdapter( handler, cr.getVersion(), false), false);
See JAXP and SAX documentation for more detils.

There are few illustrations of the bytecode transformation with XSLT in examples directory. The following XSLT procesors has been tested.

Engine javax.xml.transform.TransformerFactory property
jd.xslt jd.xml.xslt.trax.TransformerFactoryImpl
Saxon net.sf.saxon.TransformerFactoryImpl
Caucho com.caucho.xsl.Xsl
Xalan interpeter org.apache.xalan.processor.TransformerFactory
Xalan xsltc org.apache.xalan.xsltc.trax.TransformerFactoryImpl
@since ASM 1.4.3 asm-3.3.2/src/org/objectweb/asm/xml/ASMContentHandler.java0000644000175000017500000013503611302174156023263 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * A {@link org.xml.sax.ContentHandler ContentHandler} that transforms XML * document into Java class file. This class can be feeded by any kind of SAX * 2.0 event producers, e.g. XML parser, XSLT or XPath engines, or custom code. * * @see org.objectweb.asm.xml.SAXClassAdapter * @see org.objectweb.asm.xml.Processor * * @author Eugene Kuleshov */ public class ASMContentHandler extends DefaultHandler implements Opcodes { /** * Stack of the intermediate processing contexts. */ private final List stack = new ArrayList(); /** * Complete name of the current element. */ String match = ""; /** * true if the maximum stack size and number of local variables * must be automatically computed. */ protected boolean computeMax; /** * Output stream to write result bytecode. */ protected OutputStream os; /** * Current instance of the {@link ClassWriter ClassWriter} used to write * class bytecode. */ protected ClassWriter cw; /** * Map of the active {@link Label Label} instances for current method. */ protected Map labels; private static final String BASE = "class"; private final RuleSet RULES = new RuleSet(); { RULES.add(BASE, new ClassRule()); RULES.add(BASE + "/interfaces/interface", new InterfaceRule()); RULES.add(BASE + "/interfaces", new InterfacesRule()); RULES.add(BASE + "/outerclass", new OuterClassRule()); RULES.add(BASE + "/innerclass", new InnerClassRule()); RULES.add(BASE + "/source", new SourceRule()); RULES.add(BASE + "/field", new FieldRule()); RULES.add(BASE + "/method", new MethodRule()); RULES.add(BASE + "/method/exceptions/exception", new ExceptionRule()); RULES.add(BASE + "/method/exceptions", new ExceptionsRule()); RULES.add(BASE + "/method/annotationDefault", new AnnotationDefaultRule()); RULES.add(BASE + "/method/code/*", new OpcodesRule()); // opcodes RULES.add(BASE + "/method/code/frame", new FrameRule()); RULES.add(BASE + "/method/code/frame/local", new FrameTypeRule()); RULES.add(BASE + "/method/code/frame/stack", new FrameTypeRule()); RULES.add(BASE + "/method/code/TABLESWITCH", new TableSwitchRule()); RULES.add(BASE + "/method/code/TABLESWITCH/label", new TableSwitchLabelRule()); RULES.add(BASE + "/method/code/LOOKUPSWITCH", new LookupSwitchRule()); RULES.add(BASE + "/method/code/LOOKUPSWITCH/label", new LookupSwitchLabelRule()); RULES.add(BASE + "/method/code/Label", new LabelRule()); RULES.add(BASE + "/method/code/TryCatch", new TryCatchRule()); RULES.add(BASE + "/method/code/LineNumber", new LineNumberRule()); RULES.add(BASE + "/method/code/LocalVar", new LocalVarRule()); RULES.add(BASE + "/method/code/Max", new MaxRule()); RULES.add("*/annotation", new AnnotationRule()); RULES.add("*/parameterAnnotation", new AnnotationParameterRule()); RULES.add("*/annotationValue", new AnnotationValueRule()); RULES.add("*/annotationValueAnnotation", new AnnotationValueAnnotationRule()); RULES.add("*/annotationValueEnum", new AnnotationValueEnumRule()); RULES.add("*/annotationValueArray", new AnnotationValueArrayRule()); } private static interface OpcodeGroup { public static final int INSN = 0; public static final int INSN_INT = 1; public static final int INSN_VAR = 2; public static final int INSN_TYPE = 3; public static final int INSN_FIELD = 4; public static final int INSN_METHOD = 5; public static final int INSN_JUMP = 6; public static final int INSN_LDC = 7; public static final int INSN_IINC = 8; public static final int INSN_MULTIANEWARRAY = 9; } /** * Map of the opcode names to opcode and opcode group */ static final Map OPCODES = new HashMap(); static { addOpcode("NOP", NOP, OpcodeGroup.INSN); addOpcode("ACONST_NULL", ACONST_NULL, OpcodeGroup.INSN); addOpcode("ICONST_M1", ICONST_M1, OpcodeGroup.INSN); addOpcode("ICONST_0", ICONST_0, OpcodeGroup.INSN); addOpcode("ICONST_1", ICONST_1, OpcodeGroup.INSN); addOpcode("ICONST_2", ICONST_2, OpcodeGroup.INSN); addOpcode("ICONST_3", ICONST_3, OpcodeGroup.INSN); addOpcode("ICONST_4", ICONST_4, OpcodeGroup.INSN); addOpcode("ICONST_5", ICONST_5, OpcodeGroup.INSN); addOpcode("LCONST_0", LCONST_0, OpcodeGroup.INSN); addOpcode("LCONST_1", LCONST_1, OpcodeGroup.INSN); addOpcode("FCONST_0", FCONST_0, OpcodeGroup.INSN); addOpcode("FCONST_1", FCONST_1, OpcodeGroup.INSN); addOpcode("FCONST_2", FCONST_2, OpcodeGroup.INSN); addOpcode("DCONST_0", DCONST_0, OpcodeGroup.INSN); addOpcode("DCONST_1", DCONST_1, OpcodeGroup.INSN); addOpcode("BIPUSH", BIPUSH, OpcodeGroup.INSN_INT); addOpcode("SIPUSH", SIPUSH, OpcodeGroup.INSN_INT); addOpcode("LDC", LDC, OpcodeGroup.INSN_LDC); addOpcode("ILOAD", ILOAD, OpcodeGroup.INSN_VAR); addOpcode("LLOAD", LLOAD, OpcodeGroup.INSN_VAR); addOpcode("FLOAD", FLOAD, OpcodeGroup.INSN_VAR); addOpcode("DLOAD", DLOAD, OpcodeGroup.INSN_VAR); addOpcode("ALOAD", ALOAD, OpcodeGroup.INSN_VAR); addOpcode("IALOAD", IALOAD, OpcodeGroup.INSN); addOpcode("LALOAD", LALOAD, OpcodeGroup.INSN); addOpcode("FALOAD", FALOAD, OpcodeGroup.INSN); addOpcode("DALOAD", DALOAD, OpcodeGroup.INSN); addOpcode("AALOAD", AALOAD, OpcodeGroup.INSN); addOpcode("BALOAD", BALOAD, OpcodeGroup.INSN); addOpcode("CALOAD", CALOAD, OpcodeGroup.INSN); addOpcode("SALOAD", SALOAD, OpcodeGroup.INSN); addOpcode("ISTORE", ISTORE, OpcodeGroup.INSN_VAR); addOpcode("LSTORE", LSTORE, OpcodeGroup.INSN_VAR); addOpcode("FSTORE", FSTORE, OpcodeGroup.INSN_VAR); addOpcode("DSTORE", DSTORE, OpcodeGroup.INSN_VAR); addOpcode("ASTORE", ASTORE, OpcodeGroup.INSN_VAR); addOpcode("IASTORE", IASTORE, OpcodeGroup.INSN); addOpcode("LASTORE", LASTORE, OpcodeGroup.INSN); addOpcode("FASTORE", FASTORE, OpcodeGroup.INSN); addOpcode("DASTORE", DASTORE, OpcodeGroup.INSN); addOpcode("AASTORE", AASTORE, OpcodeGroup.INSN); addOpcode("BASTORE", BASTORE, OpcodeGroup.INSN); addOpcode("CASTORE", CASTORE, OpcodeGroup.INSN); addOpcode("SASTORE", SASTORE, OpcodeGroup.INSN); addOpcode("POP", POP, OpcodeGroup.INSN); addOpcode("POP2", POP2, OpcodeGroup.INSN); addOpcode("DUP", DUP, OpcodeGroup.INSN); addOpcode("DUP_X1", DUP_X1, OpcodeGroup.INSN); addOpcode("DUP_X2", DUP_X2, OpcodeGroup.INSN); addOpcode("DUP2", DUP2, OpcodeGroup.INSN); addOpcode("DUP2_X1", DUP2_X1, OpcodeGroup.INSN); addOpcode("DUP2_X2", DUP2_X2, OpcodeGroup.INSN); addOpcode("SWAP", SWAP, OpcodeGroup.INSN); addOpcode("IADD", IADD, OpcodeGroup.INSN); addOpcode("LADD", LADD, OpcodeGroup.INSN); addOpcode("FADD", FADD, OpcodeGroup.INSN); addOpcode("DADD", DADD, OpcodeGroup.INSN); addOpcode("ISUB", ISUB, OpcodeGroup.INSN); addOpcode("LSUB", LSUB, OpcodeGroup.INSN); addOpcode("FSUB", FSUB, OpcodeGroup.INSN); addOpcode("DSUB", DSUB, OpcodeGroup.INSN); addOpcode("IMUL", IMUL, OpcodeGroup.INSN); addOpcode("LMUL", LMUL, OpcodeGroup.INSN); addOpcode("FMUL", FMUL, OpcodeGroup.INSN); addOpcode("DMUL", DMUL, OpcodeGroup.INSN); addOpcode("IDIV", IDIV, OpcodeGroup.INSN); addOpcode("LDIV", LDIV, OpcodeGroup.INSN); addOpcode("FDIV", FDIV, OpcodeGroup.INSN); addOpcode("DDIV", DDIV, OpcodeGroup.INSN); addOpcode("IREM", IREM, OpcodeGroup.INSN); addOpcode("LREM", LREM, OpcodeGroup.INSN); addOpcode("FREM", FREM, OpcodeGroup.INSN); addOpcode("DREM", DREM, OpcodeGroup.INSN); addOpcode("INEG", INEG, OpcodeGroup.INSN); addOpcode("LNEG", LNEG, OpcodeGroup.INSN); addOpcode("FNEG", FNEG, OpcodeGroup.INSN); addOpcode("DNEG", DNEG, OpcodeGroup.INSN); addOpcode("ISHL", ISHL, OpcodeGroup.INSN); addOpcode("LSHL", LSHL, OpcodeGroup.INSN); addOpcode("ISHR", ISHR, OpcodeGroup.INSN); addOpcode("LSHR", LSHR, OpcodeGroup.INSN); addOpcode("IUSHR", IUSHR, OpcodeGroup.INSN); addOpcode("LUSHR", LUSHR, OpcodeGroup.INSN); addOpcode("IAND", IAND, OpcodeGroup.INSN); addOpcode("LAND", LAND, OpcodeGroup.INSN); addOpcode("IOR", IOR, OpcodeGroup.INSN); addOpcode("LOR", LOR, OpcodeGroup.INSN); addOpcode("IXOR", IXOR, OpcodeGroup.INSN); addOpcode("LXOR", LXOR, OpcodeGroup.INSN); addOpcode("IINC", IINC, OpcodeGroup.INSN_IINC); addOpcode("I2L", I2L, OpcodeGroup.INSN); addOpcode("I2F", I2F, OpcodeGroup.INSN); addOpcode("I2D", I2D, OpcodeGroup.INSN); addOpcode("L2I", L2I, OpcodeGroup.INSN); addOpcode("L2F", L2F, OpcodeGroup.INSN); addOpcode("L2D", L2D, OpcodeGroup.INSN); addOpcode("F2I", F2I, OpcodeGroup.INSN); addOpcode("F2L", F2L, OpcodeGroup.INSN); addOpcode("F2D", F2D, OpcodeGroup.INSN); addOpcode("D2I", D2I, OpcodeGroup.INSN); addOpcode("D2L", D2L, OpcodeGroup.INSN); addOpcode("D2F", D2F, OpcodeGroup.INSN); addOpcode("I2B", I2B, OpcodeGroup.INSN); addOpcode("I2C", I2C, OpcodeGroup.INSN); addOpcode("I2S", I2S, OpcodeGroup.INSN); addOpcode("LCMP", LCMP, OpcodeGroup.INSN); addOpcode("FCMPL", FCMPL, OpcodeGroup.INSN); addOpcode("FCMPG", FCMPG, OpcodeGroup.INSN); addOpcode("DCMPL", DCMPL, OpcodeGroup.INSN); addOpcode("DCMPG", DCMPG, OpcodeGroup.INSN); addOpcode("IFEQ", IFEQ, OpcodeGroup.INSN_JUMP); addOpcode("IFNE", IFNE, OpcodeGroup.INSN_JUMP); addOpcode("IFLT", IFLT, OpcodeGroup.INSN_JUMP); addOpcode("IFGE", IFGE, OpcodeGroup.INSN_JUMP); addOpcode("IFGT", IFGT, OpcodeGroup.INSN_JUMP); addOpcode("IFLE", IFLE, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPEQ", IF_ICMPEQ, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPNE", IF_ICMPNE, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPLT", IF_ICMPLT, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPGE", IF_ICMPGE, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPGT", IF_ICMPGT, OpcodeGroup.INSN_JUMP); addOpcode("IF_ICMPLE", IF_ICMPLE, OpcodeGroup.INSN_JUMP); addOpcode("IF_ACMPEQ", IF_ACMPEQ, OpcodeGroup.INSN_JUMP); addOpcode("IF_ACMPNE", IF_ACMPNE, OpcodeGroup.INSN_JUMP); addOpcode("GOTO", GOTO, OpcodeGroup.INSN_JUMP); addOpcode("JSR", JSR, OpcodeGroup.INSN_JUMP); addOpcode("RET", RET, OpcodeGroup.INSN_VAR); addOpcode("IRETURN", IRETURN, OpcodeGroup.INSN); addOpcode("LRETURN", LRETURN, OpcodeGroup.INSN); addOpcode("FRETURN", FRETURN, OpcodeGroup.INSN); addOpcode("DRETURN", DRETURN, OpcodeGroup.INSN); addOpcode("ARETURN", ARETURN, OpcodeGroup.INSN); addOpcode("RETURN", RETURN, OpcodeGroup.INSN); addOpcode("GETSTATIC", GETSTATIC, OpcodeGroup.INSN_FIELD); addOpcode("PUTSTATIC", PUTSTATIC, OpcodeGroup.INSN_FIELD); addOpcode("GETFIELD", GETFIELD, OpcodeGroup.INSN_FIELD); addOpcode("PUTFIELD", PUTFIELD, OpcodeGroup.INSN_FIELD); addOpcode("INVOKEVIRTUAL", INVOKEVIRTUAL, OpcodeGroup.INSN_METHOD); addOpcode("INVOKESPECIAL", INVOKESPECIAL, OpcodeGroup.INSN_METHOD); addOpcode("INVOKESTATIC", INVOKESTATIC, OpcodeGroup.INSN_METHOD); addOpcode("INVOKEINTERFACE", INVOKEINTERFACE, OpcodeGroup.INSN_METHOD); addOpcode("INVOKEDYNAMIC", INVOKEDYNAMIC, OpcodeGroup.INSN_METHOD); addOpcode("NEW", NEW, OpcodeGroup.INSN_TYPE); addOpcode("NEWARRAY", NEWARRAY, OpcodeGroup.INSN_INT); addOpcode("ANEWARRAY", ANEWARRAY, OpcodeGroup.INSN_TYPE); addOpcode("ARRAYLENGTH", ARRAYLENGTH, OpcodeGroup.INSN); addOpcode("ATHROW", ATHROW, OpcodeGroup.INSN); addOpcode("CHECKCAST", CHECKCAST, OpcodeGroup.INSN_TYPE); addOpcode("INSTANCEOF", INSTANCEOF, OpcodeGroup.INSN_TYPE); addOpcode("MONITORENTER", MONITORENTER, OpcodeGroup.INSN); addOpcode("MONITOREXIT", MONITOREXIT, OpcodeGroup.INSN); addOpcode("MULTIANEWARRAY", MULTIANEWARRAY, OpcodeGroup.INSN_MULTIANEWARRAY); addOpcode("IFNULL", IFNULL, OpcodeGroup.INSN_JUMP); addOpcode("IFNONNULL", IFNONNULL, OpcodeGroup.INSN_JUMP); } private static void addOpcode(String operStr, int oper, int group) { OPCODES.put(operStr, new Opcode(oper, group)); } static final Map TYPES = new HashMap(); static { String[] types = SAXCodeAdapter.TYPES; for (int i = 0; i < types.length; i++) { TYPES.put(types[i], new Integer(i)); } } /** * Constructs a new {@link ASMContentHandler ASMContentHandler} object. * * @param os output stream to write generated class. * @param computeMax true if the maximum stack size and the * maximum number of local variables must be automatically computed. * This value is passed to {@link ClassWriter ClassWriter} instance. */ public ASMContentHandler(final OutputStream os, final boolean computeMax) { this.os = os; this.computeMax = computeMax; } /** * Returns the bytecode of the class that was build with underneath class * writer. * * @return the bytecode of the class that was build with underneath class * writer or null if there are no classwriter created. */ public byte[] toByteArray() { return cw == null ? null : cw.toByteArray(); } /** * Process notification of the start of an XML element being reached. * * @param ns - The Namespace URI, or the empty string if the element has no * Namespace URI or if Namespace processing is not being performed. * @param lName - The local name (without prefix), or the empty string if * Namespace processing is not being performed. * @param qName - The qualified name (with prefix), or the empty string if * qualified names are not available. * @param list - The attributes attached to the element. If there are no * attributes, it shall be an empty Attributes object. * @exception SAXException if a parsing error is to be reported */ public final void startElement( final String ns, final String lName, final String qName, final Attributes list) throws SAXException { // the actual element name is either in lName or qName, depending // on whether the parser is namespace aware String name = lName == null || lName.length() == 0 ? qName : lName; // Compute the current matching rule StringBuffer sb = new StringBuffer(match); if (match.length() > 0) { sb.append('/'); } sb.append(name); match = sb.toString(); // Fire "begin" events for all relevant rules Rule r = (Rule) RULES.match(match); if (r != null) { r.begin(name, list); } } /** * Process notification of the end of an XML element being reached. * * @param ns - The Namespace URI, or the empty string if the element has no * Namespace URI or if Namespace processing is not being performed. * @param lName - The local name (without prefix), or the empty string if * Namespace processing is not being performed. * @param qName - The qualified XML 1.0 name (with prefix), or the empty * string if qualified names are not available. * * @exception SAXException if a parsing error is to be reported */ public final void endElement( final String ns, final String lName, final String qName) throws SAXException { // the actual element name is either in lName or qName, depending // on whether the parser is namespace aware String name = lName == null || lName.length() == 0 ? qName : lName; // Fire "end" events for all relevant rules in reverse order Rule r = (Rule) RULES.match(match); if (r != null) { r.end(name); } // Recover the previous match expression int slash = match.lastIndexOf('/'); if (slash >= 0) { match = match.substring(0, slash); } else { match = ""; } } /** * Process notification of the end of a document and write generated * bytecode into output stream. * * @exception SAXException if parsing or writing error is to be reported. */ public final void endDocument() throws SAXException { try { os.write(toByteArray()); } catch (IOException ex) { throw new SAXException(ex.toString(), ex); } } /** * Return the top object on the stack without removing it. If there are no * objects on the stack, return null. * * @return the top object on the stack without removing it. */ final Object peek() { int size = stack.size(); return size == 0 ? null : stack.get(size - 1); } /** * Pop the top object off of the stack, and return it. If there are no * objects on the stack, return null. * * @return the top object off of the stack. */ final Object pop() { int size = stack.size(); return size == 0 ? null : stack.remove(size - 1); } /** * Push a new object onto the top of the object stack. * * @param object The new object */ final void push(final Object object) { stack.add(object); } static final class RuleSet { private final Map rules = new HashMap(); private final List lpatterns = new ArrayList(); private final List rpatterns = new ArrayList(); public void add(final String path, final Object rule) { String pattern = path; if (path.startsWith("*/")) { pattern = path.substring(1); lpatterns.add(pattern); } else if (path.endsWith("/*")) { pattern = path.substring(0, path.length() - 1); rpatterns.add(pattern); } rules.put(pattern, rule); } public Object match(final String path) { if (rules.containsKey(path)) { return rules.get(path); } int n = path.lastIndexOf('/'); for (Iterator it = lpatterns.iterator(); it.hasNext();) { String pattern = (String) it.next(); if (path.substring(n).endsWith(pattern)) { return rules.get(pattern); } } for (Iterator it = rpatterns.iterator(); it.hasNext();) { String pattern = (String) it.next(); if (path.startsWith(pattern)) { return rules.get(pattern); } } return null; } } /** * Rule */ protected abstract class Rule { public void begin(final String name, final Attributes attrs) throws SAXException { } public void end(final String name) { } protected final Object getValue(final String desc, final String val) throws SAXException { Object value = null; if (val != null) { if ("Ljava/lang/String;".equals(desc)) { value = decode(val); } else if ("Ljava/lang/Integer;".equals(desc) || "I".equals(desc) || "S".equals(desc) || "B".equals(desc) || "C".equals(desc) || "Z".equals(desc)) { value = new Integer(val); } else if ("Ljava/lang/Short;".equals(desc)) { value = new Short(val); } else if ("Ljava/lang/Byte;".equals(desc)) { value = new Byte(val); } else if ("Ljava/lang/Character;".equals(desc)) { value = new Character(decode(val).charAt(0)); } else if ("Ljava/lang/Boolean;".equals(desc)) { value = Boolean.valueOf(val); } else if ("Ljava/lang/Long;".equals(desc) || "J".equals(desc)) { value = new Long(val); } else if ("Ljava/lang/Float;".equals(desc) || "F".equals(desc)) { value = new Float(val); } else if ("Ljava/lang/Double;".equals(desc) || "D".equals(desc)) { value = new Double(val); } else if (Type.getDescriptor(Type.class).equals(desc)) { value = Type.getType(val); } else { // TODO use of default toString(). throw new SAXException("Invalid value:" + val + " desc:" + desc + " ctx:" + this); } } return value; } private final String decode(final String val) throws SAXException { StringBuffer sb = new StringBuffer(val.length()); try { int n = 0; while (n < val.length()) { char c = val.charAt(n); if (c == '\\') { n++; c = val.charAt(n); if (c == '\\') { sb.append('\\'); } else { n++; // skip 'u' sb.append((char) Integer.parseInt(val.substring(n, n + 4), 16)); n += 3; } } else { sb.append(c); } n++; } } catch (RuntimeException ex) { throw new SAXException(ex); } return sb.toString(); } protected final Label getLabel(final Object label) { Label lbl = (Label) labels.get(label); if (lbl == null) { lbl = new Label(); labels.put(label, lbl); } return lbl; } // TODO verify move to stack protected final MethodVisitor getCodeVisitor() { return (MethodVisitor) peek(); } protected final int getAccess(final String s) { int access = 0; if (s.indexOf("public") != -1) { access |= ACC_PUBLIC; } if (s.indexOf("private") != -1) { access |= ACC_PRIVATE; } if (s.indexOf("protected") != -1) { access |= ACC_PROTECTED; } if (s.indexOf("static") != -1) { access |= ACC_STATIC; } if (s.indexOf("final") != -1) { access |= ACC_FINAL; } if (s.indexOf("super") != -1) { access |= ACC_SUPER; } if (s.indexOf("synchronized") != -1) { access |= ACC_SYNCHRONIZED; } if (s.indexOf("volatile") != -1) { access |= ACC_VOLATILE; } if (s.indexOf("bridge") != -1) { access |= ACC_BRIDGE; } if (s.indexOf("varargs") != -1) { access |= ACC_VARARGS; } if (s.indexOf("transient") != -1) { access |= ACC_TRANSIENT; } if (s.indexOf("native") != -1) { access |= ACC_NATIVE; } if (s.indexOf("interface") != -1) { access |= ACC_INTERFACE; } if (s.indexOf("abstract") != -1) { access |= ACC_ABSTRACT; } if (s.indexOf("strict") != -1) { access |= ACC_STRICT; } if (s.indexOf("synthetic") != -1) { access |= ACC_SYNTHETIC; } if (s.indexOf("annotation") != -1) { access |= ACC_ANNOTATION; } if (s.indexOf("enum") != -1) { access |= ACC_ENUM; } if (s.indexOf("deprecated") != -1) { access |= ACC_DEPRECATED; } return access; } } /** * ClassRule */ final class ClassRule extends Rule { public final void begin(final String name, final Attributes attrs) { int major = Integer.parseInt(attrs.getValue("major")); int minor = Integer.parseInt(attrs.getValue("minor")); cw = new ClassWriter(computeMax ? ClassWriter.COMPUTE_MAXS : 0); Map vals = new HashMap(); vals.put("version", new Integer(minor << 16 | major)); vals.put("access", attrs.getValue("access")); vals.put("name", attrs.getValue("name")); vals.put("parent", attrs.getValue("parent")); vals.put("source", attrs.getValue("source")); vals.put("signature", attrs.getValue("signature")); vals.put("interfaces", new ArrayList()); push(vals); // values will be extracted in InterfacesRule.end(); } } final class SourceRule extends Rule { public void begin(final String name, final Attributes attrs) { String file = attrs.getValue("file"); String debug = attrs.getValue("debug"); cw.visitSource(file, debug); } } /** * InterfaceRule */ final class InterfaceRule extends Rule { public final void begin(final String name, final Attributes attrs) { ((List) ((HashMap) peek()).get("interfaces")).add(attrs.getValue("name")); } } /** * InterfacesRule */ final class InterfacesRule extends Rule { public final void end(final String element) { Map vals = (Map) pop(); int version = ((Integer) vals.get("version")).intValue(); int access = getAccess((String) vals.get("access")); String name = (String) vals.get("name"); String signature = (String) vals.get("signature"); String parent = (String) vals.get("parent"); List infs = (List) vals.get("interfaces"); String[] interfaces = (String[]) infs.toArray(new String[infs.size()]); cw.visit(version, access, name, signature, parent, interfaces); push(cw); } } /** * OuterClassRule */ final class OuterClassRule extends Rule { public final void begin(final String element, final Attributes attrs) { String owner = attrs.getValue("owner"); String name = attrs.getValue("name"); String desc = attrs.getValue("desc"); cw.visitOuterClass(owner, name, desc); } } /** * InnerClassRule */ final class InnerClassRule extends Rule { public final void begin(final String element, final Attributes attrs) { int access = getAccess(attrs.getValue("access")); String name = attrs.getValue("name"); String outerName = attrs.getValue("outerName"); String innerName = attrs.getValue("innerName"); cw.visitInnerClass(name, outerName, innerName, access); } } /** * FieldRule */ final class FieldRule extends Rule { public final void begin(final String element, final Attributes attrs) throws SAXException { int access = getAccess(attrs.getValue("access")); String name = attrs.getValue("name"); String signature = attrs.getValue("signature"); String desc = attrs.getValue("desc"); Object value = getValue(desc, attrs.getValue("value")); push(cw.visitField(access, name, desc, signature, value)); } public void end(final String name) { ((FieldVisitor) pop()).visitEnd(); } } /** * MethodRule */ final class MethodRule extends Rule { public final void begin(final String name, final Attributes attrs) { labels = new HashMap(); Map vals = new HashMap(); vals.put("access", attrs.getValue("access")); vals.put("name", attrs.getValue("name")); vals.put("desc", attrs.getValue("desc")); vals.put("signature", attrs.getValue("signature")); vals.put("exceptions", new ArrayList()); push(vals); // values will be extracted in ExceptionsRule.end(); } public final void end(final String name) { ((MethodVisitor) pop()).visitEnd(); labels = null; } } /** * ExceptionRule */ final class ExceptionRule extends Rule { public final void begin(final String name, final Attributes attrs) { ((List) ((HashMap) peek()).get("exceptions")).add(attrs.getValue("name")); } } /** * ExceptionsRule */ final class ExceptionsRule extends Rule { public final void end(final String element) { Map vals = (Map) pop(); int access = getAccess((String) vals.get("access")); String name = (String) vals.get("name"); String desc = (String) vals.get("desc"); String signature = (String) vals.get("signature"); List excs = (List) vals.get("exceptions"); String[] exceptions = (String[]) excs.toArray(new String[excs.size()]); push(cw.visitMethod(access, name, desc, signature, exceptions)); } } /** * TableSwitchRule */ class TableSwitchRule extends Rule { public final void begin(final String name, final Attributes attrs) { Map vals = new HashMap(); vals.put("min", attrs.getValue("min")); vals.put("max", attrs.getValue("max")); vals.put("dflt", attrs.getValue("dflt")); vals.put("labels", new ArrayList()); push(vals); } public final void end(final String name) { Map vals = (Map) pop(); int min = Integer.parseInt((String) vals.get("min")); int max = Integer.parseInt((String) vals.get("max")); Label dflt = getLabel(vals.get("dflt")); List lbls = (List) vals.get("labels"); Label[] labels = (Label[]) lbls.toArray(new Label[lbls.size()]); getCodeVisitor().visitTableSwitchInsn(min, max, dflt, labels); } } /** * TableSwitchLabelRule */ final class TableSwitchLabelRule extends Rule { public final void begin(final String name, final Attributes attrs) { ((List) ((HashMap) peek()).get("labels")).add(getLabel(attrs.getValue("name"))); } } /** * LookupSwitchRule */ final class LookupSwitchRule extends Rule { public final void begin(final String name, final Attributes attrs) { Map vals = new HashMap(); vals.put("dflt", attrs.getValue("dflt")); vals.put("labels", new ArrayList()); vals.put("keys", new ArrayList()); push(vals); } public final void end(final String name) { Map vals = (Map) pop(); Label dflt = getLabel(vals.get("dflt")); List keyList = (List) vals.get("keys"); List lbls = (List) vals.get("labels"); Label[] labels = (Label[]) lbls.toArray(new Label[lbls.size()]); int[] keys = new int[keyList.size()]; for (int i = 0; i < keys.length; i++) { keys[i] = Integer.parseInt((String) keyList.get(i)); } getCodeVisitor().visitLookupSwitchInsn(dflt, keys, labels); } } /** * LookupSwitchLabelRule */ final class LookupSwitchLabelRule extends Rule { public final void begin(final String name, final Attributes attrs) { Map vals = (Map) peek(); ((List) vals.get("labels")).add(getLabel(attrs.getValue("name"))); ((List) vals.get("keys")).add(attrs.getValue("key")); } } /** * FrameRule */ final class FrameRule extends Rule { public void begin(final String name, final Attributes attrs) { Map typeLists = new HashMap(); typeLists.put("local", new ArrayList()); typeLists.put("stack", new ArrayList()); push(attrs.getValue("type")); push(attrs.getValue("count") == null ? "0" : attrs.getValue("count")); push(typeLists); } public void end(final String name) { Map typeLists = (Map) pop(); List locals = (List) typeLists.get("local"); int nLocal = locals.size(); Object[] local = locals.toArray(); List stacks = (List) typeLists.get("stack"); int nStack = stacks.size(); Object[] stack = stacks.toArray(); String count = (String) pop(); String type = (String) pop(); if ("NEW".equals(type)) { getCodeVisitor().visitFrame(F_NEW, nLocal, local, nStack, stack); } else if ("FULL".equals(type)) { getCodeVisitor().visitFrame(F_FULL, nLocal, local, nStack, stack); } else if ("APPEND".equals(type)) { getCodeVisitor().visitFrame(F_APPEND, nLocal, local, 0, null); } else if ("CHOP".equals(type)) { getCodeVisitor().visitFrame(F_CHOP, Integer.parseInt(count), null, 0, null); } else if ("SAME".equals(type)) { getCodeVisitor().visitFrame(F_SAME, 0, null, 0, null); } else if ("SAME1".equals(type)) { getCodeVisitor().visitFrame(F_SAME1, 0, null, nStack, stack); } } } final class FrameTypeRule extends Rule { public void begin(final String name, final Attributes attrs) { List types = (List) ((HashMap) peek()).get(name); String type = attrs.getValue("type"); if ("uninitialized".equals(type)) { types.add(getLabel(attrs.getValue("label"))); } else { Integer t = (Integer) TYPES.get(type); if (t == null) { types.add(type); } else { types.add(t); } } } } /** * LabelRule */ final class LabelRule extends Rule { public final void begin(final String name, final Attributes attrs) { getCodeVisitor().visitLabel(getLabel(attrs.getValue("name"))); } } /** * TryCatchRule */ final class TryCatchRule extends Rule { public final void begin(final String name, final Attributes attrs) { Label start = getLabel(attrs.getValue("start")); Label end = getLabel(attrs.getValue("end")); Label handler = getLabel(attrs.getValue("handler")); String type = attrs.getValue("type"); getCodeVisitor().visitTryCatchBlock(start, end, handler, type); } } /** * LineNumberRule */ final class LineNumberRule extends Rule { public final void begin(final String name, final Attributes attrs) { int line = Integer.parseInt(attrs.getValue("line")); Label start = getLabel(attrs.getValue("start")); getCodeVisitor().visitLineNumber(line, start); } } /** * LocalVarRule */ final class LocalVarRule extends Rule { public final void begin(final String element, final Attributes attrs) { String name = attrs.getValue("name"); String desc = attrs.getValue("desc"); String signature = attrs.getValue("signature"); Label start = getLabel(attrs.getValue("start")); Label end = getLabel(attrs.getValue("end")); int var = Integer.parseInt(attrs.getValue("var")); getCodeVisitor().visitLocalVariable(name, desc, signature, start, end, var); } } /** * OpcodesRule */ final class OpcodesRule extends Rule { // public boolean match( String match, String element) { // return match.startsWith( path) && OPCODES.containsKey( element); // } public final void begin(final String element, final Attributes attrs) throws SAXException { Opcode o = (Opcode) OPCODES.get(element); if (o == null) { throw new SAXException("Invalid element: " + element + " at " + match); } switch (o.type) { case OpcodeGroup.INSN: getCodeVisitor().visitInsn(o.opcode); break; case OpcodeGroup.INSN_FIELD: getCodeVisitor().visitFieldInsn(o.opcode, attrs.getValue("owner"), attrs.getValue("name"), attrs.getValue("desc")); break; case OpcodeGroup.INSN_INT: getCodeVisitor().visitIntInsn(o.opcode, Integer.parseInt(attrs.getValue("value"))); break; case OpcodeGroup.INSN_JUMP: getCodeVisitor().visitJumpInsn(o.opcode, getLabel(attrs.getValue("label"))); break; case OpcodeGroup.INSN_METHOD: getCodeVisitor().visitMethodInsn(o.opcode, (o.opcode != Opcodes.INVOKEDYNAMIC)? attrs.getValue("owner"): Opcodes.INVOKEDYNAMIC_OWNER, attrs.getValue("name"), attrs.getValue("desc")); break; case OpcodeGroup.INSN_TYPE: getCodeVisitor().visitTypeInsn(o.opcode, attrs.getValue("desc")); break; case OpcodeGroup.INSN_VAR: getCodeVisitor().visitVarInsn(o.opcode, Integer.parseInt(attrs.getValue("var"))); break; case OpcodeGroup.INSN_IINC: getCodeVisitor().visitIincInsn(Integer.parseInt(attrs.getValue("var")), Integer.parseInt(attrs.getValue("inc"))); break; case OpcodeGroup.INSN_LDC: getCodeVisitor().visitLdcInsn(getValue(attrs.getValue("desc"), attrs.getValue("cst"))); break; case OpcodeGroup.INSN_MULTIANEWARRAY: getCodeVisitor().visitMultiANewArrayInsn(attrs.getValue("desc"), Integer.parseInt(attrs.getValue("dims"))); break; default: throw new Error("Internal error"); } } } /** * MaxRule */ final class MaxRule extends Rule { public final void begin(final String element, final Attributes attrs) { int maxStack = Integer.parseInt(attrs.getValue("maxStack")); int maxLocals = Integer.parseInt(attrs.getValue("maxLocals")); getCodeVisitor().visitMaxs(maxStack, maxLocals); } } final class AnnotationRule extends Rule { public void begin(final String name, final Attributes attrs) { String desc = attrs.getValue("desc"); boolean visible = Boolean.valueOf(attrs.getValue("visible")) .booleanValue(); Object v = peek(); if (v instanceof ClassVisitor) { push(((ClassVisitor) v).visitAnnotation(desc, visible)); } else if (v instanceof FieldVisitor) { push(((FieldVisitor) v).visitAnnotation(desc, visible)); } else if (v instanceof MethodVisitor) { push(((MethodVisitor) v).visitAnnotation(desc, visible)); } } public void end(final String name) { AnnotationVisitor av = (AnnotationVisitor) pop(); if (av != null) { av.visitEnd(); } } } final class AnnotationParameterRule extends Rule { public void begin(final String name, final Attributes attrs) { int parameter = Integer.parseInt(attrs.getValue("parameter")); String desc = attrs.getValue("desc"); boolean visible = Boolean.valueOf(attrs.getValue("visible")) .booleanValue(); push(((MethodVisitor) peek()).visitParameterAnnotation(parameter, desc, visible)); } public void end(final String name) { AnnotationVisitor av = (AnnotationVisitor) pop(); if (av != null) { av.visitEnd(); } } } final class AnnotationValueRule extends Rule { public void begin(final String nm, final Attributes attrs) throws SAXException { AnnotationVisitor av = (AnnotationVisitor) peek(); if (av != null) { av.visit(attrs.getValue("name"), getValue(attrs.getValue("desc"), attrs.getValue("value"))); } } } final class AnnotationValueEnumRule extends Rule { public void begin(final String nm, final Attributes attrs) { AnnotationVisitor av = (AnnotationVisitor) peek(); if (av != null) { av.visitEnum(attrs.getValue("name"), attrs.getValue("desc"), attrs.getValue("value")); } } } final class AnnotationValueAnnotationRule extends Rule { public void begin(final String nm, final Attributes attrs) { AnnotationVisitor av = (AnnotationVisitor) peek(); push(av == null ? null : av.visitAnnotation(attrs.getValue("name"), attrs.getValue("desc"))); } public void end(final String name) { AnnotationVisitor av = (AnnotationVisitor) pop(); if (av != null) { av.visitEnd(); } } } final class AnnotationValueArrayRule extends Rule { public void begin(final String nm, final Attributes attrs) { AnnotationVisitor av = (AnnotationVisitor) peek(); push(av == null ? null : av.visitArray(attrs.getValue("name"))); } public void end(final String name) { AnnotationVisitor av = (AnnotationVisitor) pop(); if (av != null) { av.visitEnd(); } } } final class AnnotationDefaultRule extends Rule { public void begin(final String nm, final Attributes attrs) { MethodVisitor av = (MethodVisitor) peek(); push(av == null ? null : av.visitAnnotationDefault()); } public void end(final String name) { AnnotationVisitor av = (AnnotationVisitor) pop(); if (av != null) { av.visitEnd(); } } } /** * Opcode */ static final class Opcode { public final int opcode; public final int type; Opcode(final int opcode, final int type) { this.opcode = opcode; this.type = type; } } } asm-3.3.2/src/org/objectweb/asm/xml/SAXAdapter.java0000644000175000017500000000607610701747173021756 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import org.objectweb.asm.Attribute; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; /** * SAXAdapter * * @author Eugene Kuleshov */ public abstract class SAXAdapter { private final ContentHandler h; protected SAXAdapter(final ContentHandler h) { this.h = h; } protected ContentHandler getContentHandler() { return h; } protected void addDocumentStart() { try { h.startDocument(); } catch (SAXException ex) { throw new RuntimeException(ex.getException()); } } protected void addDocumentEnd() { try { h.endDocument(); } catch (SAXException ex) { throw new RuntimeException(ex.toString()); } } protected final void addStart(final String name, final Attributes attrs) { try { h.startElement("", name, name, attrs); } catch (SAXException ex) { throw new RuntimeException(ex.toString()); } } protected final void addEnd(final String name) { try { h.endElement("", name, name); } catch (SAXException ex) { throw new RuntimeException(ex.toString()); } } protected final void addElement(final String name, final Attributes attrs) { addStart(name, attrs); addEnd(name); } public void visitAttribute(final Attribute attr) { // nothing to do } } asm-3.3.2/src/org/objectweb/asm/xml/asm-xml.dtd0000644000175000017500000002747211211477631021231 0ustar twernertwerner asm-3.3.2/src/org/objectweb/asm/xml/SAXAnnotationAdapter.java0000644000175000017500000001556710452754520024013 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Type; import org.xml.sax.ContentHandler; import org.xml.sax.helpers.AttributesImpl; /** * SAXAnnotationAdapter * * @author Eugene Kuleshov */ public class SAXAnnotationAdapter extends SAXAdapter implements AnnotationVisitor { private final String elementName; public SAXAnnotationAdapter( final ContentHandler h, final String elementName, final int visible, final String name, final String desc) { this(h, elementName, visible, desc, name, -1); } public SAXAnnotationAdapter( final ContentHandler h, final String elementName, final int visible, final int parameter, final String desc) { this(h, elementName, visible, desc, null, parameter); } private SAXAnnotationAdapter( final ContentHandler h, final String elementName, final int visible, final String desc, final String name, final int parameter) { super(h); this.elementName = elementName; AttributesImpl att = new AttributesImpl(); if (name != null) { att.addAttribute("", "name", "name", "", name); } if (visible != 0) { att.addAttribute("", "visible", "visible", "", visible > 0 ? "true" : "false"); } if (parameter != -1) { att.addAttribute("", "parameter", "parameter", "", Integer.toString(parameter)); } if (desc != null) { att.addAttribute("", "desc", "desc", "", desc); } addStart(elementName, att); } public void visit(final String name, final Object value) { Class c = value.getClass(); if (c.isArray()) { AnnotationVisitor av = visitArray(name); if (value instanceof byte[]) { byte[] b = (byte[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Byte(b[i])); } } else if (value instanceof char[]) { char[] b = (char[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Character(b[i])); } } else if (value instanceof short[]) { short[] b = (short[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Short(b[i])); } } else if (value instanceof boolean[]) { boolean[] b = (boolean[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, Boolean.valueOf(b[i])); } } else if (value instanceof int[]) { int[] b = (int[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Integer(b[i])); } } else if (value instanceof long[]) { long[] b = (long[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Long(b[i])); } } else if (value instanceof float[]) { float[] b = (float[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Float(b[i])); } } else if (value instanceof double[]) { double[] b = (double[]) value; for (int i = 0; i < b.length; i++) { av.visit(null, new Double(b[i])); } } av.visitEnd(); } else { addValueElement("annotationValue", name, Type.getDescriptor(c), value.toString()); } } public void visitEnum( final String name, final String desc, final String value) { addValueElement("annotationValueEnum", name, desc, value); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { return new SAXAnnotationAdapter(getContentHandler(), "annotationValueAnnotation", 0, name, desc); } public AnnotationVisitor visitArray(final String name) { return new SAXAnnotationAdapter(getContentHandler(), "annotationValueArray", 0, name, null); } public void visitEnd() { addEnd(elementName); } private void addValueElement( final String element, final String name, final String desc, final String value) { AttributesImpl att = new AttributesImpl(); if (name != null) { att.addAttribute("", "name", "name", "", name); } if (desc != null) { att.addAttribute("", "desc", "desc", "", desc); } if (value != null) { att.addAttribute("", "value", "value", "", SAXClassAdapter.encode(value)); } addElement(element, att); } } asm-3.3.2/src/org/objectweb/asm/xml/Processor.java0000644000175000017500000010302611224532001021751 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamSource; import org.objectweb.asm.ClassReader; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; /** * Processor is a command line tool that can be used for bytecode waving * directed by XSL transformation.

In order to use a concrete XSLT engine, * system property javax.xml.transform.TransformerFactory must be set * to one of the following values. * *

* * * * * * * * * * *
jd.xsltjd.xml.xslt.trax.TransformerFactoryImpl
Saxon net.sf.saxon.TransformerFactoryImpl
Caucho com.caucho.xsl.Xsl
Xalan interpeter org.apache.xalan.processor.TransformerFactory
Xalan xsltc org.apache.xalan.xsltc.trax.TransformerFactoryImpl
* * @author Eugene Kuleshov */ public class Processor { public static final int BYTECODE = 1; public static final int MULTI_XML = 2; public static final int SINGLE_XML = 3; private static final String SINGLE_XML_NAME = "classes.xml"; private final int inRepresentation; private final int outRepresentation; private final InputStream input; private final OutputStream output; private final Source xslt; private final boolean computeMax; private int n = 0; public Processor( final int inRepresenation, final int outRepresentation, final InputStream input, final OutputStream output, final Source xslt) { this.inRepresentation = inRepresenation; this.outRepresentation = outRepresentation; this.input = input; this.output = output; this.xslt = xslt; this.computeMax = true; } public int process() throws TransformerException, IOException, SAXException { ZipInputStream zis = new ZipInputStream(input); final ZipOutputStream zos = new ZipOutputStream(output); final OutputStreamWriter osw = new OutputStreamWriter(zos); Thread.currentThread() .setContextClassLoader(getClass().getClassLoader()); TransformerFactory tf = TransformerFactory.newInstance(); if (!tf.getFeature(SAXSource.FEATURE) || !tf.getFeature(SAXResult.FEATURE)) { return 0; } SAXTransformerFactory saxtf = (SAXTransformerFactory) tf; Templates templates = null; if (xslt != null) { templates = saxtf.newTemplates(xslt); } // configuring outHandlerFactory // /////////////////////////////////////////////////////// EntryElement entryElement = getEntryElement(zos); ContentHandler outDocHandler = null; switch (outRepresentation) { case BYTECODE: outDocHandler = new OutputSlicingHandler(new ASMContentHandlerFactory(zos, computeMax), entryElement, false); break; case MULTI_XML: outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw, true), entryElement, true); break; case SINGLE_XML: ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME); zos.putNextEntry(outputEntry); outDocHandler = new SAXWriter(osw, false); break; } // configuring inputDocHandlerFactory // ///////////////////////////////////////////////// ContentHandler inDocHandler; if (templates == null) { inDocHandler = outDocHandler; } else { inDocHandler = new InputSlicingHandler("class", outDocHandler, new TransformerHandlerFactory(saxtf, templates, outDocHandler)); } ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(inDocHandler); if (inDocHandler != null && inRepresentation != SINGLE_XML) { inDocHandler.startDocument(); inDocHandler.startElement("", "classes", "classes", new AttributesImpl()); } int i = 0; ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { update(ze.getName(), n++); if (isClassEntry(ze)) { processEntry(zis, ze, inDocHandlerFactory); } else { OutputStream os = entryElement.openEntry(getName(ze)); copyEntry(zis, os); entryElement.closeEntry(); } i++; } if (inDocHandler != null && inRepresentation != SINGLE_XML) { inDocHandler.endElement("", "classes", "classes"); inDocHandler.endDocument(); } if (outRepresentation == SINGLE_XML) { zos.closeEntry(); } zos.flush(); zos.close(); return i; } private void copyEntry(final InputStream is, final OutputStream os) throws IOException { if (outRepresentation == SINGLE_XML) { return; } byte[] buff = new byte[2048]; int i; while ((i = is.read(buff)) != -1) { os.write(buff, 0, i); } } private boolean isClassEntry(final ZipEntry ze) { String name = ze.getName(); return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME) || name.endsWith(".class") || name.endsWith(".class.xml"); } private void processEntry( final ZipInputStream zis, final ZipEntry ze, final ContentHandlerFactory handlerFactory) { ContentHandler handler = handlerFactory.createContentHandler(); try { // if (CODE2ASM.equals(command)) { // read bytecode and process it // // with TraceClassVisitor // ClassReader cr = new ClassReader(readEntry(zis, ze)); // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)), // false); // } boolean singleInputDocument = inRepresentation == SINGLE_XML; if (inRepresentation == BYTECODE) { // read bytecode and process it // with handler ClassReader cr = new ClassReader(readEntry(zis, ze)); cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0); } else { // read XML and process it with handler XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setContentHandler(handler); reader.parse(new InputSource(singleInputDocument ? (InputStream) new ProtectedInputStream(zis) : new ByteArrayInputStream(readEntry(zis, ze)))); } } catch (Exception ex) { update(ze.getName(), 0); update(ex, 0); } } private EntryElement getEntryElement(final ZipOutputStream zos) { if (outRepresentation == SINGLE_XML) { return new SingleDocElement(zos); } return new ZipEntryElement(zos); } // private ContentHandlerFactory getHandlerFactory( // OutputStream os, // SAXTransformerFactory saxtf, // Templates templates) // { // ContentHandlerFactory factory = null; // if (templates == null) { // if (outputRepresentation == BYTECODE) { // factory used to write // // bytecode // factory = new ASMContentHandlerFactory(os, computeMax); // } else { // factory used to write XML // factory = new SAXWriterFactory(os, true); // } // } else { // if (outputRepresentation == BYTECODE) { // factory used to transform // // and then write bytecode // factory = new ASMTransformerHandlerFactory(saxtf, // templates, // os, // computeMax); // } else { // factory used to transformand then write XML // factory = new TransformerHandlerFactory(saxtf, // templates, // os, // outputRepresentation == SINGLE_XML); // } // } // return factory; // } private String getName(final ZipEntry ze) { String name = ze.getName(); if (isClassEntry(ze)) { if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) { name = name.substring(0, name.length() - 4); // .class.xml to // .class } else if (inRepresentation == BYTECODE && outRepresentation != BYTECODE) { name += ".xml"; // .class to .class.xml } // } else if( CODE2ASM.equals( command)) { // name = name.substring( 0, name.length()-6).concat( ".asm"); } return name; } private static byte[] readEntry(final InputStream zis, final ZipEntry ze) throws IOException { long size = ze.getSize(); if (size > -1) { byte[] buff = new byte[(int) size]; int k = 0; int n; while ((n = zis.read(buff, k, buff.length - k)) > 0) { k += n; } return buff; } ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buff = new byte[4096]; int i; while ((i = zis.read(buff)) != -1) { bos.write(buff, 0, i); } return bos.toByteArray(); } /* * (non-Javadoc) * * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ protected void update(final Object arg, final int n) { if (arg instanceof Throwable) { ((Throwable) arg).printStackTrace(); } else { if (n % 100 == 0) { System.err.println(n + " " + arg); } } } public static void main(final String[] args) throws Exception { if (args.length < 2) { showUsage(); return; } int inRepresentation = getRepresentation(args[0]); int outRepresentation = getRepresentation(args[1]); InputStream is = System.in; OutputStream os = new BufferedOutputStream(System.out); Source xslt = null; // boolean computeMax = true; for (int i = 2; i < args.length; i++) { if ("-in".equals(args[i])) { is = new FileInputStream(args[++i]); } else if ("-out".equals(args[i])) { os = new BufferedOutputStream(new FileOutputStream(args[++i])); } else if ("-xslt".equals(args[i])) { xslt = new StreamSource(new FileInputStream(args[++i])); // } else if( "-computemax".equals( args[ i].toLowerCase())) { // computeMax = true; } else { showUsage(); return; } } if (inRepresentation == 0 || outRepresentation == 0) { showUsage(); return; } Processor m = new Processor(inRepresentation, outRepresentation, is, os, xslt); long l1 = System.currentTimeMillis(); int n = m.process(); long l2 = System.currentTimeMillis(); System.err.println(n); System.err.println((l2 - l1) + "ms " + 1000f * n / (l2 - l1) + " resources/sec"); } private static int getRepresentation(final String s) { if ("code".equals(s)) { return BYTECODE; } else if ("xml".equals(s)) { return MULTI_XML; } else if ("singlexml".equals(s)) { return SINGLE_XML; } return 0; } private static void showUsage() { System.err.println("Usage: Main [-in ] [-out ] [-xslt ]"); System.err.println(" when -in or -out is omitted sysin and sysout would be used"); System.err.println(" and - code | xml | singlexml"); } /** * IputStream wrapper class used to protect input streams from being closed * by some stupid XML parsers. */ private static final class ProtectedInputStream extends InputStream { private final InputStream is; ProtectedInputStream(final InputStream is) { this.is = is; } public final void close() throws IOException { } public final int read() throws IOException { return is.read(); } public final int read(final byte[] b, final int off, final int len) throws IOException { return is.read(b, off, len); } public final int available() throws IOException { return is.available(); } } /** * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete * context. */ private static interface ContentHandlerFactory { /** * Creates an instance of the content handler. * * @return content handler */ ContentHandler createContentHandler(); } /** * SAXWriterFactory */ private static final class SAXWriterFactory implements ContentHandlerFactory { private final Writer w; private final boolean optimizeEmptyElements; SAXWriterFactory( final Writer w, final boolean optimizeEmptyElements) { this.w = w; this.optimizeEmptyElements = optimizeEmptyElements; } public final ContentHandler createContentHandler() { return new SAXWriter(w, optimizeEmptyElements); } } /** * ASMContentHandlerFactory */ private static final class ASMContentHandlerFactory implements ContentHandlerFactory { private OutputStream os; private final boolean computeMax; ASMContentHandlerFactory( final OutputStream os, final boolean computeMax) { this.os = os; this.computeMax = computeMax; } public final ContentHandler createContentHandler() { return new ASMContentHandler(os, computeMax); } } /** * TransformerHandlerFactory */ private static final class TransformerHandlerFactory implements ContentHandlerFactory { private SAXTransformerFactory saxtf; private final Templates templates; private ContentHandler outputHandler; TransformerHandlerFactory( final SAXTransformerFactory saxtf, final Templates templates, final ContentHandler outputHandler) { this.saxtf = saxtf; this.templates = templates; this.outputHandler = outputHandler; } public final ContentHandler createContentHandler() { try { TransformerHandler handler = saxtf.newTransformerHandler(templates); handler.setResult(new SAXResult(outputHandler)); return handler; } catch (TransformerConfigurationException ex) { throw new RuntimeException(ex.toString()); } } } /** * SubdocumentHandlerFactory */ private static final class SubdocumentHandlerFactory implements ContentHandlerFactory { private final ContentHandler subdocumentHandler; SubdocumentHandlerFactory(final ContentHandler subdocumentHandler) { this.subdocumentHandler = subdocumentHandler; } public final ContentHandler createContentHandler() { return subdocumentHandler; } } /** * A {@link org.xml.sax.ContentHandler ContentHandler} and * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML * from SAX 2.0 events into {@link java.io.Writer Writer}. * *
This implementation does not support namespaces, entity * definitions (uncluding DTD), CDATA and text elements.
*/ private static final class SAXWriter extends DefaultHandler implements LexicalHandler { private static final char[] OFF = " ".toCharArray(); private Writer w; private final boolean optimizeEmptyElements; private boolean openElement = false; private int ident = 0; /** * Creates SAXWriter. * * @param w writer * @param optimizeEmptyElements if set to true, short * XML syntax will be used for empty elements */ SAXWriter(final Writer w, final boolean optimizeEmptyElements) { this.w = w; this.optimizeEmptyElements = optimizeEmptyElements; } public final void startElement( final String ns, final String localName, final String qName, final Attributes atts) throws SAXException { try { closeElement(); writeIdent(); w.write('<' + qName); if (atts != null && atts.getLength() > 0) { writeAttributes(atts); } if (optimizeEmptyElements) { openElement = true; } else { w.write(">\n"); } ident += 2; } catch (IOException ex) { throw new SAXException(ex); } } public final void endElement( final String ns, final String localName, final String qName) throws SAXException { ident -= 2; try { if (openElement) { w.write("/>\n"); openElement = false; } else { writeIdent(); w.write("\n"); } } catch (IOException ex) { throw new SAXException(ex); } } public final void endDocument() throws SAXException { try { w.flush(); } catch (IOException ex) { throw new SAXException(ex); } } public final void comment(final char[] ch, final int off, final int len) throws SAXException { try { closeElement(); writeIdent(); w.write("\n"); } catch (IOException ex) { throw new SAXException(ex); } } public final void startDTD( final String arg0, final String arg1, final String arg2) throws SAXException { } public final void endDTD() throws SAXException { } public final void startEntity(final String arg0) throws SAXException { } public final void endEntity(final String arg0) throws SAXException { } public final void startCDATA() throws SAXException { } public final void endCDATA() throws SAXException { } private final void writeAttributes(final Attributes atts) throws IOException { StringBuffer sb = new StringBuffer(); int len = atts.getLength(); for (int i = 0; i < len; i++) { sb.append(' ') .append(atts.getLocalName(i)) .append("=\"") .append(esc(atts.getValue(i))) .append('\"'); } w.write(sb.toString()); } /** * Encode string with escaping. * * @param str string to encode. * @return encoded string */ private static final String esc(final String str) { StringBuffer sb = new StringBuffer(str.length()); for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); switch (ch) { case '&': sb.append("&"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '\"': sb.append("""); break; default: if (ch > 0x7f) { sb.append("&#") .append(Integer.toString(ch)) .append(';'); } else { sb.append(ch); } } } return sb.toString(); } private final void writeIdent() throws IOException { int n = ident; while (n > 0) { if (n > OFF.length) { w.write(OFF); n -= OFF.length; } else { w.write(OFF, 0, n); n = 0; } } } private final void closeElement() throws IOException { if (openElement) { w.write(">\n"); } openElement = false; } } /** * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML * documents into smaller chunks. Each chunk is processed by the nested * {@link org.xml.sax.ContentHandler ContentHandler} obtained from * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is * useful for running XSLT engine against large XML document that will * hardly fit into the memory all together.

TODO use complete path for * subdocumentRoot */ private static final class InputSlicingHandler extends DefaultHandler { private String subdocumentRoot; private final ContentHandler rootHandler; private ContentHandlerFactory subdocumentHandlerFactory; private boolean subdocument = false; private ContentHandler subdocumentHandler; /** * Constructs a new {@link InputSlicingHandler SubdocumentHandler} * object. * * @param subdocumentRoot name/path to the root element of the * subdocument * @param rootHandler content handler for the entire document * (subdocument envelope). * @param subdocumentHandlerFactory a * {@link ContentHandlerFactory ContentHandlerFactory} used to * create {@link ContentHandler ContentHandler} instances for * subdocuments. */ InputSlicingHandler( final String subdocumentRoot, final ContentHandler rootHandler, final ContentHandlerFactory subdocumentHandlerFactory) { this.subdocumentRoot = subdocumentRoot; this.rootHandler = rootHandler; this.subdocumentHandlerFactory = subdocumentHandlerFactory; } public final void startElement( final String namespaceURI, final String localName, final String qName, final Attributes list) throws SAXException { if (subdocument) { subdocumentHandler.startElement(namespaceURI, localName, qName, list); } else if (localName.equals(subdocumentRoot)) { subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); subdocumentHandler.startDocument(); subdocumentHandler.startElement(namespaceURI, localName, qName, list); subdocument = true; } else if (rootHandler != null) { rootHandler.startElement(namespaceURI, localName, qName, list); } } public final void endElement( final String namespaceURI, final String localName, final String qName) throws SAXException { if (subdocument) { subdocumentHandler.endElement(namespaceURI, localName, qName); if (localName.equals(subdocumentRoot)) { subdocumentHandler.endDocument(); subdocument = false; } } else if (rootHandler != null) { rootHandler.endElement(namespaceURI, localName, qName); } } public final void startDocument() throws SAXException { if (rootHandler != null) { rootHandler.startDocument(); } } public final void endDocument() throws SAXException { if (rootHandler != null) { rootHandler.endDocument(); } } public final void characters( final char[] buff, final int offset, final int size) throws SAXException { if (subdocument) { subdocumentHandler.characters(buff, offset, size); } else if (rootHandler != null) { rootHandler.characters(buff, offset, size); } } } /** * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML * documents into smaller chunks. Each chunk is processed by the nested * {@link org.xml.sax.ContentHandler ContentHandler} obtained from * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is * useful for running XSLT engine against large XML document that will * hardly fit into the memory all together. * *

TODO use complete path for subdocumentRoot */ private static final class OutputSlicingHandler extends DefaultHandler { private final String subdocumentRoot; private ContentHandlerFactory subdocumentHandlerFactory; private final EntryElement entryElement; private boolean isXml; private boolean subdocument = false; private ContentHandler subdocumentHandler; /** * Constructs a new {@link OutputSlicingHandler SubdocumentHandler} * object. * * @param subdocumentHandlerFactory a * {@link ContentHandlerFactory ContentHandlerFactory} used to * create {@link ContentHandler ContentHandler} instances for * subdocuments. * @param entryElement TODO. * @param isXml TODO. */ OutputSlicingHandler( final ContentHandlerFactory subdocumentHandlerFactory, final EntryElement entryElement, final boolean isXml) { this.subdocumentRoot = "class"; this.subdocumentHandlerFactory = subdocumentHandlerFactory; this.entryElement = entryElement; this.isXml = isXml; } public final void startElement( final String namespaceURI, final String localName, final String qName, final Attributes list) throws SAXException { if (subdocument) { subdocumentHandler.startElement(namespaceURI, localName, qName, list); } else if (localName.equals(subdocumentRoot)) { String name = list.getValue("name"); if (name == null || name.length() == 0) { throw new SAXException("Class element without name attribute."); } try { entryElement.openEntry(isXml ? name + ".class.xml" : name + ".class"); } catch (IOException ex) { throw new SAXException(ex.toString(), ex); } subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); subdocumentHandler.startDocument(); subdocumentHandler.startElement(namespaceURI, localName, qName, list); subdocument = true; } } public final void endElement( final String namespaceURI, final String localName, final String qName) throws SAXException { if (subdocument) { subdocumentHandler.endElement(namespaceURI, localName, qName); if (localName.equals(subdocumentRoot)) { subdocumentHandler.endDocument(); subdocument = false; try { entryElement.closeEntry(); } catch (IOException ex) { throw new SAXException(ex.toString(), ex); } } } } public final void startDocument() throws SAXException { } public final void endDocument() throws SAXException { } public final void characters( final char[] buff, final int offset, final int size) throws SAXException { if (subdocument) { subdocumentHandler.characters(buff, offset, size); } } } private static interface EntryElement { OutputStream openEntry(String name) throws IOException; void closeEntry() throws IOException; } private static final class SingleDocElement implements EntryElement { private final OutputStream os; SingleDocElement(final OutputStream os) { this.os = os; } public OutputStream openEntry(final String name) throws IOException { return os; } public void closeEntry() throws IOException { os.flush(); } } private static final class ZipEntryElement implements EntryElement { private ZipOutputStream zos; ZipEntryElement(final ZipOutputStream zos) { this.zos = zos; } public OutputStream openEntry(final String name) throws IOException { ZipEntry entry = new ZipEntry(name); zos.putNextEntry(entry); return zos; } public void closeEntry() throws IOException { zos.flush(); zos.closeEntry(); } } } asm-3.3.2/src/org/objectweb/asm/AnnotationVisitor.java0000644000175000017500000001044010635277351022704 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A visitor to visit a Java annotation. The methods of this interface must be * called in the following order: (visit | visitEnum | * visitAnnotation | visitArray)* visitEnd. * * @author Eric Bruneton * @author Eugene Kuleshov */ public interface AnnotationVisitor { /** * Visits a primitive value of the annotation. * * @param name the value name. * @param value the actual value, whose type must be {@link Byte}, * {@link Boolean}, {@link Character}, {@link Short}, * {@link Integer}, {@link Long}, {@link Float}, {@link Double}, * {@link String} or {@link Type}. This value can also be an array * of byte, boolean, short, char, int, long, float or double values * (this is equivalent to using {@link #visitArray visitArray} and * visiting each array element in turn, but is more convenient). */ void visit(String name, Object value); /** * Visits an enumeration value of the annotation. * * @param name the value name. * @param desc the class descriptor of the enumeration class. * @param value the actual enumeration value. */ void visitEnum(String name, String desc, String value); /** * Visits a nested annotation value of the annotation. * * @param name the value name. * @param desc the class descriptor of the nested annotation class. * @return a visitor to visit the actual nested annotation value, or * null if this visitor is not interested in visiting * this nested annotation. The nested annotation value must be * fully visited before calling other methods on this annotation * visitor. */ AnnotationVisitor visitAnnotation(String name, String desc); /** * Visits an array value of the annotation. Note that arrays of primitive * types (such as byte, boolean, short, char, int, long, float or double) * can be passed as value to {@link #visit visit}. This is what * {@link ClassReader} does. * * @param name the value name. * @return a visitor to visit the actual array value elements, or * null if this visitor is not interested in visiting * these values. The 'name' parameters passed to the methods of this * visitor are ignored. All the array values must be visited * before calling other methods on this annotation visitor. */ AnnotationVisitor visitArray(String name); /** * Visits the end of the annotation. */ void visitEnd(); } asm-3.3.2/src/org/objectweb/asm/Type.java0000644000175000017500000006177711525262537020155 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * A Java type. This class can be used to make it easier to manipulate type and * method descriptors. * * @author Eric Bruneton * @author Chris Nokleberg */ public class Type { /** * The sort of the void type. See {@link #getSort getSort}. */ public static final int VOID = 0; /** * The sort of the boolean type. See {@link #getSort getSort}. */ public static final int BOOLEAN = 1; /** * The sort of the char type. See {@link #getSort getSort}. */ public static final int CHAR = 2; /** * The sort of the byte type. See {@link #getSort getSort}. */ public static final int BYTE = 3; /** * The sort of the short type. See {@link #getSort getSort}. */ public static final int SHORT = 4; /** * The sort of the int type. See {@link #getSort getSort}. */ public static final int INT = 5; /** * The sort of the float type. See {@link #getSort getSort}. */ public static final int FLOAT = 6; /** * The sort of the long type. See {@link #getSort getSort}. */ public static final int LONG = 7; /** * The sort of the double type. See {@link #getSort getSort}. */ public static final int DOUBLE = 8; /** * The sort of array reference types. See {@link #getSort getSort}. */ public static final int ARRAY = 9; /** * The sort of object reference type. See {@link #getSort getSort}. */ public static final int OBJECT = 10; /** * The void type. */ public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1); /** * The boolean type. */ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1); /** * The char type. */ public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1); /** * The byte type. */ public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1); /** * The short type. */ public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1); /** * The int type. */ public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1); /** * The float type. */ public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1); /** * The long type. */ public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1); /** * The double type. */ public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1); // ------------------------------------------------------------------------ // Fields // ------------------------------------------------------------------------ /** * The sort of this Java type. */ private final int sort; /** * A buffer containing the internal name of this Java type. This field is * only used for reference types. */ private final char[] buf; /** * The offset of the internal name of this Java type in {@link #buf buf} or, * for primitive types, the size, descriptor and getOpcode offsets for this * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset * for IALOAD or IASTORE, byte 3 the offset for all other instructions). */ private final int off; /** * The length of the internal name of this Java type. */ private final int len; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * 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 internal name. * * @param internalName an internal name. * @return the Java type corresponding to the given internal name. */ public static Type getObjectType(final String internalName) { char[] buf = internalName.toCharArray(); return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); } /** * 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 + (args[size].sort == OBJECT ? 2 : 0); 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()); } /** * 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). */ public 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; } } } /** * 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 + 1, 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 binary name of the class corresponding to this type. * * @return the binary name of the class corresponding to this type. */ public String getClassName() { switch (sort) { case VOID: return "void"; case BOOLEAN: return "boolean"; case CHAR: return "char"; case BYTE: return "byte"; case SHORT: return "short"; case INT: return "int"; case FLOAT: return "float"; case LONG: return "long"; case DOUBLE: return "double"; case ARRAY: StringBuffer b = new StringBuffer(getElementType().getClassName()); for (int i = getDimensions(); i > 0; --i) { b.append("[]"); } return b.toString(); // case OBJECT: default: return new String(buf, off, len).replace('/', '.'); } } /** * Returns the internal name of the class corresponding to this object or * array type. The internal name of a class is its fully qualified name (as * returned by Class.getName(), where '.' are replaced by '/'. This method * should only be used for an object or array type. * * @return the internal name of the class corresponding to this object type. */ public String getInternalName() { return new String(buf, off, len); } // ------------------------------------------------------------------------ // 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) { if (this.buf == null) { // descriptor is in byte 3 of 'off' for primitive types (buf == null) buf.append((char) ((off & 0xFF000000) >>> 24)); } else if (sort == ARRAY) { buf.append(this.buf, off, len); } else { // sort == OBJECT buf.append('L'); buf.append(this.buf, off, len); buf.append(';'); } } // ------------------------------------------------------------------------ // 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, as returned by Class.getName(), where * '.' are replaced by '/'. * * @param c an object or array 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 constructor. * * @param c a {@link Constructor Constructor} object. * @return the descriptor of the given constructor. */ public static String getConstructorDescriptor(final Constructor c) { Class[] parameters = c.getParameterTypes(); StringBuffer buf = new StringBuffer(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); } return buf.append(")V").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, 0 for void and 1 otherwise. */ public int getSize() { // the size is in byte 0 of 'off' for primitive types (buf == null) return buf == null ? (off & 0xFF) : 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 == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { // the offset for IALOAD or IASTORE is in byte 1 of 'off' for // primitive types (buf == null) return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); } else { // the offset for other instructions is in byte 2 of 'off' for // primitive types (buf == null) return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); } } // ------------------------------------------------------------------------ // Equals, hashCode and toString // ------------------------------------------------------------------------ /** * Tests if the given object is equal to this type. * * @param o the object to be compared to this type. * @return true if the given object is equal to this type. */ public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Type)) { return false; } Type t = (Type) o; if (sort != t.sort) { return false; } if (sort == OBJECT || sort == ARRAY) { if (len != t.len) { return false; } for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { if (buf[i] != t.buf[j]) { return false; } } } return true; } /** * Returns a hash code value for this type. * * @return a hash code value for this type. */ public int hashCode() { int hc = 13 * sort; if (sort == OBJECT || sort == ARRAY) { for (int i = off, end = i + len; i < end; i++) { hc = 17 * (hc + buf[i]); } } return hc; } /** * Returns a string representation of this type. * * @return the descriptor of this type. */ public String toString() { return getDescriptor(); } } asm-3.3.2/src/org/objectweb/asm/package.html0000644000175000017500000001046210452754520020627 0ustar twernertwerner Provides a small and fast bytecode manipulation framework.

The ASM framework is organized around the {@link org.objectweb.asm.ClassVisitor ClassVisitor}, {@link org.objectweb.asm.FieldVisitor FieldVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces, which allow one to visit the fields and methods of a class, including the bytecode instructions of each method.

In addition to these main interfaces, ASM provides a {@link org.objectweb.asm.ClassReader ClassReader} class, that can parse an existing class and make a given visitor visit it. ASM also provides a {@link org.objectweb.asm.ClassWriter ClassWriter} class, which is a visitor that generates Java class files.

In order to generate a class from scratch, only the {@link org.objectweb.asm.ClassWriter ClassWriter} class is necessary. Indeed, in order to generate a class, one must just call its visitXXX methods with the appropriate arguments to generate the desired fields and methods. See the "helloworld" example in the ASM distribution for more details about class generation.

In order to modify existing classes, one must use a {@link org.objectweb.asm.ClassReader ClassReader} class to analyze the original class, a class modifier, and a {@link org.objectweb.asm.ClassWriter ClassWriter} to construct the modified class. The class modifier is just a {@link org.objectweb.asm.ClassVisitor ClassVisitor} that delegates most of the work to another {@link org.objectweb.asm.ClassVisitor ClassVisitor}, but that sometimes changes some parameter values, or call additional methods, in order to implement the desired modification process. In order to make it easier to implement such class modifiers, ASM provides the {@link org.objectweb.asm.ClassAdapter ClassAdapter} and {@link org.objectweb.asm.MethodAdapter MethodAdapter} classes, which implement the {@link org.objectweb.asm.ClassVisitor ClassVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces by delegating all work to other visitors. See the "adapt" example in the ASM distribution for more details about class modification.

The size of the core ASM library, asm.jar, is only 42KB, which is much smaller than the size of the BCEL library (504KB), and than the size of the SERP library (150KB). ASM is also much faster than these tools. Indeed the overhead of a load time class transformation process is of the order of 60% with ASM, 700% or more with BCEL, and 1100% or more with SERP (see the test/perf directory in the ASM distribution)! @since ASM 1.3 asm-3.3.2/src/org/objectweb/asm/FieldVisitor.java0000644000175000017500000000531610635277351021623 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A visitor to visit a Java field. The methods of this interface must be called * in the following order: ( visitAnnotation | * visitAttribute )* visitEnd. * * @author Eric Bruneton */ public interface FieldVisitor { /** * Visits an annotation of the field. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ AnnotationVisitor visitAnnotation(String desc, boolean visible); /** * Visits a non standard attribute of the field. * * @param attr an attribute. */ void visitAttribute(Attribute attr); /** * Visits the end of the field. This method, which is the last one to be * called, is used to inform the visitor that all the annotations and * attributes of the field have been visited. */ void visitEnd(); } asm-3.3.2/src/org/objectweb/asm/ClassAdapter.java0000644000175000017500000000765310635277351021574 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * An empty {@link ClassVisitor} that delegates to another {@link ClassVisitor}. * This class can be used as a super class to quickly implement usefull class * adapter classes, just by overriding the necessary methods. * * @author Eric Bruneton */ public class ClassAdapter implements ClassVisitor { /** * The {@link ClassVisitor} to which this adapter delegates calls. */ protected ClassVisitor cv; /** * Constructs a new {@link ClassAdapter} object. * * @param cv the class visitor to which this adapter must delegate calls. */ public ClassAdapter(final ClassVisitor cv) { this.cv = cv; } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { cv.visit(version, access, name, signature, superName, interfaces); } public void visitSource(final String source, final String debug) { cv.visitSource(source, debug); } public void visitOuterClass( final String owner, final String name, final String desc) { cv.visitOuterClass(owner, name, desc); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return cv.visitAnnotation(desc, visible); } public void visitAttribute(final Attribute attr) { cv.visitAttribute(attr); } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { cv.visitInnerClass(name, outerName, innerName, access); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { return cv.visitField(access, name, desc, signature, value); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return cv.visitMethod(access, name, desc, signature, exceptions); } public void visitEnd() { cv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/ByteVector.java0000644000175000017500000002313311214050516021265 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A dynamically extensible vector of bytes. This class is roughly equivalent to * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. * * @author Eric Bruneton */ public class ByteVector { /** * The content of this vector. */ byte[] data; /** * Actual number of bytes in this vector. */ int length; /** * Constructs a new {@link ByteVector ByteVector} with a default initial * size. */ public ByteVector() { data = new byte[64]; } /** * Constructs a new {@link ByteVector ByteVector} with the given initial * size. * * @param initialSize the initial size of the byte vector to be constructed. */ public ByteVector(final int initialSize) { data = new byte[initialSize]; } /** * Puts a byte into this byte vector. The byte vector is automatically * enlarged if necessary. * * @param b a byte. * @return this byte vector. */ public ByteVector putByte(final int b) { int length = this.length; if (length + 1 > data.length) { enlarge(1); } data[length++] = (byte) b; this.length = length; return this; } /** * Puts two bytes into this byte vector. The byte vector is automatically * enlarged if necessary. * * @param b1 a byte. * @param b2 another byte. * @return this byte vector. */ ByteVector put11(final int b1, final int b2) { int length = this.length; if (length + 2 > data.length) { enlarge(2); } byte[] data = this.data; data[length++] = (byte) b1; data[length++] = (byte) b2; this.length = length; return this; } /** * Puts a short into this byte vector. The byte vector is automatically * enlarged if necessary. * * @param s a short. * @return this byte vector. */ public ByteVector putShort(final int s) { int length = this.length; if (length + 2 > data.length) { enlarge(2); } byte[] data = this.data; data[length++] = (byte) (s >>> 8); data[length++] = (byte) s; this.length = length; return this; } /** * Puts a byte and a short into this byte vector. The byte vector is * automatically enlarged if necessary. * * @param b a byte. * @param s a short. * @return this byte vector. */ ByteVector put12(final int b, final int s) { int length = this.length; if (length + 3 > data.length) { enlarge(3); } byte[] data = this.data; data[length++] = (byte) b; data[length++] = (byte) (s >>> 8); data[length++] = (byte) s; this.length = length; return this; } /** * Puts an int into this byte vector. The byte vector is automatically * enlarged if necessary. * * @param i an int. * @return this byte vector. */ public ByteVector putInt(final int i) { int length = this.length; if (length + 4 > data.length) { enlarge(4); } byte[] data = this.data; data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 8); data[length++] = (byte) i; this.length = length; return this; } /** * Puts a long into this byte vector. The byte vector is automatically * enlarged if necessary. * * @param l a long. * @return this byte vector. */ public ByteVector putLong(final long l) { int length = this.length; if (length + 8 > data.length) { enlarge(8); } byte[] data = this.data; int i = (int) (l >>> 32); data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 8); data[length++] = (byte) i; i = (int) l; data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 8); data[length++] = (byte) i; this.length = length; return this; } /** * Puts an UTF8 string into this byte vector. The byte vector is * automatically enlarged if necessary. * * @param s a String. * @return this byte vector. */ public ByteVector putUTF8(final String s) { int charLength = s.length(); int len = length; if (len + 2 + charLength > data.length) { enlarge(2 + charLength); } byte[] data = this.data; // optimistic algorithm: instead of computing the byte length and then // serializing the string (which requires two loops), we assume the byte // length is equal to char length (which is the most frequent case), and // we start serializing the string right away. During the serialization, // if we find that this assumption is wrong, we continue with the // general method. data[len++] = (byte) (charLength >>> 8); data[len++] = (byte) charLength; for (int i = 0; i < charLength; ++i) { char c = s.charAt(i); if (c >= '\001' && c <= '\177') { data[len++] = (byte) c; } else { int byteLength = i; for (int j = i; j < charLength; ++j) { c = s.charAt(j); if (c >= '\001' && c <= '\177') { byteLength++; } else if (c > '\u07FF') { byteLength += 3; } else { byteLength += 2; } } data[length] = (byte) (byteLength >>> 8); data[length + 1] = (byte) byteLength; if (length + 2 + byteLength > data.length) { length = len; enlarge(2 + byteLength); data = this.data; } for (int j = i; j < charLength; ++j) { c = s.charAt(j); if (c >= '\001' && c <= '\177') { data[len++] = (byte) c; } else if (c > '\u07FF') { data[len++] = (byte) (0xE0 | c >> 12 & 0xF); data[len++] = (byte) (0x80 | c >> 6 & 0x3F); data[len++] = (byte) (0x80 | c & 0x3F); } else { data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); data[len++] = (byte) (0x80 | c & 0x3F); } } break; } } length = len; return this; } /** * Puts an array of bytes into this byte vector. The byte vector is * automatically enlarged if necessary. * * @param b an array of bytes. May be 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) { int length1 = 2 * data.length; int length2 = length + size; byte[] newData = new byte[length1 > length2 ? length1 : length2]; System.arraycopy(data, 0, newData, 0, length); data = newData; } } asm-3.3.2/src/org/objectweb/asm/Item.java0000644000175000017500000002043011214131647020077 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A constant pool item. Constant pool items can be created with the 'newXXX' * methods in the {@link ClassWriter} class. * * @author Eric Bruneton */ final class Item { /** * Index of this item in the constant pool. */ int index; /** * Type of this constant pool item. A single class is used to represent all * constant pool item types, in order to minimize the bytecode size of this * package. The value of this field is one of {@link ClassWriter#INT}, * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}. * * Special Item types are used for Items that are stored in the ClassWriter * {@link ClassWriter#typeTable}, instead of the constant pool, in order to * avoid clashes with normal constant pool items in the ClassWriter constant * pool's hash table. These special item types are * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and * {@link ClassWriter#TYPE_MERGED}. */ int type; /** * Value of this item, for an integer item. */ int intVal; /** * Value of this item, for a long item. */ long longVal; /** * 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() { } /** * Constructs an uninitialized {@link Item} for constant pool element at * given position. * * @param index index of the item to be constructed. */ Item(final int index) { this.index = index; } /** * Constructs a copy of the given item. * * @param index index of the item to be constructed. * @param i the item that must be copied into the item to be constructed. */ Item(final int index, final Item i) { this.index = index; type = i.type; intVal = i.intVal; longVal = i.longVal; strVal1 = i.strVal1; strVal2 = i.strVal2; strVal3 = i.strVal3; hashCode = i.hashCode; } /** * Sets this item to an integer item. * * @param intVal the value of this item. */ void set(final int intVal) { this.type = ClassWriter.INT; this.intVal = intVal; this.hashCode = 0x7FFFFFFF & (type + intVal); } /** * Sets this item to a long item. * * @param longVal the value of this item. */ void set(final long longVal) { this.type = ClassWriter.LONG; this.longVal = longVal; this.hashCode = 0x7FFFFFFF & (type + (int) longVal); } /** * Sets this item to a float item. * * @param floatVal the value of this item. */ void set(final float floatVal) { this.type = ClassWriter.FLOAT; this.intVal = Float.floatToRawIntBits(floatVal); this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); } /** * Sets this item to a double item. * * @param doubleVal the value of this item. */ void set(final double doubleVal) { this.type = ClassWriter.DOUBLE; this.longVal = Double.doubleToRawLongBits(doubleVal); this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); } /** * Sets this item to an item that do not hold a primitive value. * * @param type the type of this item. * @param strVal1 first part of the value of this item. * @param strVal2 second part of the value of this item. * @param strVal3 third part of the value of this item. */ void set( final int type, final String strVal1, final String strVal2, final String strVal3) { this.type = type; this.strVal1 = strVal1; this.strVal2 = strVal2; this.strVal3 = strVal3; switch (type) { case ClassWriter.UTF8: case ClassWriter.STR: case ClassWriter.CLASS: case ClassWriter.TYPE_NORMAL: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); return; case ClassWriter.NAME_TYPE: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode()); return; // ClassWriter.FIELD: // ClassWriter.METH: // ClassWriter.IMETH: default: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode()); } } /** * Indicates if the given item is equal to this one. This method assumes * that the two items have the same {@link #type}. * * @param i the item to be compared to this one. Both items must have the * same {@link #type}. * @return true if the given item if equal to this one, * false otherwise. */ boolean isEqualTo(final Item i) { switch (type) { case ClassWriter.UTF8: case ClassWriter.STR: case ClassWriter.CLASS: case ClassWriter.TYPE_NORMAL: return i.strVal1.equals(strVal1); case ClassWriter.TYPE_MERGED: case ClassWriter.LONG: case ClassWriter.DOUBLE: return i.longVal == longVal; case ClassWriter.INT: case ClassWriter.FLOAT: return i.intVal == intVal; case ClassWriter.TYPE_UNINIT: return i.intVal == intVal && 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); } } } asm-3.3.2/src/org/objectweb/asm/Frame.java0000644000175000017500000013752711211477631020256 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * Information about the input and output stack map frames of a basic block. * * @author Eric Bruneton */ final class Frame { /* * Frames are computed in a two steps process: during the visit of each * instruction, the state of the frame at the end of current basic block is * updated by simulating the action of the instruction on the previous state * of this so called "output frame". In visitMaxs, a fix point algorithm is * used to compute the "input frame" of each basic block, i.e. the stack map * frame at the beginning of the basic block, starting from the input frame * of the first basic block (which is computed from the method descriptor), * and by using the previously computed output frames to compute the input * state of the other blocks. * * All output and input frames are stored as arrays of integers. Reference * and array types are represented by an index into a type table (which is * not the same as the constant pool of the class, in order to avoid adding * unnecessary constants in the pool - not all computed frames will end up * being stored in the stack map table). This allows very fast type * comparisons. * * Output stack map frames are computed relatively to the input frame of the * basic block, which is not yet known when output frames are computed. It * is therefore necessary to be able to represent abstract types such as * "the type at position x in the input frame locals" or "the type at * position x from the top of the input frame stack" or even "the type at * position x in the input frame, with y more (or less) array dimensions". * This explains the rather complicated type format used in output frames. * * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a * signed number of array dimensions (from -8 to 7). KIND is either BASE, * LOCAL or STACK. BASE is used for types that are not relative to the input * frame. LOCAL is used for types that are relative to the input local * variable types. STACK is used for types that are relative to the input * stack types. VALUE depends on KIND. For LOCAL types, it is an index in * the input local variable types. For STACK types, it is a position * relatively to the top of input frame stack. For BASE types, it is either * one of the constants defined in FrameVisitor, or for OBJECT and * UNINITIALIZED types, a tag and an index in the type table. * * Output frames can contain types of any kind and with a positive or * negative dimension (and even unassigned types, represented by 0 - which * does not correspond to any valid type value). Input frames can only * contain BASE types of positive or null dimension. In all cases the type * table contains only internal type names (array type descriptors are * forbidden - dimensions must be represented through the DIM field). * * The LONG and DOUBLE types are always represented by using two slots (LONG + * TOP or DOUBLE + TOP), for local variable types as well as in the operand * stack. This is necessary to be able to simulate DUPx_y instructions, * whose effect would be dependent on the actual type values if types were * always represented by a single slot in the stack (and this is not * possible, since actual type values are not always known - cf LOCAL and * STACK type kinds). */ /** * Mask to get the dimension of a frame type. This dimension is a signed * integer between -8 and 7. */ static final int DIM = 0xF0000000; /** * Constant to be added to a type to get a type with one more dimension. */ static final int ARRAY_OF = 0x10000000; /** * Constant to be added to a type to get a type with one less dimension. */ static final int ELEMENT_OF = 0xF0000000; /** * Mask to get the kind of a frame type. * * @see #BASE * @see #LOCAL * @see #STACK */ static final int KIND = 0xF000000; /** * Flag used for LOCAL and STACK types. Indicates that if this type happens * to be a long or double type (during the computations of input frames), * then it must be set to TOP because the second word of this value has * been reused to store other data in the basic block. Hence the first word * no longer stores a valid long or double value. */ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; /** * Mask to get the value of a frame type. */ static final int VALUE = 0x7FFFFF; /** * Mask to get the kind of base types. */ static final int BASE_KIND = 0xFF00000; /** * Mask to get the value of base types. */ static final int BASE_VALUE = 0xFFFFF; /** * Kind of the types that are not relative to an input stack map frame. */ static final int BASE = 0x1000000; /** * Base kind of the base reference types. The BASE_VALUE of such types is an * index into the type table. */ static final int OBJECT = BASE | 0x700000; /** * Base kind of the uninitialized base types. The BASE_VALUE of such types * in an index into the type table (the Item at that index contains both an * instruction offset and an internal class name). */ static final int UNINITIALIZED = BASE | 0x800000; /** * Kind of the types that are relative to the local variable types of an * input stack map frame. The value of such types is a local variable index. */ private static final int LOCAL = 0x2000000; /** * Kind of the the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ private static final int STACK = 0x3000000; /** * The TOP type. This is a BASE type. */ static final int TOP = BASE | 0; /** * The BOOLEAN type. This is a BASE type mainly used for array types. */ static final int BOOLEAN = BASE | 9; /** * The BYTE type. This is a BASE type mainly used for array types. */ static final int BYTE = BASE | 10; /** * The CHAR type. This is a BASE type mainly used for array types. */ static final int CHAR = BASE | 11; /** * The SHORT type. This is a BASE type mainly used for array types. */ static final int SHORT = BASE | 12; /** * The INTEGER type. This is a BASE type. */ static final int INTEGER = BASE | 1; /** * The FLOAT type. This is a BASE type. */ static final int FLOAT = BASE | 2; /** * The DOUBLE type. This is a BASE type. */ static final int DOUBLE = BASE | 3; /** * The LONG type. This is a BASE type. */ static final int LONG = BASE | 4; /** * The NULL type. This is a BASE type. */ static final int NULL = BASE | 5; /** * The UNINITIALIZED_THIS type. This is a BASE type. */ static final int UNINITIALIZED_THIS = BASE | 6; /** * 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. */ static final int[] SIZE; /** * Computes the stack size variation corresponding to each JVM instruction. */ static { int i; int[] b = new int[202]; String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; for (i = 0; i < b.length; ++i) { b[i] = s.charAt(i) - 'E'; } SIZE = b; // code to generate the above string // // int NA = 0; // not applicable (unused opcode or variable size opcode) // // b = new int[] { // 0, //NOP, // visitInsn // 1, //ACONST_NULL, // - // 1, //ICONST_M1, // - // 1, //ICONST_0, // - // 1, //ICONST_1, // - // 1, //ICONST_2, // - // 1, //ICONST_3, // - // 1, //ICONST_4, // - // 1, //ICONST_5, // - // 2, //LCONST_0, // - // 2, //LCONST_1, // - // 1, //FCONST_0, // - // 1, //FCONST_1, // - // 1, //FCONST_2, // - // 2, //DCONST_0, // - // 2, //DCONST_1, // - // 1, //BIPUSH, // visitIntInsn // 1, //SIPUSH, // - // 1, //LDC, // visitLdcInsn // NA, //LDC_W, // - // NA, //LDC2_W, // - // 1, //ILOAD, // visitVarInsn // 2, //LLOAD, // - // 1, //FLOAD, // - // 2, //DLOAD, // - // 1, //ALOAD, // - // NA, //ILOAD_0, // - // NA, //ILOAD_1, // - // NA, //ILOAD_2, // - // NA, //ILOAD_3, // - // NA, //LLOAD_0, // - // NA, //LLOAD_1, // - // NA, //LLOAD_2, // - // NA, //LLOAD_3, // - // NA, //FLOAD_0, // - // NA, //FLOAD_1, // - // NA, //FLOAD_2, // - // NA, //FLOAD_3, // - // NA, //DLOAD_0, // - // NA, //DLOAD_1, // - // NA, //DLOAD_2, // - // NA, //DLOAD_3, // - // NA, //ALOAD_0, // - // NA, //ALOAD_1, // - // NA, //ALOAD_2, // - // NA, //ALOAD_3, // - // -1, //IALOAD, // visitInsn // 0, //LALOAD, // - // -1, //FALOAD, // - // 0, //DALOAD, // - // -1, //AALOAD, // - // -1, //BALOAD, // - // -1, //CALOAD, // - // -1, //SALOAD, // - // -1, //ISTORE, // visitVarInsn // -2, //LSTORE, // - // -1, //FSTORE, // - // -2, //DSTORE, // - // -1, //ASTORE, // - // NA, //ISTORE_0, // - // NA, //ISTORE_1, // - // NA, //ISTORE_2, // - // NA, //ISTORE_3, // - // NA, //LSTORE_0, // - // NA, //LSTORE_1, // - // NA, //LSTORE_2, // - // NA, //LSTORE_3, // - // NA, //FSTORE_0, // - // NA, //FSTORE_1, // - // NA, //FSTORE_2, // - // NA, //FSTORE_3, // - // NA, //DSTORE_0, // - // NA, //DSTORE_1, // - // NA, //DSTORE_2, // - // NA, //DSTORE_3, // - // NA, //ASTORE_0, // - // NA, //ASTORE_1, // - // NA, //ASTORE_2, // - // NA, //ASTORE_3, // - // -3, //IASTORE, // visitInsn // -4, //LASTORE, // - // -3, //FASTORE, // - // -4, //DASTORE, // - // -3, //AASTORE, // - // -3, //BASTORE, // - // -3, //CASTORE, // - // -3, //SASTORE, // - // -1, //POP, // - // -2, //POP2, // - // 1, //DUP, // - // 1, //DUP_X1, // - // 1, //DUP_X2, // - // 2, //DUP2, // - // 2, //DUP2_X1, // - // 2, //DUP2_X2, // - // 0, //SWAP, // - // -1, //IADD, // - // -2, //LADD, // - // -1, //FADD, // - // -2, //DADD, // - // -1, //ISUB, // - // -2, //LSUB, // - // -1, //FSUB, // - // -2, //DSUB, // - // -1, //IMUL, // - // -2, //LMUL, // - // -1, //FMUL, // - // -2, //DMUL, // - // -1, //IDIV, // - // -2, //LDIV, // - // -1, //FDIV, // - // -2, //DDIV, // - // -1, //IREM, // - // -2, //LREM, // - // -1, //FREM, // - // -2, //DREM, // - // 0, //INEG, // - // 0, //LNEG, // - // 0, //FNEG, // - // 0, //DNEG, // - // -1, //ISHL, // - // -1, //LSHL, // - // -1, //ISHR, // - // -1, //LSHR, // - // -1, //IUSHR, // - // -1, //LUSHR, // - // -1, //IAND, // - // -2, //LAND, // - // -1, //IOR, // - // -2, //LOR, // - // -1, //IXOR, // - // -2, //LXOR, // - // 0, //IINC, // visitIincInsn // 1, //I2L, // visitInsn // 0, //I2F, // - // 1, //I2D, // - // -1, //L2I, // - // -1, //L2F, // - // 0, //L2D, // - // 0, //F2I, // - // 1, //F2L, // - // 1, //F2D, // - // -1, //D2I, // - // 0, //D2L, // - // -1, //D2F, // - // 0, //I2B, // - // 0, //I2C, // - // 0, //I2S, // - // -3, //LCMP, // - // -1, //FCMPL, // - // -1, //FCMPG, // - // -3, //DCMPL, // - // -3, //DCMPG, // - // -1, //IFEQ, // visitJumpInsn // -1, //IFNE, // - // -1, //IFLT, // - // -1, //IFGE, // - // -1, //IFGT, // - // -1, //IFLE, // - // -2, //IF_ICMPEQ, // - // -2, //IF_ICMPNE, // - // -2, //IF_ICMPLT, // - // -2, //IF_ICMPGE, // - // -2, //IF_ICMPGT, // - // -2, //IF_ICMPLE, // - // -2, //IF_ACMPEQ, // - // -2, //IF_ACMPNE, // - // 0, //GOTO, // - // 1, //JSR, // - // 0, //RET, // visitVarInsn // -1, //TABLESWITCH, // visiTableSwitchInsn // -1, //LOOKUPSWITCH, // visitLookupSwitch // -1, //IRETURN, // visitInsn // -2, //LRETURN, // - // -1, //FRETURN, // - // -2, //DRETURN, // - // -1, //ARETURN, // - // 0, //RETURN, // - // NA, //GETSTATIC, // visitFieldInsn // NA, //PUTSTATIC, // - // NA, //GETFIELD, // - // NA, //PUTFIELD, // - // NA, //INVOKEVIRTUAL, // visitMethodInsn // NA, //INVOKESPECIAL, // - // NA, //INVOKESTATIC, // - // NA, //INVOKEINTERFACE, // - // NA, //INVOKEDYNAMIC, // - // 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(); } /** * The label (i.e. basic block) to which these input and output stack map * frames correspond. */ Label owner; /** * The input stack map frame locals. */ int[] inputLocals; /** * The input stack map frame stack. */ int[] inputStack; /** * The output stack map frame locals. */ private int[] outputLocals; /** * The output stack map frame stack. */ private int[] outputStack; /** * Relative size of the output stack. The exact semantics of this field * depends on the algorithm that is used. * * When only the maximum stack size is computed, this field is the size of * the output stack relatively to the top of the input stack. * * When the stack map frames are completely computed, this field is the * actual number of types in {@link #outputStack}. */ private int outputStackTop; /** * Number of types that are initialized in the basic block. * * @see #initializations */ private int initializationCount; /** * The types that are initialized in the basic block. A constructor * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace * every occurence of this type in the local variables and in the * operand stack. This cannot be done during the first phase of the * algorithm since, during this phase, the local variables and the operand * stack are not completely computed. It is therefore necessary to store the * types on which constructors are invoked in the basic block, in order to * do this replacement during the second phase of the algorithm, where the * frames are fully computed. Note that this array can contain types that * are relative to input locals or to the input stack (see below for the * description of the algorithm). */ private int[] initializations; /** * Returns the output frame local variable type at the given index. * * @param local the index of the local that must be returned. * @return the output frame local variable type at the given index. */ private int get(final int local) { if (outputLocals == null || local >= outputLocals.length) { // this local has never been assigned in this basic block, // so it is still equal to its value in the input frame return LOCAL | local; } else { int type = outputLocals[local]; if (type == 0) { // this local has never been assigned in this basic block, // so it is still equal to its value in the input frame type = outputLocals[local] = LOCAL | local; } return type; } } /** * Sets the output frame local variable type at the given index. * * @param local the index of the local that must be set. * @param type the value of the local that must be set. */ private void set(final int local, final int type) { // creates and/or resizes the output local variables array if necessary if (outputLocals == null) { outputLocals = new int[10]; } int n = outputLocals.length; if (local >= n) { int[] t = new int[Math.max(local + 1, 2 * n)]; System.arraycopy(outputLocals, 0, t, 0, n); outputLocals = t; } // sets the local variable outputLocals[local] = type; } /** * Pushes a new type onto the output frame stack. * * @param type the type that must be pushed. */ private void push(final int type) { // creates and/or resizes the output stack array if necessary if (outputStack == null) { outputStack = new int[10]; } int n = outputStack.length; if (outputStackTop >= n) { int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; System.arraycopy(outputStack, 0, t, 0, n); outputStack = t; } // pushes the type on the output stack outputStack[outputStackTop++] = type; // updates the maximun height reached by the output stack, if needed int top = owner.inputStackTop + outputStackTop; if (top > owner.outputStackMax) { owner.outputStackMax = top; } } /** * Pushes a new type onto the output frame stack. * * @param cw the ClassWriter to which this label belongs. * @param desc the descriptor of the type to be pushed. Can also be a method * descriptor (in this case this method pushes its return type onto * the output frame stack). */ private void push(final ClassWriter cw, final String desc) { int type = type(cw, desc); if (type != 0) { push(type); if (type == LONG || type == DOUBLE) { push(TOP); } } } /** * Returns the int encoding of the given type. * * @param cw the ClassWriter to which this label belongs. * @param desc a type descriptor. * @return the int encoding of the given type. */ private static int type(final ClassWriter cw, final String desc) { String t; int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; switch (desc.charAt(index)) { case 'V': return 0; case 'Z': case 'C': case 'B': case 'S': case 'I': return INTEGER; case 'F': return FLOAT; case 'J': return LONG; case 'D': return DOUBLE; case 'L': // stores the internal name, not the descriptor! t = desc.substring(index + 1, desc.length() - 1); return OBJECT | cw.addType(t); // case '[': default: // extracts the dimensions and the element type int data; int dims = index + 1; while (desc.charAt(dims) == '[') { ++dims; } switch (desc.charAt(dims)) { case 'Z': data = BOOLEAN; break; case 'C': data = CHAR; break; case 'B': data = BYTE; break; case 'S': data = SHORT; break; case 'I': data = INTEGER; break; case 'F': data = FLOAT; break; case 'J': data = LONG; break; case 'D': data = DOUBLE; break; // case 'L': default: // stores the internal name, not the descriptor t = desc.substring(dims + 1, desc.length() - 1); data = OBJECT | cw.addType(t); } return (dims - index) << 28 | data; } } /** * Pops a type from the output frame stack and returns its value. * * @return the type that has been popped from the output frame stack. */ private int pop() { if (outputStackTop > 0) { return outputStack[--outputStackTop]; } else { // if the output frame stack is empty, pops from the input stack return STACK | -(--owner.inputStackTop); } } /** * Pops the given number of types from the output frame stack. * * @param elements the number of types that must be popped. */ private void pop(final int elements) { if (outputStackTop >= elements) { outputStackTop -= elements; } else { // if the number of elements to be popped is greater than the number // of elements in the output stack, clear it, and pops the remaining // elements from the input stack. owner.inputStackTop -= elements - outputStackTop; outputStackTop = 0; } } /** * Pops a type from the output frame stack. * * @param desc the descriptor of the type to be popped. Can also be a method * descriptor (in this case this method pops the types corresponding * to the method arguments). */ private void pop(final String desc) { char c = desc.charAt(0); if (c == '(') { pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); } else if (c == 'J' || c == 'D') { pop(2); } else { pop(1); } } /** * Adds a new type to the list of types on which a constructor is invoked in * the basic block. * * @param var a type on a which a constructor is invoked. */ private void init(final int var) { // creates and/or resizes the initializations array if necessary if (initializations == null) { initializations = new int[2]; } int n = initializations.length; if (initializationCount >= n) { int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; System.arraycopy(initializations, 0, t, 0, n); initializations = t; } // stores the type to be initialized initializations[initializationCount++] = var; } /** * Replaces the given type with the appropriate type if it is one of the * types on which a constructor is invoked in the basic block. * * @param cw the ClassWriter to which this label belongs. * @param t a type * @return t or, if t is one of the types on which a constructor is invoked * in the basic block, the type corresponding to this constructor. */ private int init(final ClassWriter cw, final int t) { int s; if (t == UNINITIALIZED_THIS) { s = OBJECT | cw.addType(cw.thisName); } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { String type = cw.typeTable[t & BASE_VALUE].strVal1; s = OBJECT | cw.addType(type); } else { return t; } for (int j = 0; j < initializationCount; ++j) { int u = initializations[j]; int dim = u & DIM; int kind = u & KIND; if (kind == LOCAL) { u = dim + inputLocals[u & VALUE]; } else if (kind == STACK) { u = dim + inputStack[inputStack.length - (u & VALUE)]; } if (t == u) { return s; } } return t; } /** * Initializes the input frame of the first basic block from the method * descriptor. * * @param cw the ClassWriter to which this label belongs. * @param access the access flags of the method to which this label belongs. * @param args the formal parameter types of this method. * @param maxLocals the maximum number of local variables of this method. */ void initInputFrame( final ClassWriter cw, final int access, final Type[] args, final int maxLocals) { inputLocals = new int[maxLocals]; inputStack = new int[0]; int i = 0; if ((access & Opcodes.ACC_STATIC) == 0) { if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { inputLocals[i++] = OBJECT | cw.addType(cw.thisName); } else { inputLocals[i++] = UNINITIALIZED_THIS; } } for (int j = 0; j < args.length; ++j) { int t = type(cw, args[j].getDescriptor()); inputLocals[i++] = t; if (t == LONG || t == DOUBLE) { inputLocals[i++] = TOP; } } while (i < maxLocals) { inputLocals[i++] = TOP; } } /** * Simulates the action of the given instruction on the output stack frame. * * @param opcode the opcode of the instruction. * @param arg the operand of the instruction, if any. * @param cw the class writer to which this label belongs. * @param item the operand of the instructions, if any. */ void execute( final int opcode, final int arg, final ClassWriter cw, final Item item) { int t1, t2, t3, t4; switch (opcode) { case Opcodes.NOP: case Opcodes.INEG: case Opcodes.LNEG: case Opcodes.FNEG: case Opcodes.DNEG: case Opcodes.I2B: case Opcodes.I2C: case Opcodes.I2S: case Opcodes.GOTO: case Opcodes.RETURN: break; case Opcodes.ACONST_NULL: push(NULL); break; case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: case Opcodes.BIPUSH: case Opcodes.SIPUSH: case Opcodes.ILOAD: push(INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.LLOAD: push(LONG); push(TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: case Opcodes.FLOAD: push(FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; case Opcodes.LDC: switch (item.type) { case ClassWriter.INT: push(INTEGER); break; case ClassWriter.LONG: push(LONG); push(TOP); break; case ClassWriter.FLOAT: push(FLOAT); break; case ClassWriter.DOUBLE: push(DOUBLE); push(TOP); break; case ClassWriter.CLASS: push(OBJECT | cw.addType("java/lang/Class")); break; // case ClassWriter.STR: default: push(OBJECT | cw.addType("java/lang/String")); } break; case Opcodes.ALOAD: push(get(arg)); break; case Opcodes.IALOAD: case Opcodes.BALOAD: case Opcodes.CALOAD: case Opcodes.SALOAD: pop(2); push(INTEGER); break; case Opcodes.LALOAD: case Opcodes.D2L: pop(2); push(LONG); push(TOP); break; case Opcodes.FALOAD: pop(2); push(FLOAT); break; case Opcodes.DALOAD: case Opcodes.L2D: pop(2); push(DOUBLE); push(TOP); break; case Opcodes.AALOAD: pop(1); t1 = pop(); push(ELEMENT_OF + t1); break; case Opcodes.ISTORE: case Opcodes.FSTORE: case Opcodes.ASTORE: t1 = pop(); set(arg, t1); if (arg > 0) { t2 = get(arg - 1); // if t2 is of kind STACK or LOCAL we cannot know its size! if (t2 == LONG || t2 == DOUBLE) { set(arg - 1, TOP); } else if ((t2 & KIND) != BASE) { set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); } } break; case Opcodes.LSTORE: case Opcodes.DSTORE: pop(1); t1 = pop(); set(arg, t1); set(arg + 1, TOP); if (arg > 0) { t2 = get(arg - 1); // if t2 is of kind STACK or LOCAL we cannot know its size! if (t2 == LONG || t2 == DOUBLE) { set(arg - 1, TOP); } else if ((t2 & KIND) != BASE) { set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); } } break; case Opcodes.IASTORE: case Opcodes.BASTORE: case Opcodes.CASTORE: case Opcodes.SASTORE: case Opcodes.FASTORE: case Opcodes.AASTORE: pop(3); break; case Opcodes.LASTORE: case Opcodes.DASTORE: pop(4); break; case Opcodes.POP: case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IFLE: case Opcodes.IRETURN: case Opcodes.FRETURN: case Opcodes.ARETURN: case Opcodes.TABLESWITCH: case Opcodes.LOOKUPSWITCH: case Opcodes.ATHROW: case Opcodes.MONITORENTER: case Opcodes.MONITOREXIT: case Opcodes.IFNULL: case Opcodes.IFNONNULL: pop(1); break; case Opcodes.POP2: case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ICMPLE: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: case Opcodes.LRETURN: case Opcodes.DRETURN: pop(2); break; case Opcodes.DUP: t1 = pop(); push(t1); push(t1); break; case Opcodes.DUP_X1: t1 = pop(); t2 = pop(); push(t1); push(t2); push(t1); break; case Opcodes.DUP_X2: t1 = pop(); t2 = pop(); t3 = pop(); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2: t1 = pop(); t2 = pop(); push(t2); push(t1); push(t2); push(t1); break; case Opcodes.DUP2_X1: t1 = pop(); t2 = pop(); t3 = pop(); push(t2); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2_X2: t1 = pop(); t2 = pop(); t3 = pop(); t4 = pop(); push(t2); push(t1); push(t4); push(t3); push(t2); push(t1); break; case Opcodes.SWAP: t1 = pop(); t2 = pop(); push(t1); push(t2); break; case Opcodes.IADD: case Opcodes.ISUB: case Opcodes.IMUL: case Opcodes.IDIV: case Opcodes.IREM: case Opcodes.IAND: case Opcodes.IOR: case Opcodes.IXOR: case Opcodes.ISHL: case Opcodes.ISHR: case Opcodes.IUSHR: case Opcodes.L2I: case Opcodes.D2I: case Opcodes.FCMPL: case Opcodes.FCMPG: pop(2); push(INTEGER); break; case Opcodes.LADD: case Opcodes.LSUB: case Opcodes.LMUL: case Opcodes.LDIV: case Opcodes.LREM: case Opcodes.LAND: case Opcodes.LOR: case Opcodes.LXOR: pop(4); push(LONG); push(TOP); break; case Opcodes.FADD: case Opcodes.FSUB: case Opcodes.FMUL: case Opcodes.FDIV: case Opcodes.FREM: case Opcodes.L2F: case Opcodes.D2F: pop(2); push(FLOAT); break; case Opcodes.DADD: case Opcodes.DSUB: case Opcodes.DMUL: case Opcodes.DDIV: case Opcodes.DREM: pop(4); push(DOUBLE); push(TOP); break; case Opcodes.LSHL: case Opcodes.LSHR: case Opcodes.LUSHR: pop(3); push(LONG); push(TOP); break; case Opcodes.IINC: set(arg, INTEGER); break; case Opcodes.I2L: case Opcodes.F2L: pop(1); push(LONG); push(TOP); break; case Opcodes.I2F: pop(1); push(FLOAT); break; case Opcodes.I2D: case Opcodes.F2D: pop(1); push(DOUBLE); push(TOP); break; case Opcodes.F2I: case Opcodes.ARRAYLENGTH: case Opcodes.INSTANCEOF: pop(1); push(INTEGER); break; case Opcodes.LCMP: case Opcodes.DCMPL: case Opcodes.DCMPG: pop(4); push(INTEGER); break; case Opcodes.JSR: case Opcodes.RET: throw new RuntimeException("JSR/RET are not supported with computeFrames option"); case Opcodes.GETSTATIC: push(cw, item.strVal3); break; case Opcodes.PUTSTATIC: pop(item.strVal3); break; case Opcodes.GETFIELD: pop(1); push(cw, item.strVal3); break; case Opcodes.PUTFIELD: pop(item.strVal3); pop(); break; case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESTATIC: case Opcodes.INVOKEINTERFACE: pop(item.strVal3); if (opcode != Opcodes.INVOKESTATIC) { t1 = pop(); if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') { init(t1); } } push(cw, item.strVal3); break; case Opcodes.INVOKEDYNAMIC: pop(item.strVal2); push(cw, item.strVal2); break; case Opcodes.NEW: push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); break; case Opcodes.NEWARRAY: pop(); switch (arg) { case Opcodes.T_BOOLEAN: push(ARRAY_OF | BOOLEAN); break; case Opcodes.T_CHAR: push(ARRAY_OF | CHAR); break; case Opcodes.T_BYTE: push(ARRAY_OF | BYTE); break; case Opcodes.T_SHORT: push(ARRAY_OF | SHORT); break; case Opcodes.T_INT: push(ARRAY_OF | INTEGER); break; case Opcodes.T_FLOAT: push(ARRAY_OF | FLOAT); break; case Opcodes.T_DOUBLE: push(ARRAY_OF | DOUBLE); break; // case Opcodes.T_LONG: default: push(ARRAY_OF | LONG); break; } break; case Opcodes.ANEWARRAY: String s = item.strVal1; pop(); if (s.charAt(0) == '[') { push(cw, '[' + s); } else { push(ARRAY_OF | OBJECT | cw.addType(s)); } break; case Opcodes.CHECKCAST: s = item.strVal1; pop(); if (s.charAt(0) == '[') { push(cw, s); } else { push(OBJECT | cw.addType(s)); } break; // case Opcodes.MULTIANEWARRAY: default: pop(arg); push(cw, item.strVal1); break; } } /** * Merges the input frame of the given basic block with the input and output * frames of this basic block. Returns true if the input frame of * the given label has been changed by this operation. * * @param cw the ClassWriter to which this label belongs. * @param frame the basic block whose input frame must be updated. * @param edge the kind of the {@link Edge} between this label and 'label'. * See {@link Edge#info}. * @return true if the input frame of the given label has been * changed by this operation. */ boolean merge(final ClassWriter cw, final Frame frame, final int edge) { boolean changed = false; int i, s, dim, kind, t; int nLocal = inputLocals.length; int nStack = inputStack.length; if (frame.inputLocals == null) { frame.inputLocals = new int[nLocal]; changed = true; } for (i = 0; i < nLocal; ++i) { if (outputLocals != null && i < outputLocals.length) { s = outputLocals[i]; if (s == 0) { t = inputLocals[i]; } else { dim = s & DIM; kind = s & KIND; if (kind == BASE) { t = s; } else { if (kind == LOCAL) { t = dim + inputLocals[s & VALUE]; } else { t = dim + inputStack[nStack - (s & VALUE)]; } if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { t = TOP; } } } } else { t = inputLocals[i]; } if (initializations != null) { t = init(cw, t); } changed |= merge(cw, t, frame.inputLocals, i); } if (edge > 0) { for (i = 0; i < nLocal; ++i) { t = inputLocals[i]; changed |= merge(cw, t, frame.inputLocals, i); } if (frame.inputStack == null) { frame.inputStack = new int[1]; changed = true; } changed |= merge(cw, edge, frame.inputStack, 0); return changed; } int nInputStack = inputStack.length + owner.inputStackTop; if (frame.inputStack == null) { frame.inputStack = new int[nInputStack + outputStackTop]; changed = true; } for (i = 0; i < nInputStack; ++i) { t = inputStack[i]; if (initializations != null) { t = init(cw, t); } changed |= merge(cw, t, frame.inputStack, i); } for (i = 0; i < outputStackTop; ++i) { s = outputStack[i]; dim = s & DIM; kind = s & KIND; if (kind == BASE) { t = s; } else { if (kind == LOCAL) { t = dim + inputLocals[s & VALUE]; } else { t = dim + inputStack[nStack - (s & VALUE)]; } if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { t = TOP; } } if (initializations != null) { t = init(cw, t); } changed |= merge(cw, t, frame.inputStack, nInputStack + i); } return changed; } /** * Merges the type at the given index in the given type array with the given * type. Returns true if the type array has been modified by this * operation. * * @param cw the ClassWriter to which this label belongs. * @param t the type with which the type array element must be merged. * @param types an array of types. * @param index the index of the type that must be merged in 'types'. * @return true if the type array has been modified by this * operation. */ private static boolean merge( final ClassWriter cw, int t, final int[] types, final int index) { int u = types[index]; if (u == t) { // if the types are equal, merge(u,t)=u, so there is no change return false; } if ((t & ~DIM) == NULL) { if (u == NULL) { return false; } t = NULL; } if (u == 0) { // if types[index] has never been assigned, merge(u,t)=t types[index] = t; return true; } int v; if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { // if u is a reference type of any dimension if (t == NULL) { // if t is the NULL type, merge(u,t)=u, so there is no change return false; } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { if ((u & BASE_KIND) == OBJECT) { // if t is also a reference type, and if u and t have the // same dimension merge(u,t) = dim(t) | common parent of the // element types of u and t v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); } else { // if u and t are array types, but not with the same element // type, merge(u,t)=java/lang/Object v = OBJECT | cw.addType("java/lang/Object"); } } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { // if t is any other reference or array type, // merge(u,t)=java/lang/Object v = OBJECT | cw.addType("java/lang/Object"); } else { // if t is any other type, merge(u,t)=TOP v = TOP; } } else if (u == NULL) { // if u is the NULL type, merge(u,t)=t, // or TOP if t is not a reference type v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; } else { // if u is any other type, merge(u,t)=TOP whatever t v = TOP; } if (u != v) { types[index] = v; return true; } return false; } } asm-3.3.2/src/org/objectweb/asm/Attribute.java0000644000175000017500000002314710635277351021165 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A non standard class, field, method or code attribute. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class Attribute { /** * The type of this attribute. */ public final String type; /** * The raw value of this attribute, used only for unknown attributes. */ byte[] value; /** * The next attribute in this attribute list. May be null. */ Attribute next; /** * Constructs a new empty attribute. * * @param type the type of the attribute. */ protected Attribute(final String type) { this.type = type; } /** * Returns true if this type of attribute is unknown. The default * implementation of this method always returns true. * * @return true if this type of attribute is unknown. */ public boolean isUnknown() { return true; } /** * Returns true if this type of attribute is a code attribute. * * @return true if this type of attribute is a code attribute. */ public boolean isCodeAttribute() { return false; } /** * Returns the labels corresponding to this attribute. * * @return the labels corresponding to this attribute, or null if * this attribute is not a code attribute that contains labels. */ protected Label[] getLabels() { return null; } /** * Reads a {@link #type type} attribute. This method must return a new * {@link Attribute} object, of type {@link #type type}, corresponding to * the len bytes starting at the given offset, in the given class * reader. * * @param cr the class that contains the attribute to be read. * @param off index of the first byte of the attribute's content in {@link * ClassReader#b cr.b}. The 6 attribute header bytes, containing the * type and the length of the attribute, are not taken into account * here. * @param len the length of the attribute's content. * @param buf buffer to be used to call * {@link ClassReader#readUTF8 readUTF8}, * {@link ClassReader#readClass(int,char[]) readClass} or * {@link ClassReader#readConst readConst}. * @param codeOff index of the first byte of code's attribute content in * {@link ClassReader#b cr.b}, or -1 if the attribute to be read is * not a code attribute. The 6 attribute header bytes, containing the * type and the length of the attribute, are not taken into account * here. * @param labels the labels of the method's code, or null if the * attribute to be read is not a code attribute. * @return a new {@link Attribute} object corresponding to the given * bytes. */ protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { Attribute attr = new Attribute(type); attr.value = new byte[len]; System.arraycopy(cr.b, off, attr.value, 0, len); return attr; } /** * Returns the byte array form of this attribute. * * @param cw the class to which this attribute must be added. This parameter * can be used to add to the constant pool of this class the items * that corresponds to this attribute. * @param code the bytecode of the method corresponding to this code * attribute, or null if this attribute is not a code * attributes. * @param len the length of the bytecode of the method corresponding to this * code attribute, or null if this attribute is not a code * attribute. * @param maxStack the maximum stack size of the method corresponding to * this code attribute, or -1 if this attribute is not a code * attribute. * @param maxLocals the maximum number of local variables of the method * corresponding to this code attribute, or -1 if this attribute is * not a code attribute. * @return the byte array form of this attribute. */ protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { ByteVector v = new ByteVector(); v.data = value; v.length = value.length; return v; } /** * Returns the length of the attribute list that begins with this attribute. * * @return the length of the attribute list that begins with this attribute. */ final int getCount() { int count = 0; Attribute attr = this; while (attr != null) { count += 1; attr = attr.next; } return count; } /** * Returns the size of all the attributes in this attribute list. * * @param cw the class writer to be used to convert the attributes into byte * arrays, with the {@link #write write} method. * @param code the bytecode of the method corresponding to these code * attributes, or null if these attributes are not code * attributes. * @param len the length of the bytecode of the method corresponding to * these code attributes, or null if these attributes are * not code attributes. * @param maxStack the maximum stack size of the method corresponding to * these code attributes, or -1 if these attributes are not code * attributes. * @param maxLocals the maximum number of local variables of the method * corresponding to these code attributes, or -1 if these attributes * are not code attributes. * @return the size of all the attributes in this attribute list. This size * includes the size of the attribute headers. */ final int getSize( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { Attribute attr = this; int size = 0; while (attr != null) { cw.newUTF8(attr.type); size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; attr = attr.next; } return size; } /** * Writes all the attributes of this attribute list in the given byte * vector. * * @param cw the class writer to be used to convert the attributes into byte * arrays, with the {@link #write write} method. * @param code the bytecode of the method corresponding to these code * attributes, or null if these attributes are not code * attributes. * @param len the length of the bytecode of the method corresponding to * these code attributes, or null if these attributes are * not code attributes. * @param maxStack the maximum stack size of the method corresponding to * these code attributes, or -1 if these attributes are not code * attributes. * @param maxLocals the maximum number of local variables of the method * corresponding to these code attributes, or -1 if these attributes * are not code attributes. * @param out where the attributes must be written. */ final void put( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals, final ByteVector out) { Attribute attr = this; while (attr != null) { ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); out.putShort(cw.newUTF8(attr.type)).putInt(b.length); out.putByteArray(b.data, 0, b.length); attr = attr.next; } } } asm-3.3.2/src/org/objectweb/asm/MethodWriter.java0000644000175000017500000030363611541415063021632 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A {@link MethodVisitor} that generates methods in bytecode form. Each visit * method of this class appends the bytecode corresponding to the visited * instruction to a byte vector, in the order these methods are called. * * @author Eric Bruneton * @author Eugene Kuleshov */ class MethodWriter implements MethodVisitor { /** * Pseudo access flag used to denote constructors. */ static final int ACC_CONSTRUCTOR = 262144; /** * Frame has exactly the same locals as the previous stack map frame and * number of stack items is zero. */ static final int SAME_FRAME = 0; // to 63 (0-3f) /** * Frame has exactly the same locals as the previous stack map frame and * number of stack items is 1 */ static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) /** * Reserved for future use */ static final int RESERVED = 128; /** * Frame has exactly the same locals as the previous stack map frame and * number of stack items is 1. Offset is bigger then 63; */ static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 /** * Frame where current locals are the same as the locals in the previous * frame, except that the k last locals are absent. The value of k is given * by the formula 251-frame_type. */ static final int CHOP_FRAME = 248; // to 250 (f8-fA) /** * Frame has exactly the same locals as the previous stack map frame and * number of stack items is zero. Offset is bigger then 63; */ static final int SAME_FRAME_EXTENDED = 251; // fb /** * Frame where current locals are the same as the locals in the previous * frame, except that k additional locals are defined. The value of k is * given by the formula frame_type-251. */ static final int APPEND_FRAME = 252; // to 254 // fc-fe /** * Full frame */ static final int FULL_FRAME = 255; // ff /** * Indicates that the stack map frames must be recomputed from scratch. In * this case the maximum stack size and number of local variables is also * recomputed from scratch. * * @see #compute */ private static final int FRAMES = 0; /** * Indicates that the maximum stack size and number of local variables must * be automatically computed. * * @see #compute */ private static final int MAXS = 1; /** * Indicates that nothing must be automatically computed. * * @see #compute */ private static final int NOTHING = 2; /** * Next method writer (see {@link ClassWriter#firstMethod firstMethod}). */ MethodWriter next; /** * The class writer to which this method must be added. */ final ClassWriter cw; /** * Access flags of this method. */ private int access; /** * The index of the constant pool item that contains the name of this * method. */ private final int name; /** * The index of the constant pool item that contains the descriptor of this * method. */ private final int desc; /** * The descriptor of this method. */ private final String descriptor; /** * The signature of this method. */ String signature; /** * If not zero, indicates that the code of this method must be copied from * the ClassReader associated to this writer in cw.cr. More * precisely, this field gives the index of the first byte to copied from * cw.cr.b. */ int classReaderOffset; /** * If not zero, indicates that the code of this method must be copied from * the ClassReader associated to this writer in cw.cr. More * precisely, this field gives the number of bytes to copied from * cw.cr.b. */ int classReaderLength; /** * Number of exceptions that can be thrown by this method. */ int exceptionCount; /** * The exceptions that can be thrown by this method. More precisely, this * array contains the indexes of the constant pool items that contain the * internal names of these exception classes. */ int[] exceptions; /** * The annotation default attribute of this method. May be null. */ private ByteVector annd; /** * The runtime visible annotations of this method. May be null. */ private AnnotationWriter anns; /** * The runtime invisible annotations of this method. May be null. */ private AnnotationWriter ianns; /** * The runtime visible parameter annotations of this method. May be * null. */ private AnnotationWriter[] panns; /** * The runtime invisible parameter annotations of this method. May be * null. */ private AnnotationWriter[] ipanns; /** * The number of synthetic parameters of this method. */ private int synthetics; /** * The non standard attributes of the method. */ private Attribute attrs; /** * The bytecode of this method. */ private ByteVector code = new ByteVector(); /** * Maximum stack size of this method. */ private int maxStack; /** * Maximum number of local variables for this method. */ private int maxLocals; /** * Number of local variables in the current stack map frame. */ private int currentLocals; /** * Number of stack map frames in the StackMapTable attribute. */ private int frameCount; /** * The StackMapTable attribute. */ private ByteVector stackMap; /** * The offset of the last frame that was written in the StackMapTable * attribute. */ private int previousFrameOffset; /** * The last frame that was written in the StackMapTable attribute. * * @see #frame */ private int[] previousFrame; /** * Index of the next element to be added in {@link #frame}. */ private int frameIndex; /** * The current stack map frame. The first element contains the offset of the * instruction to which the frame corresponds, the second element is the * number of locals and the third one is the number of stack elements. The * local variables start at index 3 and are followed by the operand stack * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = * nStack, frame[3] = nLocal. All types are encoded as integers, with the * same format as the one used in {@link Label}, but limited to BASE types. */ private int[] frame; /** * Number of elements in the exception handler list. */ private int handlerCount; /** * The first element in the exception handler list. */ private Handler firstHandler; /** * The last element in the exception handler list. */ private Handler lastHandler; /** * Number of entries in the LocalVariableTable attribute. */ private int localVarCount; /** * The LocalVariableTable attribute. */ private ByteVector localVar; /** * Number of entries in the LocalVariableTypeTable attribute. */ private int localVarTypeCount; /** * The LocalVariableTypeTable attribute. */ private ByteVector localVarType; /** * Number of entries in the LineNumberTable attribute. */ private int lineNumberCount; /** * The LineNumberTable attribute. */ private ByteVector lineNumber; /** * The non standard attributes of the method's code. */ private Attribute cattrs; /** * Indicates if some jump instructions are too small and need to be resized. */ private boolean resize; /** * The number of subroutines in this method. */ private int subroutines; // ------------------------------------------------------------------------ /* * 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. */ /** * Indicates what must be automatically computed. * * @see #FRAMES * @see #MAXS * @see #NOTHING */ private final int compute; /** * A list of labels. This list is the list of basic blocks in the method, * i.e. a list of Label objects linked to each other by their * {@link Label#successor} field, in the order they are visited by * {@link MethodVisitor#visitLabel}, and starting with the first basic block. */ private Label labels; /** * The previous basic block. */ private Label previousBlock; /** * The current basic block. */ private Label currentBlock; /** * 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#inputStackTop 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#inputStackTop beginStackSize} of the current basic * block plus stackSize. */ private int maxStackSize; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructs a new {@link MethodWriter}. * * @param cw the class writer in which the method must be added. * @param access the method's access flags (see {@link Opcodes}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type}). * @param signature the method's signature. May be null. * @param exceptions the internal names of the method's exceptions. May be * null. * @param computeMaxs true if the maximum stack size and number * of local variables must be automatically computed. * @param computeFrames true if the stack map tables must be * recomputed from scratch. */ MethodWriter( final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions, final boolean computeMaxs, final boolean computeFrames) { if (cw.firstMethod == null) { cw.firstMethod = this; } else { cw.lastMethod.next = this; } cw.lastMethod = this; this.cw = cw; this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; if (ClassReader.SIGNATURES) { this.signature = signature; } if (exceptions != null && exceptions.length > 0) { exceptionCount = exceptions.length; this.exceptions = new int[exceptionCount]; for (int i = 0; i < exceptionCount; ++i) { this.exceptions[i] = cw.newClass(exceptions[i]); } } this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); if (computeMaxs || computeFrames) { if (computeFrames && "".equals(name)) { this.access |= ACC_CONSTRUCTOR; } // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { --size; } maxLocals = size; currentLocals = size; // creates and visits the label for the first basic block labels = new Label(); labels.status |= Label.PUSHED; visitLabel(labels); } } // ------------------------------------------------------------------------ // Implementation of the MethodVisitor interface // ------------------------------------------------------------------------ public AnnotationVisitor visitAnnotationDefault() { if (!ClassReader.ANNOTATIONS) { return null; } annd = new ByteVector(); return new AnnotationWriter(cw, false, annd, null, 0); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(cw.newUTF8(desc)).putShort(0); AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); if (visible) { aw.next = anns; anns = aw; } else { aw.next = ianns; ianns = aw; } return aw; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } ByteVector bv = new ByteVector(); if ("Ljava/lang/Synthetic;".equals(desc)) { // workaround for a bug in javac with synthetic parameters // see ClassReader.readParameterAnnotations synthetics = Math.max(synthetics, parameter + 1); return new AnnotationWriter(cw, false, bv, null, 0); } // write type, and reserve space for values count bv.putShort(cw.newUTF8(desc)).putShort(0); AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); if (visible) { if (panns == null) { panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; } aw.next = panns[parameter]; panns[parameter] = aw; } else { if (ipanns == null) { ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; } aw.next = ipanns[parameter]; ipanns[parameter] = aw; } return aw; } public void visitAttribute(final Attribute attr) { if (attr.isCodeAttribute()) { attr.next = cattrs; cattrs = attr; } else { attr.next = attrs; attrs = attr; } } public void visitCode() { } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { if (!ClassReader.FRAMES || compute == FRAMES) { return; } if (type == Opcodes.F_NEW) { currentLocals = nLocal; startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { frame[frameIndex++] = Frame.OBJECT | cw.addType((String) local[i]); } else if (local[i] instanceof Integer) { frame[frameIndex++] = ((Integer) local[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) local[i]).position); } } for (int i = 0; i < nStack; ++i) { if (stack[i] instanceof String) { frame[frameIndex++] = Frame.OBJECT | cw.addType((String) stack[i]); } else if (stack[i] instanceof Integer) { frame[frameIndex++] = ((Integer) stack[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) stack[i]).position); } } endFrame(); } else { int delta; if (stackMap == null) { stackMap = new ByteVector(); delta = code.length; } else { delta = code.length - previousFrameOffset - 1; if (delta < 0) { if (type == Opcodes.F_SAME) { return; } else { throw new IllegalStateException(); } } } switch (type) { case Opcodes.F_FULL: currentLocals = nLocal; stackMap.putByte(FULL_FRAME) .putShort(delta) .putShort(nLocal); for (int i = 0; i < nLocal; ++i) { writeFrameType(local[i]); } stackMap.putShort(nStack); for (int i = 0; i < nStack; ++i) { writeFrameType(stack[i]); } break; case Opcodes.F_APPEND: currentLocals += nLocal; stackMap.putByte(SAME_FRAME_EXTENDED + nLocal) .putShort(delta); for (int i = 0; i < nLocal; ++i) { writeFrameType(local[i]); } break; case Opcodes.F_CHOP: currentLocals -= nLocal; stackMap.putByte(SAME_FRAME_EXTENDED - nLocal) .putShort(delta); break; case Opcodes.F_SAME: if (delta < 64) { stackMap.putByte(delta); } else { stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); } break; case Opcodes.F_SAME1: if (delta < 64) { stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); } else { stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) .putShort(delta); } writeFrameType(stack[0]); break; } previousFrameOffset = code.length; ++frameCount; } maxStack = Math.max(maxStack, nStack); maxLocals = Math.max(maxLocals, currentLocals); } public void visitInsn(final int opcode) { // adds the instruction to the bytecode of the method code.putByte(opcode); // update currentBlock // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, 0, null, null); } else { // updates current and max stack sizes int size = stackSize + Frame.SIZE[opcode]; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // if opcode == ATHROW or xRETURN, ends current block (no successor) if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { noSuccessor(); } } } public void visitIntInsn(final int opcode, final int operand) { // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, operand, null, null); } else if (opcode != Opcodes.NEWARRAY) { // updates current and max stack sizes only for NEWARRAY // (stack size variation = 0 for BIPUSH or SIPUSH) int size = stackSize + 1; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } } // adds the instruction to the bytecode of the method if (opcode == Opcodes.SIPUSH) { code.put12(opcode, operand); } else { // BIPUSH or NEWARRAY code.put11(opcode, operand); } } public void visitVarInsn(final int opcode, final int var) { // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, var, null, null); } else { // updates current and max stack sizes if (opcode == Opcodes.RET) { // no stack change, but end of current block (no successor) currentBlock.status |= Label.RET; // save 'stackSize' here for future use // (see {@link #findSubroutineSuccessors}) currentBlock.inputStackTop = stackSize; noSuccessor(); } else { // xLOAD or xSTORE int size = stackSize + Frame.SIZE[opcode]; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } } } if (compute != NOTHING) { // updates max locals int n; if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { n = var + 2; } else { n = var + 1; } if (n > maxLocals) { maxLocals = n; } } // adds the instruction to the bytecode of the method if (var < 4 && opcode != Opcodes.RET) { int opt; if (opcode < Opcodes.ISTORE) { /* ILOAD_0 */ opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; } else { /* ISTORE_0 */ opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; } code.putByte(opt); } else if (var >= 256) { code.putByte(196 /* WIDE */).put12(opcode, var); } else { code.put11(opcode, var); } if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { visitLabel(new Label()); } } public void visitTypeInsn(final int opcode, final String type) { Item i = cw.newClassItem(type); // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, code.length, cw, i); } else if (opcode == Opcodes.NEW) { // updates current and max stack sizes only if opcode == NEW // (no stack change 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, i.index); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { Item i = cw.newFieldItem(owner, name, desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, 0, cw, i); } else { int size; // computes the stack size variation char c = desc.charAt(0); switch (opcode) { case Opcodes.GETSTATIC: size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); break; case Opcodes.PUTSTATIC: size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); break; case Opcodes.GETFIELD: size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); break; // case Constants.PUTFIELD: default: size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); break; } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } } // adds the instruction to the bytecode of the method code.put12(opcode, i.index); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { boolean itf = opcode == Opcodes.INVOKEINTERFACE; Item i = (opcode == Opcodes.INVOKEDYNAMIC) ? cw.newNameTypeItem(name, desc): cw.newMethodItem(owner, name, desc, itf); int argSize = i.intVal; // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, 0, cw, i); } else { /* * 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 = Type.getArgumentsAndReturnSizes(desc); // ... and we save them in order // not to recompute them in the future i.intVal = argSize; } int size; if (opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKEDYNAMIC) { size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; } else { size = stackSize - (argSize >> 2) + (argSize & 0x03); } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } } // adds the instruction to the bytecode of the method if (itf) { if (argSize == 0) { argSize = Type.getArgumentsAndReturnSizes(desc); i.intVal = argSize; } code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); } else { code.put12(opcode, i.index); if (opcode==Opcodes.INVOKEDYNAMIC) { code.putShort(0); } } } public void visitJumpInsn(final int opcode, final Label label) { Label nextInsn = null; // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(opcode, 0, null, null); // 'label' is the target of a jump instruction label.getFirst().status |= Label.TARGET; // adds 'label' as a successor of this basic block addSuccessor(Edge.NORMAL, label); if (opcode != Opcodes.GOTO) { // creates a Label for the next basic block nextInsn = new Label(); } } else { if (opcode == Opcodes.JSR) { if ((label.status & Label.SUBROUTINE) == 0) { label.status |= Label.SUBROUTINE; ++subroutines; } currentBlock.status |= Label.JSR; addSuccessor(stackSize + 1, label); // creates a Label for the next basic block nextInsn = new Label(); /* * note that, by construction in this method, a JSR block * has at least two successors in the control flow graph: * the first one leads the next instruction after the JSR, * while the second one leads to the JSR target. */ } else { // updates current stack size (max stack size unchanged // because stack size variation always negative in this // case) stackSize += Frame.SIZE[opcode]; addSuccessor(stackSize, label); } } } // adds the instruction to the bytecode of the method if ((label.status & Label.RESOLVED) != 0 && 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 == Opcodes.GOTO) { code.putByte(200); // GOTO_W } else if (opcode == Opcodes.JSR) { code.putByte(201); // JSR_W } else { // if the IF instruction is transformed into IFNOT GOTO_W the // next instruction becomes the target of the IFNOT instruction if (nextInsn != null) { nextInsn.status |= Label.TARGET; } code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.putShort(8); // jump offset code.putByte(200); // GOTO_W } label.put(this, code, code.length - 1, true); } else { /* * case of a backward jump with an offset >= -32768, or of a forward * jump with, of course, an unknown offset. In these cases we store * the offset in 2 bytes (which will be increased in * resizeInstructions, if needed). */ code.putByte(opcode); label.put(this, code, code.length - 1, false); } if (currentBlock != null) { if (nextInsn != null) { // if the jump instruction is not a GOTO, the next instruction // is also a successor of this instruction. Calling visitLabel // adds the label of this next instruction as a successor of the // current block, and starts a new basic block visitLabel(nextInsn); } if (opcode == Opcodes.GOTO) { noSuccessor(); } } } public void visitLabel(final Label label) { // resolves previous forward references to label, if any resize |= label.resolve(this, code.length, code.data); // updates currentBlock if ((label.status & Label.DEBUG) != 0) { return; } if (compute == FRAMES) { if (currentBlock != null) { if (label.position == currentBlock.position) { // successive labels, do not start a new basic block currentBlock.status |= (label.status & Label.TARGET); label.frame = currentBlock.frame; return; } // ends current block (with one new successor) addSuccessor(Edge.NORMAL, label); } // begins a new current block currentBlock = label; if (label.frame == null) { label.frame = new Frame(); label.frame.owner = label; } // updates the basic block list if (previousBlock != null) { if (label.position == previousBlock.position) { previousBlock.status |= (label.status & Label.TARGET); label.frame = previousBlock.frame; currentBlock = previousBlock; return; } previousBlock.successor = label; } previousBlock = label; } else if (compute == MAXS) { if (currentBlock != null) { // ends current block (with one new successor) currentBlock.outputStackMax = maxStackSize; addSuccessor(stackSize, label); } // begins a new current block currentBlock = label; // resets the relative current and max stack sizes stackSize = 0; maxStackSize = 0; // updates the basic block list if (previousBlock != null) { previousBlock.successor = label; } previousBlock = label; } } public void visitLdcInsn(final Object cst) { Item i = cw.newConstItem(cst); // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); } else { int size; // computes the stack size variation if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { size = stackSize + 2; } else { size = stackSize + 1; } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } } // adds the instruction to the bytecode of the method int index = i.index; if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { code.put12(20 /* LDC2_W */, index); } else if (index >= 256) { code.put12(19 /* LDC_W */, index); } else { code.put11(Opcodes.LDC, index); } } public void visitIincInsn(final int var, final int increment) { if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(Opcodes.IINC, var, null, null); } } if (compute != NOTHING) { // updates max locals int n = var + 1; if (n > maxLocals) { maxLocals = n; } } // adds the instruction to the bytecode of the method if ((var > 255) || (increment > 127) || (increment < -128)) { code.putByte(196 /* WIDE */) .put12(Opcodes.IINC, var) .putShort(increment); } else { code.putByte(Opcodes.IINC).put11(var, increment); } } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.TABLESWITCH); code.putByteArray(null, 0, (4 - code.length % 4) % 4); dflt.put(this, code, source, true); code.putInt(min).putInt(max); for (int i = 0; i < labels.length; ++i) { labels[i].put(this, code, source, true); } // updates currentBlock visitSwitchInsn(dflt, labels); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.LOOKUPSWITCH); code.putByteArray(null, 0, (4 - code.length % 4) % 4); dflt.put(this, code, source, true); code.putInt(labels.length); for (int i = 0; i < labels.length; ++i) { code.putInt(keys[i]); labels[i].put(this, code, source, true); } // updates currentBlock visitSwitchInsn(dflt, labels); } private void visitSwitchInsn(final Label dflt, final Label[] labels) { // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); // adds current block successors addSuccessor(Edge.NORMAL, dflt); dflt.getFirst().status |= Label.TARGET; for (int i = 0; i < labels.length; ++i) { addSuccessor(Edge.NORMAL, labels[i]); labels[i].getFirst().status |= Label.TARGET; } } else { // updates current stack size (max stack size unchanged) --stackSize; // adds current block successors addSuccessor(stackSize, dflt); for (int i = 0; i < labels.length; ++i) { addSuccessor(stackSize, labels[i]); } } // ends current block noSuccessor(); } } public void visitMultiANewArrayInsn(final String desc, final int dims) { Item i = cw.newClassItem(desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { if (compute == FRAMES) { currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); } else { // updates current stack size (max stack size unchanged because // stack size variation always negative or null) stackSize += 1 - dims; } } // adds the instruction to the bytecode of the method code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { ++handlerCount; Handler h = new Handler(); h.start = start; h.end = end; h.handler = handler; h.desc = type; h.type = type != null ? cw.newClass(type) : 0; if (lastHandler == null) { firstHandler = h; } else { lastHandler.next = h; } lastHandler = h; } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { if (signature != null) { if (localVarType == null) { localVarType = new ByteVector(); } ++localVarTypeCount; localVarType.putShort(start.position) .putShort(end.position - start.position) .putShort(cw.newUTF8(name)) .putShort(cw.newUTF8(signature)) .putShort(index); } if (localVar == null) { localVar = new ByteVector(); } ++localVarCount; localVar.putShort(start.position) .putShort(end.position - start.position) .putShort(cw.newUTF8(name)) .putShort(cw.newUTF8(desc)) .putShort(index); if (compute != NOTHING) { // updates max locals char c = desc.charAt(0); int n = index + (c == 'J' || c == 'D' ? 2 : 1); if (n > maxLocals) { maxLocals = n; } } } public void visitLineNumber(final int line, final Label start) { if (lineNumber == null) { lineNumber = new ByteVector(); } ++lineNumberCount; lineNumber.putShort(start.position); lineNumber.putShort(line); } public void visitMaxs(final int maxStack, final int maxLocals) { if (ClassReader.FRAMES && compute == FRAMES) { // completes the control flow graph with exception handler blocks Handler handler = firstHandler; while (handler != null) { Label l = handler.start.getFirst(); Label h = handler.handler.getFirst(); Label e = handler.end.getFirst(); // computes the kind of the edges to 'h' String t = handler.desc == null ? "java/lang/Throwable" : handler.desc; int kind = Frame.OBJECT | cw.addType(t); // h is an exception handler h.status |= Label.TARGET; // adds 'h' as a successor of labels between 'start' and 'end' while (l != e) { // creates an edge to 'h' Edge b = new Edge(); b.info = kind; b.successor = h; // adds it to the successors of 'l' b.next = l.successors; l.successors = b; // goes to the next label l = l.successor; } handler = handler.next; } // creates and visits the first (implicit) frame Frame f = labels.frame; Type[] args = Type.getArgumentTypes(descriptor); f.initInputFrame(cw, access, args, this.maxLocals); visitFrame(f); /* * fix point algorithm: mark the first basic block as 'changed' * (i.e. put it in the 'changed' list) and, while there are changed * basic blocks, choose one, mark it as unchanged, and update its * successors (which can be changed in the process). */ int max = 0; Label changed = labels; while (changed != null) { // removes a basic block from the list of changed basic blocks Label l = changed; changed = changed.next; l.next = null; f = l.frame; // a reachable jump target must be stored in the stack map if ((l.status & Label.TARGET) != 0) { l.status |= Label.STORE; } // all visited labels are reachable, by definition l.status |= Label.REACHABLE; // updates the (absolute) maximum stack size int blockMax = f.inputStack.length + l.outputStackMax; if (blockMax > max) { max = blockMax; } // updates the successors of the current basic block Edge e = l.successors; while (e != null) { Label n = e.successor.getFirst(); boolean change = f.merge(cw, n.frame, e.info); if (change && n.next == null) { // if n has changed and is not already in the 'changed' // list, adds it to this list n.next = changed; changed = n; } e = e.next; } } // visits all the frames that must be stored in the stack map Label l = labels; while (l != null) { f = l.frame; if ((l.status & Label.STORE) != 0) { visitFrame(f); } if ((l.status & Label.REACHABLE) == 0) { // finds start and end of dead basic block Label k = l.successor; int start = l.position; int end = (k == null ? code.length : k.position) - 1; // if non empty basic block if (end >= start) { max = Math.max(max, 1); // replaces instructions with NOP ... NOP ATHROW for (int i = start; i < end; ++i) { code.data[i] = Opcodes.NOP; } code.data[end] = (byte) Opcodes.ATHROW; // emits a frame for this unreachable block startFrame(start, 0, 1); frame[frameIndex++] = Frame.OBJECT | cw.addType("java/lang/Throwable"); endFrame(); } } l = l.successor; } this.maxStack = max; } else if (compute == MAXS) { // completes the control flow graph with exception handler blocks Handler handler = firstHandler; while (handler != null) { Label l = handler.start; Label h = handler.handler; Label e = handler.end; // adds 'h' as a successor of labels between 'start' and 'end' while (l != e) { // creates an edge to 'h' Edge b = new Edge(); b.info = Edge.EXCEPTION; b.successor = h; // adds it to the successors of 'l' if ((l.status & Label.JSR) == 0) { b.next = l.successors; l.successors = b; } else { // if l is a JSR block, adds b after the first two edges // to preserve the hypothesis about JSR block successors // order (see {@link #visitJumpInsn}) b.next = l.successors.next.next; l.successors.next.next = b; } // goes to the next label l = l.successor; } handler = handler.next; } if (subroutines > 0) { // completes the control flow graph with the RET successors /* * first step: finds the subroutines. This step determines, for * each basic block, to which subroutine(s) it belongs. */ // finds the basic blocks that belong to the "main" subroutine int id = 0; labels.visitSubroutine(null, 1, subroutines); // finds the basic blocks that belong to the real subroutines Label l = labels; while (l != null) { if ((l.status & Label.JSR) != 0) { // the subroutine is defined by l's TARGET, not by l Label subroutine = l.successors.next.successor; // if this subroutine has not been visited yet... if ((subroutine.status & Label.VISITED) == 0) { // ...assigns it a new id and finds its basic blocks id += 1; subroutine.visitSubroutine(null, (id / 32L) << 32 | (1L << (id % 32)), subroutines); } } l = l.successor; } // second step: finds the successors of RET blocks l = labels; while (l != null) { if ((l.status & Label.JSR) != 0) { Label L = labels; while (L != null) { L.status &= ~Label.VISITED2; L = L.successor; } // the subroutine is defined by l's TARGET, not by l Label subroutine = l.successors.next.successor; subroutine.visitSubroutine(l, 0, subroutines); } l = l.successor; } } /* * 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#inputStackTop} of the * blocks in the block stack are the true (non relative) beginning * stack sizes of these blocks. */ int max = 0; Label stack = labels; 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.inputStackTop; int blockMax = start + l.outputStackMax; // updates the global max stack size if (blockMax > max) { max = blockMax; } // analyzes the successors of the block Edge b = l.successors; if ((l.status & Label.JSR) != 0) { // ignores the first edge of JSR blocks (virtual successor) b = b.next; } while (b != null) { l = b.successor; // if this successor has not already been pushed... if ((l.status & Label.PUSHED) == 0) { // computes its true beginning stack size... l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start + b.info; // ...and pushes it onto the stack l.status |= Label.PUSHED; l.next = stack; stack = l; } b = b.next; } } this.maxStack = Math.max(maxStack, max); } else { this.maxStack = maxStack; this.maxLocals = maxLocals; } } public void visitEnd() { } // ------------------------------------------------------------------------ // Utility methods: control flow analysis algorithm // ------------------------------------------------------------------------ /** * Adds a successor to the {@link #currentBlock currentBlock} block. * * @param info information about the control flow edge to be added. * @param successor the successor block to be added to the current block. */ private void addSuccessor(final int info, final Label successor) { // creates and initializes an Edge object... Edge b = new Edge(); b.info = info; b.successor = successor; // ...and adds it to the successor list of the currentBlock block b.next = currentBlock.successors; currentBlock.successors = b; } /** * Ends the current basic block. This method must be used in the case where * the current basic block does not have any successor. */ private void noSuccessor() { if (compute == FRAMES) { Label l = new Label(); l.frame = new Frame(); l.frame.owner = l; l.resolve(this, code.length, code.data); previousBlock.successor = l; previousBlock = l; } else { currentBlock.outputStackMax = maxStackSize; } currentBlock = null; } // ------------------------------------------------------------------------ // Utility methods: stack map frames // ------------------------------------------------------------------------ /** * Visits a frame that has been computed from scratch. * * @param f the frame that must be visited. */ private void visitFrame(final Frame f) { int i, t; int nTop = 0; int nLocal = 0; int nStack = 0; int[] locals = f.inputLocals; int[] stacks = f.inputStack; // computes the number of locals (ignores TOP types that are just after // a LONG or a DOUBLE, and all trailing TOP types) for (i = 0; i < locals.length; ++i) { t = locals[i]; if (t == Frame.TOP) { ++nTop; } else { nLocal += nTop + 1; nTop = 0; } if (t == Frame.LONG || t == Frame.DOUBLE) { ++i; } } // computes the stack size (ignores TOP types that are just after // a LONG or a DOUBLE) for (i = 0; i < stacks.length; ++i) { t = stacks[i]; ++nStack; if (t == Frame.LONG || t == Frame.DOUBLE) { ++i; } } // visits the frame and its content startFrame(f.owner.position, nLocal, nStack); for (i = 0; nLocal > 0; ++i, --nLocal) { t = locals[i]; frame[frameIndex++] = t; if (t == Frame.LONG || t == Frame.DOUBLE) { ++i; } } for (i = 0; i < stacks.length; ++i) { t = stacks[i]; frame[frameIndex++] = t; if (t == Frame.LONG || t == Frame.DOUBLE) { ++i; } } endFrame(); } /** * Starts the visit of a stack map frame. * * @param offset the offset of the instruction to which the frame * corresponds. * @param nLocal the number of local variables in the frame. * @param nStack the number of stack elements in the frame. */ private void startFrame(final int offset, final int nLocal, final int nStack) { int n = 3 + nLocal + nStack; if (frame == null || frame.length < n) { frame = new int[n]; } frame[0] = offset; frame[1] = nLocal; frame[2] = nStack; frameIndex = 3; } /** * Checks if the visit of the current frame {@link #frame} is finished, and * if yes, write it in the StackMapTable attribute. */ private void endFrame() { if (previousFrame != null) { // do not write the first frame if (stackMap == null) { stackMap = new ByteVector(); } writeFrame(); ++frameCount; } previousFrame = frame; frame = null; } /** * Compress and writes the current frame {@link #frame} in the StackMapTable * attribute. */ private void writeFrame() { int clocalsSize = frame[1]; int cstackSize = frame[2]; if ((cw.version & 0xFFFF) < Opcodes.V1_6) { stackMap.putShort(frame[0]).putShort(clocalsSize); writeFrameTypes(3, 3 + clocalsSize); stackMap.putShort(cstackSize); writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); return; } int localsSize = previousFrame[1]; int type = FULL_FRAME; int k = 0; int delta; if (frameCount == 0) { delta = frame[0]; } else { delta = frame[0] - previousFrame[0] - 1; } if (cstackSize == 0) { k = clocalsSize - localsSize; switch (k) { case -3: case -2: case -1: type = CHOP_FRAME; localsSize = clocalsSize; break; case 0: type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; break; case 1: case 2: case 3: type = APPEND_FRAME; break; } } else if (clocalsSize == localsSize && cstackSize == 1) { type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; } if (type != FULL_FRAME) { // verify if locals are the same int l = 3; for (int j = 0; j < localsSize; j++) { if (frame[l] != previousFrame[l]) { type = FULL_FRAME; break; } l++; } } switch (type) { case SAME_FRAME: stackMap.putByte(delta); break; case SAME_LOCALS_1_STACK_ITEM_FRAME: stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); break; case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) .putShort(delta); writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); break; case SAME_FRAME_EXTENDED: stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); break; case CHOP_FRAME: stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); break; case APPEND_FRAME: stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); writeFrameTypes(3 + localsSize, 3 + clocalsSize); break; // case FULL_FRAME: default: stackMap.putByte(FULL_FRAME) .putShort(delta) .putShort(clocalsSize); writeFrameTypes(3, 3 + clocalsSize); stackMap.putShort(cstackSize); writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); } } /** * Writes some types of the current frame {@link #frame} into the * StackMapTableAttribute. This method converts types from the format used * in {@link Label} to the format used in StackMapTable attributes. In * particular, it converts type table indexes to constant pool indexes. * * @param start index of the first type in {@link #frame} to write. * @param end index of last type in {@link #frame} to write (exclusive). */ private void writeFrameTypes(final int start, final int end) { for (int i = start; i < end; ++i) { int t = frame[i]; int d = t & Frame.DIM; if (d == 0) { int v = t & Frame.BASE_VALUE; switch (t & Frame.BASE_KIND) { case Frame.OBJECT: stackMap.putByte(7) .putShort(cw.newClass(cw.typeTable[v].strVal1)); break; case Frame.UNINITIALIZED: stackMap.putByte(8).putShort(cw.typeTable[v].intVal); break; default: stackMap.putByte(v); } } else { StringBuffer buf = new StringBuffer(); d >>= 28; while (d-- > 0) { buf.append('['); } if ((t & Frame.BASE_KIND) == Frame.OBJECT) { buf.append('L'); buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); buf.append(';'); } else { switch (t & 0xF) { case 1: buf.append('I'); break; case 2: buf.append('F'); break; case 3: buf.append('D'); break; case 9: buf.append('Z'); break; case 10: buf.append('B'); break; case 11: buf.append('C'); break; case 12: buf.append('S'); break; default: buf.append('J'); } } stackMap.putByte(7).putShort(cw.newClass(buf.toString())); } } } private void writeFrameType(final Object type) { if (type instanceof String) { stackMap.putByte(7).putShort(cw.newClass((String) type)); } else if (type instanceof Integer) { stackMap.putByte(((Integer) type).intValue()); } else { stackMap.putByte(8).putShort(((Label) type).position); } } // ------------------------------------------------------------------------ // Utility methods: dump bytecode array // ------------------------------------------------------------------------ /** * Returns the size of the bytecode of this method. * * @return the size of the bytecode of this method. */ final int getSize() { if (classReaderOffset != 0) { return 6 + classReaderLength; } if (resize) { // replaces the temporary jump opcodes introduced by Label.resolve. if (ClassReader.RESIZE) { resizeInstructions(); } else { throw new RuntimeException("Method code too large!"); } } int size = 8; if (code.length > 0) { if (code.length > 65536) { throw new RuntimeException("Method code too large!"); } cw.newUTF8("Code"); size += 18 + code.length + 8 * handlerCount; if (localVar != null) { cw.newUTF8("LocalVariableTable"); size += 8 + localVar.length; } if (localVarType != null) { cw.newUTF8("LocalVariableTypeTable"); size += 8 + localVarType.length; } if (lineNumber != null) { cw.newUTF8("LineNumberTable"); size += 8 + lineNumber.length; } if (stackMap != null) { boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; cw.newUTF8(zip ? "StackMapTable" : "StackMap"); size += 8 + stackMap.length; } if (cattrs != null) { size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } } if (exceptionCount > 0) { cw.newUTF8("Exceptions"); size += 8 + 2 * exceptionCount; } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { cw.newUTF8("Synthetic"); size += 6; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cw.newUTF8("Deprecated"); size += 6; } if (ClassReader.SIGNATURES && signature != null) { cw.newUTF8("Signature"); cw.newUTF8(signature); size += 8; } if (ClassReader.ANNOTATIONS && annd != null) { cw.newUTF8("AnnotationDefault"); size += 6 + annd.length; } if (ClassReader.ANNOTATIONS && anns != null) { cw.newUTF8("RuntimeVisibleAnnotations"); size += 8 + anns.getSize(); } if (ClassReader.ANNOTATIONS && ianns != null) { cw.newUTF8("RuntimeInvisibleAnnotations"); size += 8 + ianns.getSize(); } if (ClassReader.ANNOTATIONS && panns != null) { cw.newUTF8("RuntimeVisibleParameterAnnotations"); size += 7 + 2 * (panns.length - synthetics); for (int i = panns.length - 1; i >= synthetics; --i) { size += panns[i] == null ? 0 : panns[i].getSize(); } } if (ClassReader.ANNOTATIONS && ipanns != null) { cw.newUTF8("RuntimeInvisibleParameterAnnotations"); size += 7 + 2 * (ipanns.length - synthetics); for (int i = ipanns.length - 1; i >= synthetics; --i) { size += ipanns[i] == null ? 0 : ipanns[i].getSize(); } } if (attrs != null) { size += attrs.getSize(cw, null, 0, -1, -1); } return size; } /** * Puts the bytecode of this method in the given byte vector. * * @param out the byte vector into which the bytecode of this method must be * copied. */ final void put(final ByteVector out) { int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); out.putShort(access & ~mask).putShort(name).putShort(desc); if (classReaderOffset != 0) { out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); return; } int attributeCount = 0; if (code.length > 0) { ++attributeCount; } if (exceptionCount > 0) { ++attributeCount; } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { ++attributeCount; } if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; } if (ClassReader.SIGNATURES && signature != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && annd != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && anns != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && ianns != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && panns != null) { ++attributeCount; } if (ClassReader.ANNOTATIONS && ipanns != null) { ++attributeCount; } if (attrs != null) { attributeCount += attrs.getCount(); } out.putShort(attributeCount); if (code.length > 0) { int size = 12 + code.length + 8 * handlerCount; if (localVar != null) { size += 8 + localVar.length; } if (localVarType != null) { size += 8 + localVarType.length; } if (lineNumber != null) { size += 8 + lineNumber.length; } if (stackMap != null) { size += 8 + stackMap.length; } if (cattrs != null) { size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } out.putShort(cw.newUTF8("Code")).putInt(size); out.putShort(maxStack).putShort(maxLocals); out.putInt(code.length).putByteArray(code.data, 0, code.length); out.putShort(handlerCount); if (handlerCount > 0) { Handler h = firstHandler; while (h != null) { out.putShort(h.start.position) .putShort(h.end.position) .putShort(h.handler.position) .putShort(h.type); h = h.next; } } attributeCount = 0; if (localVar != null) { ++attributeCount; } if (localVarType != null) { ++attributeCount; } if (lineNumber != null) { ++attributeCount; } if (stackMap != null) { ++attributeCount; } if (cattrs != null) { attributeCount += cattrs.getCount(); } out.putShort(attributeCount); if (localVar != null) { out.putShort(cw.newUTF8("LocalVariableTable")); out.putInt(localVar.length + 2).putShort(localVarCount); out.putByteArray(localVar.data, 0, localVar.length); } if (localVarType != null) { out.putShort(cw.newUTF8("LocalVariableTypeTable")); out.putInt(localVarType.length + 2).putShort(localVarTypeCount); out.putByteArray(localVarType.data, 0, localVarType.length); } if (lineNumber != null) { out.putShort(cw.newUTF8("LineNumberTable")); out.putInt(lineNumber.length + 2).putShort(lineNumberCount); out.putByteArray(lineNumber.data, 0, lineNumber.length); } if (stackMap != null) { boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); out.putInt(stackMap.length + 2).putShort(frameCount); out.putByteArray(stackMap.data, 0, stackMap.length); } if (cattrs != null) { cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); } } if (exceptionCount > 0) { out.putShort(cw.newUTF8("Exceptions")) .putInt(2 * exceptionCount + 2); out.putShort(exceptionCount); for (int i = 0; i < exceptionCount; ++i) { out.putShort(exceptions[i]); } } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) { out.putShort(cw.newUTF8("Synthetic")).putInt(0); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } if (ClassReader.SIGNATURES && signature != null) { out.putShort(cw.newUTF8("Signature")) .putInt(2) .putShort(cw.newUTF8(signature)); } if (ClassReader.ANNOTATIONS && annd != null) { out.putShort(cw.newUTF8("AnnotationDefault")); out.putInt(annd.length); out.putByteArray(annd.data, 0, annd.length); } if (ClassReader.ANNOTATIONS && anns != null) { out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } if (ClassReader.ANNOTATIONS && ianns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } if (ClassReader.ANNOTATIONS && panns != null) { out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); AnnotationWriter.put(panns, synthetics, out); } if (ClassReader.ANNOTATIONS && ipanns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); AnnotationWriter.put(ipanns, synthetics, out); } if (attrs != null) { attrs.put(cw, null, 0, -1, -1, out); } } // ------------------------------------------------------------------------ // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) // ------------------------------------------------------------------------ /** * Resizes and replaces the temporary instructions inserted by * {@link Label#resolve} for wide forward jumps, 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. */ private void resizeInstructions() { 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[0]; // copy of indexes int[] allSizes = new int[0]; // copy of sizes boolean[] resize; // instructions to be resized int newOffset; // future offset of a jump instruction resize = new boolean[code.length]; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done int state = 3; do { if (state == 3) { state = 2; } u = 0; while (u < b.length) { int opcode = b[u] & 0xFF; // opcode of current instruction int insert = 0; // bytes to be added after this instruction switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: u += 1; break; case ClassWriter.LABEL_INSN: if (opcode > 201) { // converts temporary opcodes 202 to 217, 218 and // 219 to IFEQ ... JSR (inclusive), IFNULL and // IFNONNULL opcode = opcode < 218 ? opcode - 49 : opcode - 20; label = u + readUnsignedShort(b, u + 1); } else { label = u + readShort(b, u + 1); } newOffset = getNewOffset(allIndexes, allSizes, u, label); if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { if (!resize[u]) { if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { // two additional bytes will be required to // replace this GOTO or JSR instruction with // a GOTO_W or a JSR_W insert = 2; } else { // five additional bytes will be required to // replace this IFxxx 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 == Opcodes.IINC) { u += 6; } else { u += 4; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: u += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: u += 3; break; case ClassWriter.ITFDYNMETH_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) { int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: newCode.putByte(opcode); u += 1; break; case ClassWriter.LABEL_INSN: if (opcode > 201) { // changes temporary opcodes 202 to 217 (inclusive), 218 // and 219 to IFEQ ... JSR (inclusive), IFNULL and // IFNONNULL opcode = opcode < 218 ? opcode - 49 : opcode - 20; label = u + readUnsignedShort(b, u + 1); } else { label = u + readShort(b, u + 1); } newOffset = getNewOffset(allIndexes, allSizes, u, label); if (resize[u]) { // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx // 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 == Opcodes.GOTO) { newCode.putByte(200); // GOTO_W } else if (opcode == Opcodes.JSR) { newCode.putByte(201); // JSR_W } else { newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); newCode.putShort(8); // jump offset newCode.putByte(200); // GOTO_W // newOffset now computed from start of GOTO_W newOffset -= 3; } newCode.putInt(newOffset); } else { newCode.putByte(opcode); newCode.putShort(newOffset); } u += 3; break; case ClassWriter.LABELW_INSN: label = u + readInt(b, u + 1); newOffset = getNewOffset(allIndexes, allSizes, u, label); newCode.putByte(opcode); newCode.putInt(newOffset); u += 5; break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes v = u; u = u + 4 - (v & 3); // reads and copies instruction newCode.putByte(Opcodes.TABLESWITCH); newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); j = readInt(b, u); u += 4; newCode.putInt(j); j = readInt(b, u) - j + 1; u += 4; newCode.putInt(readInt(b, u - 4)); for (; j > 0; --j) { label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); } break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes v = u; u = u + 4 - (v & 3); // reads and copies instruction newCode.putByte(Opcodes.LOOKUPSWITCH); newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); j = readInt(b, u); u += 4; newCode.putInt(j); for (; j > 0; --j) { newCode.putInt(readInt(b, u)); u += 4; label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); } break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) { newCode.putByteArray(b, u, 6); u += 6; } else { newCode.putByteArray(b, u, 4); u += 4; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: newCode.putByteArray(b, u, 2); u += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: newCode.putByteArray(b, u, 3); u += 3; break; case ClassWriter.ITFDYNMETH_INSN: newCode.putByteArray(b, u, 5); u += 5; break; // case MANA_INSN: default: newCode.putByteArray(b, u, 4); u += 4; break; } } // recomputes the stack map frames if (frameCount > 0) { if (compute == FRAMES) { frameCount = 0; stackMap = null; previousFrame = null; frame = null; Frame f = new Frame(); f.owner = labels; Type[] args = Type.getArgumentTypes(descriptor); f.initInputFrame(cw, access, args, maxLocals); visitFrame(f); Label l = labels; while (l != null) { /* * here we need the original label position. getNewOffset * must therefore never have been called for this label. */ u = l.position - 3; if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) { getNewOffset(allIndexes, allSizes, l); // TODO update offsets in UNINITIALIZED values visitFrame(l.frame); } l = l.successor; } } else { /* * Resizing an existing stack map frame table is really hard. * Not only the table must be parsed to update the offets, but * new frames may be needed for jump instructions that were * inserted by this method. And updating the offsets or * inserting frames can change the format of the following * frames, in case of packed frames. In practice the whole table * must be recomputed. For this the frames are marked as * potentially invalid. This will cause the whole class to be * reread and rewritten with the COMPUTE_FRAMES option (see the * ClassWriter.toByteArray method). This is not very efficient * but is much easier and requires much less code than any other * method I can think of. */ cw.invalidFrames = true; } } // updates the exception handler block labels Handler h = firstHandler; while (h != null) { getNewOffset(allIndexes, allSizes, h.start); getNewOffset(allIndexes, allSizes, h.end); getNewOffset(allIndexes, allSizes, h.handler); h = h.next; } // updates the instructions addresses in the // local var and line number tables for (i = 0; i < 2; ++i) { ByteVector bv = i == 0 ? localVar : localVarType; if (bv != null) { b = bv.data; u = 0; while (u < bv.length) { label = readUnsignedShort(b, u); newOffset = getNewOffset(allIndexes, allSizes, 0, label); writeShort(b, u, newOffset); label += readUnsignedShort(b, u + 2); newOffset = getNewOffset(allIndexes, allSizes, 0, label) - newOffset; writeShort(b, u + 2, newOffset); u += 10; } } } if (lineNumber != null) { b = lineNumber.data; u = 0; while (u < lineNumber.length) { writeShort(b, u, getNewOffset(allIndexes, allSizes, 0, readUnsignedShort(b, u))); u += 4; } } // updates the labels of the other attributes Attribute attr = cattrs; while (attr != null) { Label[] labels = attr.getLabels(); if (labels != null) { for (i = labels.length - 1; i >= 0; --i) { getNewOffset(allIndexes, allSizes, labels[i]); } } attr = attr.next; } // replaces old bytecodes with new ones code = newCode; } /** * 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; } /** * Updates the offset of the given label. * * @param indexes current positions of the instructions to be resized. Each * instruction must be designated by the index of its 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 label the label whose offset must be updated. */ static void getNewOffset( final int[] indexes, final int[] sizes, final Label label) { if ((label.status & Label.RESIZED) == 0) { label.position = getNewOffset(indexes, sizes, 0, label.position); label.status |= Label.RESIZED; } } } asm-3.3.2/src/org/objectweb/asm/Handler.java0000644000175000017500000000463710635277351020602 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * Information about an exception handler block. * * @author Eric Bruneton */ class Handler { /** * Beginning of the exception handler's scope (inclusive). */ Label start; /** * End of the exception handler's scope (exclusive). */ Label end; /** * Beginning of the exception handler's code. */ Label handler; /** * Internal name of the type of exceptions handled by this handler, or * null to catch any exceptions. */ String desc; /** * Constant pool index of the internal name of the type of exceptions * handled by this handler, or 0 to catch any exceptions. */ int type; /** * Next exception handler block info. */ Handler next; } asm-3.3.2/src/org/objectweb/asm/MethodAdapter.java0000644000175000017500000001330210701747173021731 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * An empty {@link MethodVisitor} that delegates to another * {@link MethodVisitor}. This class can be used as a super class to quickly * implement usefull method adapter classes, just by overriding the necessary * methods. * * @author Eric Bruneton */ public class MethodAdapter implements MethodVisitor { /** * The {@link MethodVisitor} to which this adapter delegates calls. */ protected MethodVisitor mv; /** * Constructs a new {@link MethodAdapter} object. * * @param mv the code visitor to which this adapter must delegate calls. */ public MethodAdapter(final MethodVisitor mv) { this.mv = mv; } public AnnotationVisitor visitAnnotationDefault() { return mv.visitAnnotationDefault(); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return mv.visitAnnotation(desc, visible); } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { return mv.visitParameterAnnotation(parameter, desc, visible); } public void visitAttribute(final Attribute attr) { mv.visitAttribute(attr); } public void visitCode() { mv.visitCode(); } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { mv.visitFrame(type, nLocal, local, nStack, stack); } public void visitInsn(final int opcode) { mv.visitInsn(opcode); } public void visitIntInsn(final int opcode, final int operand) { mv.visitIntInsn(opcode, operand); } public void visitVarInsn(final int opcode, final int var) { mv.visitVarInsn(opcode, var); } public void visitTypeInsn(final int opcode, final String type) { mv.visitTypeInsn(opcode, type); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { mv.visitFieldInsn(opcode, owner, name, desc); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { mv.visitMethodInsn(opcode, owner, name, desc); } public void visitJumpInsn(final int opcode, final Label label) { mv.visitJumpInsn(opcode, label); } public void visitLabel(final Label label) { mv.visitLabel(label); } public void visitLdcInsn(final Object cst) { mv.visitLdcInsn(cst); } public void visitIincInsn(final int var, final int increment) { mv.visitIincInsn(var, increment); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { mv.visitTableSwitchInsn(min, max, dflt, labels); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { mv.visitLookupSwitchInsn(dflt, keys, labels); } public void visitMultiANewArrayInsn(final String desc, final int dims) { mv.visitMultiANewArrayInsn(desc, dims); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { mv.visitTryCatchBlock(start, end, handler, type); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { mv.visitLocalVariable(name, desc, signature, start, end, index); } public void visitLineNumber(final int line, final Label start) { mv.visitLineNumber(line, start); } public void visitMaxs(final int maxStack, final int maxLocals) { mv.visitMaxs(maxStack, maxLocals); } public void visitEnd() { mv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/optimizer/0000755000175000017500000000000011633370220020356 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/optimizer/shrink-writer.properties0000644000175000017500000000262110707047204025311 0ustar twernertwerner# class mappings org/objectweb/asm/AnnotationWriter/remove=true org/objectweb/asm/ByteVector/remove=true org/objectweb/asm/ClassAdapter/remove=true org/objectweb/asm/ClassWriter/remove=true org/objectweb/asm/Edge/remove=true org/objectweb/asm/FieldWriter/remove=true org/objectweb/asm/Frame/remove=true org/objectweb/asm/Handler/remove=true org/objectweb/asm/Item/remove=true org/objectweb/asm/MethodAdapter/remove=true org/objectweb/asm/MethodWriter/remove=true # field mappings org/objectweb/asm/Label.position=- org/objectweb/asm/Label.referenceCount=- org/objectweb/asm/Label.srcAndRefPositions=- org/objectweb/asm/Label.inputStackTop=- org/objectweb/asm/Label.outputStackMax=- org/objectweb/asm/Label.frame=- org/objectweb/asm/Label.successor=- org/objectweb/asm/Label.successors=- org/objectweb/asm/Label.next=- # method mappings org/objectweb/asm/ClassReader.copyPool(Lorg/objectweb/asm/ClassWriter;)V=- org/objectweb/asm/Label.addReference(II)V=- org/objectweb/asm/Label.put(Lorg/objectweb/asm/MethodWriter;Lorg/objectweb/asm/ByteVector;IZ)V=- org/objectweb/asm/Label.resolve(Lorg/objectweb/asm/MethodWriter;I[B)Z=- org/objectweb/asm/Label.getFirst()Lorg/objectweb/asm/Label;=- org/objectweb/asm/Label.inSubroutine(J)Z=- org/objectweb/asm/Label.inSameSubroutine(Lorg/objectweb/asm/Label;)Z=- org/objectweb/asm/Label.addToSubroutine(JI)V=- org/objectweb/asm/Label.visitSubroutine(Lorg/objectweb/asm/Label;JI)V=- asm-3.3.2/src/org/objectweb/asm/optimizer/ClassOptimizer.java0000644000175000017500000001367010701747173024212 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.RemappingClassAdapter; /** * A {@link ClassAdapter} that renames fields and methods, and removes debug * info. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class ClassOptimizer extends RemappingClassAdapter { private String pkgName; public ClassOptimizer(final ClassVisitor cv, final Remapper remapper) { super(cv, remapper); } // ------------------------------------------------------------------------ // Overridden methods // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { super.visit(version, access, name, null, superName, interfaces); pkgName = name.substring(0, name.lastIndexOf('/')); } public void visitSource(final String source, final String debug) { // remove debug info } public void visitOuterClass( final String owner, final String name, final String desc) { // remove debug info } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { // remove annotations return null; } public void visitAttribute(final Attribute attr) { // remove non standard attributes } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { // remove debug info } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { String s = remapper.mapFieldName(className, name, desc); if ("-".equals(s)) { return null; } if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) { if ((access & Opcodes.ACC_FINAL) != 0 && (access & Opcodes.ACC_STATIC) != 0 && desc.length() == 1) { return null; } if ("org/objectweb/asm".equals(pkgName) && s.equals(name)) { System.out.println("INFO: " + s + " could be renamed"); } super.visitField(access, name, desc, null, value); } else { if (!s.equals(name)) { throw new RuntimeException("The public or protected field " + className + '.' + name + " must not be renamed."); } super.visitField(access, name, desc, null, value); } return null; // remove debug info } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { String s = remapper.mapMethodName(className, name, desc); if ("-".equals(s)) { return null; } if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) { if ("org/objectweb/asm".equals(pkgName) && !name.startsWith("<") && s.equals(name)) { System.out.println("INFO: " + s + " could be renamed"); } return super.visitMethod(access, name, desc, null, exceptions); } else { if (!s.equals(name)) { throw new RuntimeException("The public or protected method " + className + '.' + name + desc + " must not be renamed."); } return super.visitMethod(access, name, desc, null, exceptions); } } protected MethodVisitor createRemappingMethodAdapter( int access, String newDesc, MethodVisitor mv) { return new MethodOptimizer(access, newDesc, mv, remapper); } } asm-3.3.2/src/org/objectweb/asm/optimizer/JarOptimizer.java0000644000175000017500000001707711224532001023645 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.BufferedReader; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; /** * A Jar file optimizer. * * @author Eric Bruneton */ public class JarOptimizer { static final Set API= new HashSet(); static final Map HIERARCHY = new HashMap(); public static void main(final String[] args) throws IOException { File f = new File(args[0]); InputStream is = new GZIPInputStream(new FileInputStream(f)); BufferedReader lnr = new LineNumberReader(new InputStreamReader(is)); while (true) { String line = lnr.readLine(); if (line != null) { if (line.startsWith("class")) { String c = line.substring(6, line.lastIndexOf(' ')); String sc = line.substring(line.lastIndexOf(' ') + 1); HIERARCHY.put(c, sc); } else { API.add(line); } } else { break; } } optimize(new File(args[1])); } static void optimize(final File f) throws IOException { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; ++i) { optimize(files[i]); } } else if (f.getName().endsWith(".jar")) { File g = new File(f.getParentFile(), f.getName() + ".new"); ZipFile zf = new ZipFile(f); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(g)); Enumeration e = zf.entries(); byte[] buf = new byte[10000]; while (e.hasMoreElements()) { ZipEntry ze = (ZipEntry) e.nextElement(); if (ze.isDirectory()) { continue; } out.putNextEntry(ze); if (ze.getName().endsWith(".class")) { ClassReader cr = new ClassReader(zf.getInputStream(ze)); // cr.accept(new ClassDump(), 0); cr.accept(new ClassVerifier(), 0); } InputStream is = zf.getInputStream(ze); int n; do { n = is.read(buf, 0, buf.length); if (n != -1) { out.write(buf, 0, n); } } while (n != -1); out.closeEntry(); } out.close(); zf.close(); f.delete(); g.renameTo(f); } } static class ClassDump extends EmptyVisitor { String owner; public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { owner = name; if (owner.startsWith("java/")) { System.out.println("class " + name + ' ' + superName); } } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { if (owner.startsWith("java/")) { System.out.println(owner + ' ' + name); } return null; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (owner.startsWith("java/")) { System.out.println(owner + ' ' + name + desc); } return null; } } static class ClassVerifier extends EmptyVisitor { String owner; String method; public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { owner = name; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { method = name + desc; return this; } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { check(owner, name); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { check(owner, name + desc); } private void check(String owner, String member) { if (owner.startsWith("java/")) { String o = owner; while (o != null) { if (API.contains(o + ' ' + member)) { return; } o = (String) HIERARCHY.get(o); } System.out.println("WARNING: " + owner + ' ' + member + " called in " + this.owner + ' ' + method + " is not defined in JDK 1.3 API"); } } } } asm-3.3.2/src/org/objectweb/asm/optimizer/MethodConstantsCollector.java0000644000175000017500000001254210701747173026223 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * An {@link MethodVisitor} that collects the {@link Constant}s of the methods * it visits. * * @author Eric Bruneton */ public class MethodConstantsCollector extends MethodAdapter { private final ConstantPool cp; public MethodConstantsCollector( final MethodVisitor mv, final ConstantPool cp) { super(mv); this.cp = cp; } public AnnotationVisitor visitAnnotationDefault() { cp.newUTF8("AnnotationDefault"); return new AnnotationConstantsCollector(mv.visitAnnotationDefault(), cp); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { cp.newUTF8(desc); if (visible) { cp.newUTF8("RuntimeVisibleAnnotations"); } else { cp.newUTF8("RuntimeInvisibleAnnotations"); } return new AnnotationConstantsCollector(mv.visitAnnotation(desc, visible), cp); } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { cp.newUTF8(desc); if (visible) { cp.newUTF8("RuntimeVisibleParameterAnnotations"); } else { cp.newUTF8("RuntimeInvisibleParameterAnnotations"); } return new AnnotationConstantsCollector(mv.visitParameterAnnotation(parameter, desc, visible), cp); } public void visitTypeInsn(final int opcode, final String type) { cp.newClass(type); mv.visitTypeInsn(opcode, type); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { cp.newField(owner, name, desc); mv.visitFieldInsn(opcode, owner, name, desc); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { boolean itf = opcode == Opcodes.INVOKEINTERFACE; cp.newMethod(owner, name, desc, itf); mv.visitMethodInsn(opcode, owner, name, desc); } public void visitLdcInsn(final Object cst) { cp.newConst(cst); mv.visitLdcInsn(cst); } public void visitMultiANewArrayInsn(final String desc, final int dims) { cp.newClass(desc); mv.visitMultiANewArrayInsn(desc, dims); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { if (type != null) { cp.newClass(type); } mv.visitTryCatchBlock(start, end, handler, type); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { if (signature != null) { cp.newUTF8("LocalVariableTypeTable"); cp.newUTF8(name); cp.newUTF8(signature); } cp.newUTF8("LocalVariableTable"); cp.newUTF8(name); cp.newUTF8(desc); mv.visitLocalVariable(name, desc, signature, start, end, index); } public void visitLineNumber(final int line, final Label start) { cp.newUTF8("LineNumberTable"); mv.visitLineNumber(line, start); } public void visitMaxs(final int maxStack, final int maxLocals) { cp.newUTF8("Code"); mv.visitMaxs(maxStack, maxLocals); } } asm-3.3.2/src/org/objectweb/asm/optimizer/NameMapping.java0000644000175000017500000000757311302174003023423 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.objectweb.asm.Type; /** * A MAPPING from names to names, used to rename classes, fields and methods. * * @author Eric Bruneton */ public class NameMapping extends Properties { public final Set unused; public NameMapping(final String file) throws IOException { InputStream is = null; try { is = new BufferedInputStream(new FileInputStream(file)); load(is); unused = new HashSet(keySet()); } finally { if (is != null) { is.close(); } } } public String map(final String name) { String s = (String) get(name); if (s == null) { int p = name.indexOf('.'); if (p == -1) { s = name; } else { int q = name.indexOf('('); if (q == -1) { s = name.substring(p + 1); } else { s = name.substring(p + 1, q); } } } else { unused.remove(name); } return s; } public String fix(final String desc) { if (desc.startsWith("(")) { Type[] arguments = Type.getArgumentTypes(desc); Type result = Type.getReturnType(desc); for (int i = 0; i < arguments.length; ++i) { arguments[i] = fix(arguments[i]); } result = fix(result); return Type.getMethodDescriptor(result, arguments); } else { return fix(Type.getType(desc)).getDescriptor(); } } private Type fix(final Type t) { if (t.getSort() == Type.OBJECT) { return Type.getObjectType(map(t.getInternalName())); } else if (t.getSort() == Type.ARRAY) { String s = fix(t.getElementType()).getDescriptor(); for (int i = 0; i < t.getDimensions(); ++i) { s = '[' + s; } return Type.getType(s); } else { return t; } } } asm-3.3.2/src/org/objectweb/asm/optimizer/ClassConstantsCollector.java0000644000175000017500000001471010701747173026047 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A {@link ClassVisitor} that collects the {@link Constant}s of the classes it * visits. * * @author Eric Bruneton */ public class ClassConstantsCollector extends ClassAdapter { private final ConstantPool cp; public ClassConstantsCollector(final ClassVisitor cv, final ConstantPool cp) { super(cv); this.cp = cp; } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { if ((access & Opcodes.ACC_DEPRECATED) != 0) { cp.newUTF8("Deprecated"); } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { cp.newUTF8("Synthetic"); } cp.newClass(name); if (signature != null) { cp.newUTF8("Signature"); cp.newUTF8(signature); } if (superName != null) { cp.newClass(superName); } if (interfaces != null) { for (int i = 0; i < interfaces.length; ++i) { cp.newClass(interfaces[i]); } } cv.visit(version, access, name, signature, superName, interfaces); } public void visitSource(final String source, final String debug) { if (source != null) { cp.newUTF8("SourceFile"); cp.newUTF8(source); } if (debug != null) { cp.newUTF8("SourceDebugExtension"); } cv.visitSource(source, debug); } public void visitOuterClass( final String owner, final String name, final String desc) { cp.newUTF8("EnclosingMethod"); cp.newClass(owner); if (name != null && desc != null) { cp.newNameType(name, desc); } cv.visitOuterClass(owner, name, desc); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { cp.newUTF8(desc); if (visible) { cp.newUTF8("RuntimeVisibleAnnotations"); } else { cp.newUTF8("RuntimeInvisibleAnnotations"); } return new AnnotationConstantsCollector(cv.visitAnnotation(desc, visible), cp); } public void visitAttribute(final Attribute attr) { // can do nothing cv.visitAttribute(attr); } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { cp.newUTF8("InnerClasses"); if (name != null) { cp.newClass(name); } if (outerName != null) { cp.newClass(outerName); } if (innerName != null) { cp.newUTF8(innerName); } cv.visitInnerClass(name, outerName, innerName, access); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) { cp.newUTF8("Synthetic"); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cp.newUTF8("Deprecated"); } cp.newUTF8(name); cp.newUTF8(desc); if (signature != null) { cp.newUTF8("Signature"); cp.newUTF8(signature); } if (value != null) { cp.newConst(value); } return new FieldConstantsCollector(cv.visitField(access, name, desc, signature, value), cp); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) { cp.newUTF8("Synthetic"); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cp.newUTF8("Deprecated"); } cp.newUTF8(name); cp.newUTF8(desc); if (signature != null) { cp.newUTF8("Signature"); cp.newUTF8(signature); } if (exceptions != null) { cp.newUTF8("Exceptions"); for (int i = 0; i < exceptions.length; ++i) { cp.newClass(exceptions[i]); } } return new MethodConstantsCollector(cv.visitMethod(access, name, desc, signature, exceptions), cp); } } asm-3.3.2/src/org/objectweb/asm/optimizer/FieldConstantsCollector.java0000644000175000017500000000536510701747173026033 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; /** * A {@link FieldVisitor} that collects the {@link Constant}s of the fields it * visits. * * @author Eric Bruneton */ public class FieldConstantsCollector implements FieldVisitor { private final FieldVisitor fv; private final ConstantPool cp; public FieldConstantsCollector(final FieldVisitor fv, final ConstantPool cp) { this.fv = fv; this.cp = cp; } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { cp.newUTF8(desc); if (visible) { cp.newUTF8("RuntimeVisibleAnnotations"); } else { cp.newUTF8("RuntimeInvisibleAnnotations"); } return new AnnotationConstantsCollector(fv.visitAnnotation(desc, visible), cp); } public void visitAttribute(final Attribute attr) { // can do nothing fv.visitAttribute(attr); } public void visitEnd() { fv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/optimizer/Shrinker.java0000644000175000017500000001612410701747173023024 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.SimpleRemapper; /** * A class file shrinker utility. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class Shrinker { static final Properties MAPPING = new Properties(); public static void main(final String[] args) throws IOException { int n = args.length - 1; for (int i = 0; i < n - 1; ++i) { MAPPING.load(new FileInputStream(args[i])); } final Set unused = new HashSet(MAPPING.keySet()); File f = new File(args[n - 1]); File d = new File(args[n]); optimize(f, d, new SimpleRemapper(MAPPING) { public String map(String key) { String s = super.map(key); if (s != null) { unused.remove(key); } return s; } }); Iterator i = unused.iterator(); while (i.hasNext()) { String s = (String) i.next(); if (!s.endsWith("/remove")) { System.out.println("INFO: unused mapping " + s); } } } static void optimize(final File f, final File d, final Remapper remapper) throws IOException { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; ++i) { optimize(files[i], d, remapper); } } else if (f.getName().endsWith(".class")) { ConstantPool cp = new ConstantPool(); ClassReader cr = new ClassReader(new FileInputStream(f)); ClassWriter cw = new ClassWriter(0); ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp); ClassOptimizer co = new ClassOptimizer(ccc, remapper); cr.accept(co, ClassReader.SKIP_DEBUG); Set constants = new TreeSet(new ConstantComparator()); constants.addAll(cp.values()); cr = new ClassReader(cw.toByteArray()); cw = new ClassWriter(0); Iterator i = constants.iterator(); while (i.hasNext()) { Constant c = (Constant) i.next(); c.write(cw); } cr.accept(cw, ClassReader.SKIP_DEBUG); if (MAPPING.getProperty(cr.getClassName() + "/remove") != null) { return; } String n = remapper.mapType(cr.getClassName()); File g = new File(d, n + ".class"); if (!g.exists() || g.lastModified() < f.lastModified()) { g.getParentFile().mkdirs(); OutputStream os = new FileOutputStream(g); os.write(cw.toByteArray()); os.close(); } } } static class ConstantComparator implements Comparator { public int compare(final Object o1, final Object o2) { Constant c1 = (Constant) o1; Constant c2 = (Constant) o2; int d = getSort(c1) - getSort(c2); if (d == 0) { switch (c1.type) { case 'I': return new Integer(c1.intVal).compareTo(new Integer(c2.intVal)); case 'J': return new Long(c1.longVal).compareTo(new Long(c2.longVal)); case 'F': return new Float(c1.floatVal).compareTo(new Float(c2.floatVal)); case 'D': return new Double(c1.doubleVal).compareTo(new Double(c2.doubleVal)); case 's': case 'S': case 'C': return c1.strVal1.compareTo(c2.strVal1); case 'T': d = c1.strVal1.compareTo(c2.strVal1); if (d == 0) { d = c1.strVal2.compareTo(c2.strVal2); } break; default: d = c1.strVal1.compareTo(c2.strVal1); if (d == 0) { d = c1.strVal2.compareTo(c2.strVal2); if (d == 0) { d = c1.strVal3.compareTo(c2.strVal3); } } } } return d; } private static int getSort(final Constant c) { switch (c.type) { case 'I': return 0; case 'J': return 1; case 'F': return 2; case 'D': return 3; case 's': return 4; case 'S': return 5; case 'C': return 6; case 'T': return 7; case 'G': return 8; case 'M': return 9; default: return 10; } } } } asm-3.3.2/src/org/objectweb/asm/optimizer/ConstantPool.java0000644000175000017500000001403110635277351023657 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import java.util.HashMap; import org.objectweb.asm.Type; /** * A constant pool. * * @author Eric Bruneton */ public class ConstantPool extends HashMap { private final Constant key1 = new Constant(); private final Constant key2 = new Constant(); private final Constant key3 = new Constant(); public Constant newInteger(final int value) { key1.set(value); Constant result = get(key1); if (result == null) { result = new Constant(key1); put(result); } return result; } public Constant newFloat(final float value) { key1.set(value); Constant result = get(key1); if (result == null) { result = new Constant(key1); put(result); } return result; } public Constant newLong(final long value) { key1.set(value); Constant result = get(key1); if (result == null) { result = new Constant(key1); put(result); } return result; } public Constant newDouble(final double value) { key1.set(value); Constant result = get(key1); if (result == null) { result = new Constant(key1); put(result); } return result; } public Constant newUTF8(final String value) { key1.set('s', value, null, null); Constant result = get(key1); if (result == null) { result = new Constant(key1); put(result); } return result; } private Constant newString(final String value) { key2.set('S', value, null, null); Constant result = get(key2); if (result == null) { newUTF8(value); result = new Constant(key2); put(result); } return result; } public Constant newClass(final String value) { key2.set('C', value, null, null); Constant result = get(key2); if (result == null) { newUTF8(value); result = new Constant(key2); put(result); } return result; } public Constant newConst(final Object cst) { if (cst instanceof Integer) { int val = ((Integer) cst).intValue(); return newInteger(val); } else if (cst instanceof Float) { float val = ((Float) cst).floatValue(); return newFloat(val); } else if (cst instanceof Long) { long val = ((Long) cst).longValue(); return newLong(val); } else if (cst instanceof Double) { double val = ((Double) cst).doubleValue(); return newDouble(val); } else if (cst instanceof String) { return newString((String) cst); } else if (cst instanceof Type) { Type t = (Type) cst; return newClass(t.getSort() == Type.OBJECT ? t.getInternalName() : t.getDescriptor()); } else { throw new IllegalArgumentException("value " + cst); } } public Constant newField( final String owner, final String name, final String desc) { key3.set('G', owner, name, desc); Constant result = get(key3); if (result == null) { newClass(owner); newNameType(name, desc); result = new Constant(key3); put(result); } return result; } public Constant newMethod( final String owner, final String name, final String desc, final boolean itf) { key3.set(itf ? 'N' : 'M', owner, name, desc); Constant result = get(key3); if (result == null) { newClass(owner); newNameType(name, desc); result = new Constant(key3); put(result); } return result; } public Constant newNameType(final String name, final String desc) { key2.set('T', name, desc, null); Constant result = get(key2); if (result == null) { newUTF8(name); newUTF8(desc); result = new Constant(key2); put(result); } return result; } private Constant get(final Constant key) { return (Constant) get((Object) key); } private void put(final Constant cst) { put(cst, cst); } }asm-3.3.2/src/org/objectweb/asm/optimizer/jdk1.2.2_017.txt.gz0000644000175000017500000033622610532002111023256 0ustar twernertwerner‹õ€`Ejdk1.2.2_017.txtÔýYs#9’.€¾_³ûò!TOÕ•=3çŒå±kF‘”™Üš¤r}…È“d;"¨Lõ¯¿XbÁâ8‚TUOÛL¥øÜ±9‡Øìâ²|ó?ñsü{|8ì’ê÷ø§þô³ú}gÉîÿûÿ eu¼‡’"wŸ’¢Lóì6 ÿ—fiõÿ»øí˜ºMʪÈ_°äǤ’ ó¬J~U¿MlTöÞÍ!Êò†|g¿¯ª"Íqªã6͇»ôp!i2–z»œ¼7JР‚ùØ% å<Ì·Ée\&M­Î~”oŽû$«Bh¢}ü˜ -À„F$ãÕö²›ä›x×–üX¥»ßå'”bñ>©’âÍ–" -)Cß¿I¹äc’–ƒM•>³ê|Ó³äçY$ð°‹_Lz¸Dh5˜¶HÊô_ÉE¹Ó»ž¥L¹ÚÀ8–Iµbzçïü;Jö”ÿ\Uqu,¡.Ghª¸@û©¬òƒHÛ ´Ö>oºÜæ÷ÿ“l*ˆ[ƒm•.—ص³R㌠ö"®xûÈÏ h »Þ:£áÁ;±QV$Ù%R¥Aeå$L¸t’„Aå—¥{øäÉSaÃ%dÚhhB§Ž†î X°Ò´%Ðòhú¾ÅíòzXÃÉBâÉ R`¢- 9~f-…–Ä€mÓòW›'ÝöŽL9Ýï'·u3_Fßæ³õ`§/×ÑK·[ù‹÷ô$-«$k;ŽC^àßmˆ2’t†L.wùæG”mŠDŒÉß"9¥ûãÞ aª2/R–Ðz.Ø-›™I¥ú–)ûs°ÏN,£ü99oë–VëFhÓ¼NLݾ.ŒÞr.¤l:'Bk»»ÃS<Ì÷‡¼L+÷(БÃÉx°Ä“WË¡3ñnΆ Ž­ÖçÍÜ\é¢ ·kO\€á.‰ GÅÆ™8NÔ£²r‡(sÒ»’yþGGïòì]éÓhv·¼ŒˆÁ‚M£E,¾á˜â¸KðÔÿ·Ù™k_$!så±!WIctz%åæÖïÃ|—S6óïÞ“’–I¶Møœ|“fU©šomަ­4á?ñN³Ÿä°}ß­yl"nçð/¿]9AQÆI¶áf‚ÀEÓ\õä°<î̹AÇ<Åå7·È©Ú|«” ,6éµ-+Šñš%É–ýdcÛŸ5cw–Du ´ý$Ý9–š6âCbe±ŒÙÔ\Xì‘ÏŸ‹TÌxu2)_Ñ¢’€š;­Þ¿yJçïtf¯ò6&ëÏëqQä…"Äâ·Ê³`®C£u°kùUuf·\óßö(j€Û¸Š¡ïéúʺ¤d+ 0m8Ÿ.æ³ñl}7þÄÿ;¬>Â8f™G³ñÒƒ»šoWÌÇñWb:¿]I˜é|Ígèçh6šö€C§ÁèÃíj=õ·W´O=õø‹—ËlqËRÇë›ù(Ê:`6¸œŒG(z9^—Ÿ â˜/Ä#åƒX m²©åÄç÷°:áF0¾–j$ëZ ­óùn{ñ›Y˜âð2bãê*MvÛ(«r¥Ü ):']é3³a8‡0â‡4‹w܃‚$I2‹ùš›³F@Ü"³y«ø¢gT"”i9¬µÃ…nØ4¾öë]·w¡HÅçÚ¾ÐÅ®ZåÇb“@¦˜I•»r@tíô¸«Ò˜7œv ‡4¯š~ïI×½ÓöíšM«¯•lÃ}‹¤xÈ Þ£Ö]¤;:Lc¶Å%E“ó¤÷)€íb x!˜…öEæ*‹°ŠbCz•$«â”;Jb"€’˜%¹Ê7Ç-…žj•@Oî‘{”ŽÕ4©žò-Zc•õ)O•ìñ‚¨‰v ÔÔYL^МÕ4+c5±G¾ÓüX&hÎzª•·žÜ7÷iîÔR.‰êQž5[v Ñ­h©=²þœfÛü'š¹‘leo¤û À,ƒ¤`¦LŸ‰ MñfÛèqá°>±Iš÷ZqîÛÄER-øÚ‘õ?ÆUÑT¶®l·ÃV‡²»I¿ ŸŸBùM™Íç˜îBÙ-ÅÂë+·ÏXÂÕSþóôö{àÓ×5¯2/†ð™äeu—´O®JÎ'Å)›™øî2:ÜøÔEäõ#a §¤,.l¢3Y&»$>™Ëúåp‹=Ÿ4†»tó`#f”F£"~„š7˜Ñ˜kæ³0úÅúþ |`ýÌ“œ`F¨ô„p’Û¤í’ +Ã_µjBÊó×,œÐÂük'¤0Þò )À_¹‚Šôç,¢ÜÿŒu’õŸ·”rà/ZM!Eú“THîêšJ+Ã9WM’ñ_±^+ã¶Bi^{[çÇŠiŠUU$ñˆtìï 噕¤fêåÍ·KN.lDÃá§ WCæ•”š fÃ]™3=9qßúX’øœu%é&ÏÒ‡ô<ì¢s2›hhrö&~m’W“ê>tóÍȺ…zvêZ\àžô")öiY¶…)“ͱH«—ß/ã2Ýt©zv •»\ ÐY°PRõDXrþ#y{•îvƒm|ðla$ÕSZ¾ý¸ƒ’<ÄÕfí®*@½å0ñÉévx¼O7Wâdfî^QüãoyP¿ÌŒDxŸ<¦Ù‚µÇ¾:Þó¤–MvKCD"au¡—‰G­st½ÏZ\üöFµzЉºw->¼'‹µqþëåbR³ß·›ßyÕ~¿bŠ„%m›zÅÇq,¼ù0fwÓh­E”Z€åüv6r.ÇŸÆ0,î.o×kG²‹?O_ýãv°#€Ÿéqoþ'O3$i”}ʺa—²À6.± yÒÝá). £Ò%Å0>”~P^0s ÃÁ‚–޶E…ÍÕw|hס¤òÇV!s‡1T¥à§MX÷ Š‚Áø~å†-žÄ‰jÌ´s|Ð; WØŒzAŸ¹;s›r©p©Åa®¨Ð˼Ø2ñK~tƒj¸§G}©iÏŽ´,/ô1«&þLJ4Ã$ÆÓJö”é&á‹ ,õ!-JÑ΀µ•3]0à Wúl¾\ß`‰«ù-ž8¬ÖXÚç1ž6Ï µ¯¦^ޝæËñÝU´\­ï&ÑlŒWŒËÝdàÕü8„Í×ÑlåaÈãÙ…9ìS j@`*8o·ò¯Öm©¨¥öÛ{@ׄ³´­a=œ%·UžÒÝ`ôÍ £¬Œn-Íe ä_ƒ]ú˜q§ò­Ejê{]¹9| çðÉ]Ê4{Žwé–Í(òœÚž»ºjd õ^{’¿Vúd…¾ûØLFYÊSRçdy(’‡¤(’í9™JeÄàÍWÖ2è•e-HPtá屪šå²VL•»ÄìâûîÊŠî³ áctû8ÛbÉÌN¿7ÌFù5‹÷ÉŸSƒH\Z°f*þY ßwçq 5Þ#eèMòøšfØnõ1ß¶Âd–Wéà X^\ÇM'~³xŸx¢XkZQ„qÆ&¨N .Xö›Mé}OËIè@&H44 \§ÑCu‚"ß$e©Ä”ÒãMu&1T\Ó0ó~+§FÓ§+vœj—.L)αž,7¥ÙS4™-›®¢Á̇+ª9¯Eü0f³VéÖB5ÆÐõWX_Ô‰E|xJ7§y{/ ­=q…lŠëÀWOùO°ÐžÙTU’!–ü«ˆûü—gmP¦5ß&”/àz€K£6•¾8êHBÖ6&UAM­nôX)´".èD)-M‰'Ôe’J ;ÀMz „àNYp©õršì°¬E¹ùêzu·º®Dðñzd6EVA#’ä–ne7ŒAÙe 9J\9‡qè5ñO“ìÈ¥½Ki¾ù´`lºožÙ½Å!³|›îží»òø%§ÅnŒT+ eà¶:Xˆ¨üdð oéNŸUV®YºkîSfë–K¯Y»¥î?Ÿj,ðyµ“{×üÚ¢ÂçÙŽ´Ï|kR÷žw[F'Ì¿ 3ÌÊ pÎ-î¤ù/O7‰o©$0žWioæÂ(Û&¿ìdTmŠTKYН˜Š¬ós(F؈üJP€1Õ'ñ¤îà®CÇ5HÞtaè^ò£2˜åQë¢g ë?Ùªý´^MË:SÈᯒɪPÐð‹Sx«F¤Ôè¡}]¦ˆö‡åJ}Œm ⥠åLÖír¬elp@.ÖêЕ- µJÓC= ò^J¹¦g0Àškç3|£¢Þ|ÚíÀQq¢ÆWxh,¶Ô´Î4Z•N˜06üR·ß‡Ó)ï¾d£+Ý'PØ;@Ô^“óÿ®ñÆâja³ã¾ÕY¥ X½Wz¹¼¾,ù_.З¯ß¼˜Å×áÐ º^¾zA{1_‡÷ÃÂúõâŰêy1¼¹¼ ›Õ'?f²òb†Ó¯) /æÝp²ô‚þNýôŸÐQ@ÿ‡ú¿ÐS@ è’R@# hL]y@ÃÕ]éo醹8ŒÆž!Î@\ýx ¾Ñï%[°‡"ßË"]|¿ÒêA,« ˆ]Ãkß{˜ûÕcìtê|¢›}œßMáA¥e-úZÜž rjcV¹Ò”àd ‡wæ„ ±²r1ù)ªE‘?¤;ô]Y<ÚÓ‹ä˜wMâøëå_>ƒøY*ª®ã{@à &^¡ð¸à`þ¼…,É…%új1½-ç% M§:ï·øÍ3nă@ýû¦ãÑœc….¶ñïÂêñî ³ßßò?¹fñ@inRˆ²8fÚz­]úêT›7šgÅNæÚêàö މƧ$ ŽÏK\7aRÐ[®ïøK[N`ͬ>òÛÖ­ N«Õ¸Þ—€E«Å˜tmäüvMd9þ Ǭ)l[Õç“ùrµ ÇÃùìÓx¹Šæ3Ùàrµ^†”âÌÓñHdã§›UúÈÄf¤_•Ùb…<>Ó€bÙB„þz¡—ÄR^1‘åMI¬ÏÍ®¤‡û—d$ (fpCÁ• ×;0\õÀPpíCÁ ×A0\ ÁPpMCÁ• ×G0\%ÁPp­CÁ“þ¿!ŸñüØQZò§µˆhé#‚'iöƒÜ—UÁ "¼³¾ˆÜèØ * Á")¸#îï<Àe²—˜ Îé>aVÊÆW˜¸ªCº=@Ö$ùîXñf -‰·„æ^ç—[Ç4ädä;ò’ß0Óâ¬"¬—CvhUãHZÕ8’Vµa¼Kïe÷²I Y³~£Ñ=ÅÅ:.øŠ˜Ï/EúøDC’çt“LØå&„‚¿OB¦¹Ž÷GZyøÍ¸³„„ž&qy”ï¬ñÛ4¾ÜÅ›‹< ¡ùü”V fÁ㟓Ÿ4±¯Á4ɯÁ4á¯p‰)R±B¶JþyLXOnQ¾.GÄJ ,±ÎK¬²ÀþŒ] ¨Ðö¹/áG”ƒe=ÇQ‡ ÃSÊjÇ+¹{Z zlž2–ôøB‚ßnŠKãOL|Y!†y¶%]¡we—$ªÎÆ ÈÎͶà'ü¨á~ùft³c8 Tí+ˆgÞÚY~ìbC`8Ò Ô4~ôÚ:=úaƒŠYn÷Ì#Àô~‚h·“3;äwÈxÜ2) kh«×B-“2)žŸlų X¢ +ç/_¿ÍŽûû¤øâÖ>Än—aëjäWJuˆv&ë\_ßã›xÃc9Þþ òZ¶qW ©gx8Jì¨>/U¿ð~yÉÆ‰w§›áíø >ø)äóNßí­9QHȺÝÚý0J'o(2 xÏ+ï(@Ç]H~]ÅùÒÎÈæù~¿<‰Ï4þŸ¼™órkÕØ®ŽJ’f!9x÷= üb¸"޹IlõŸbr§p®®È÷Rnaò7cî"äÏlO>äíˆÇ4>›o8ÔÝkéf3\Uù‡áŠaݹ3!àU¾LÇÌÆ‹3&’uÞDœÂ­aóC’5Jûl³Â¡HŸÙ¿ÉvþìËF³ê®]iw¹¯Aʧ¼ÚÝ-‚Hmù•¿åEŸ¾gîIIw 1wl8’]ù RšÍ¢BO¶[³vîrO] 6P›6d|¸‹ÑîkÆåõeÏVä”K¾V?ÿêÃ^/Çã}9¹“Á´¾T'w%çEµBjì4fÂý‹õŠ»tX¿×T–û]™„z…Í‚ô!á³Â¦uo€Ÿ¼ÞÖ×wÂr·R¡Û¸ø¢ï¹“ÐúZh«+ùíf6»|íÒ½$»]þ(Z’dÖWþöt¦­¾ä÷ÍKlƒïwG;»ƒ±z“_ŸcûP<Þ#)ÈçØx‚¼.]i}r‚€«Áp­í³ËÏÕS󤶕„„‘iõ ®Æí­f¢#5r$™Ò‰®Ôoxš#.м…VÒݬ.e˜¯Hd%³”*g^$3fª±]Áè)ïí.wÝÖ]¡Õñ¨ú’X6ØÂ¡ûö˜äû.áÝÈL<°•r²f#§äN$[mÖÜ0-Wª ž¿©.™]p>ºI5Ü&~Ù¬sm…Ònï­ÇyR‰ã/€ci|W Iô*Ÿƒ8:‰Ú¤¥3SÖeN¹‡Äàá fvô¡’Lzbý¥ÛbHw³‘+›nJ»Šh\K!7˜À`üo031xq‘d›¢]ël¤ÁGwåD”²3Å[(K>µb‚"j9ì¼>'Qµ×@ÑÀBt܈½3™¿2³]ëÖ6ÀÄ™ÚÌC n7“Æa›–‡¼L€>Ò`ÍØ<Õ±gåçc#ï——=h²‘iPWÕ"üvðy½f£l’o~¸» "PŽÓ¢ÌD°I”Mø\z•þr?íᤳ¢Šhaæ.ø@«J*M&>Ýä%¹L–q‚]ÁåbrÂk´4¾=ž¥¥1Ÿ–Æ·ÏCµTÎá/ÖÒ8‡?]ëä+O‘.ùZš‡”ÎaFSo‰~¿KÃLŠh…Ñ$ÿ¿¾€_ÍÇ=º”§„×LbvnÂoh˶`ò=[ƒ:’r¤Z¼)®°Äͱ(s¸¥vù&6f˜&é9-Ó{$-‘‡áa:~HLÙùAFXÁ­—â¡I¸‚ùáx€“2ý4ƒž0þuØ¥›´Ú½¬l'óáG0aŸfF|€Rœ"y@Û!4/R¾ž7œ&JùfW9Ïv°Œµ¬ ;*±PÞç?º7#Ẫ:âý¥E—ÚÏsÂQ»îØzÆY­„ÁŒ·Ta˜Öš0D½5F( ŽH—ÚâˆÞä0°R „L•'[ùJ ø©½ ‰ÔÚîZ(¦Ši\þ€{µä×@À9”Q¶AòÞ,°Ú´õ|q7˜D׳©îîò=èr¾^ϧÐd|µö@–Ñõãtµò*ž€\‡m¯EÌßw ïU3- ædkÓ©rH+&ƒ´¼Ž’n¸«vÌ‚k|~‰bdp¸õT3n¯ W\¨Ü´gŽ-NÆÉ(à}bûÎ è¡c”£òà¯ÅI{)å ½Ùkñ0üusÑõÌË|µåÞç£Ìd`ÊâE¾†jäzŸÄYù; qdêäiû»zåR$J—ÍÝAˆÜßs{¯TWÍ3Q ÉæGÄ—ÄJû‹ßï#k­/¾ÏïE¤+pʱ¿œ™•妹Џº ø†Mä=îz2퀒_÷H‹PÕQj]õÔá…¿\¶Ÿæ·Mè¥ÛxÑ>§Hâ·MvlÍU˜×¹ÖiÜ»Ã%€ur݉pÔ!®6OÄ‹—`:q³Um^_¤ËŠ'ÕÜÑ“=µ– u”ãü‚îëìдHtµã~”¶ž\é.–Ø›hÐ/òA_ ËváêÙ|QiBõ^G‘ñéã­ÔÈW¥øÎ_F!µÔK/FÊ2óâ ¤ãÌ„@#_P‚Q»˜W‰¶Ùö÷.%æ® •Œÿv‚§âìÚï‚Ä`Q£œœîfùpÇÛCîJËиmèâÝ<Ø¢R´¸`D7Âudî–(y°´Þ™ÕD÷w5 Í@ÑXK~ܧ¬JˆŽppãj¨¡ãaò3ž§†àX¥»ßå''…)ãrØx)ãŒÆažÉ³4ô¼§òÙñ¶†÷ P>Nd ¼<7Û<Š¢ vó F,w"úРÀ ыɽž‚§â¤Í“'áíÚ“"â²ÎóÝTkãú“DS!dõ|o LS¿ú‹ê)élbzS»ÈQ3KºJ0š×G>_Ñ´¼Köþþfsmk;Ð6¨1éÃÆ–zOéµJ…ñq{PnÄU—uºXA¶Ñ»ä’gê o¯õÄ8”õ Ò¦FØ”£üÈÒ/|‹]즾Õp RŒD3¯‹˜-yJw¹Ä&ÔÏz^Å@óCüÏ£ƒ ß ‘àoDG²ÜMÁ?’—‘¾Ý&Å ë4†¿=Ñ;çZi׵Ϣ ½9§–¶¥r}«à Þ‡K 0c9Ÿyì8ê—Á Ð,¸Ùø»0;e——§*ª}/“Al/ÀR‡ ’$)âÇ@’1¿+=”æWj«]7É´»6™J"œà9±ž'lSù+lµî‡Äu<¿Ø9„„|gvGÃä/hŽÃÞš„ =­.FÇ÷ð{º8Ѳà<{r ìÐ"¼C9ÉM?¿Hݦ”ALÄ%çíø¦s=ÙÃ+Ô×W“‰ñgß%yx(ËSäÊvàá÷1yù4 únÀ›!drפ/§>WÑ+Ä{]uò}·nšsRµ¿O߃“ ϰ W_{Þ8ÉôÄÍ8Éä ûq £ómÉ5Wý»vå$æìs¶çÙ›ãÓ€8:åNBˆM¶5Ц;yÏšÓ`(’ò)>€ÑÌ „Ϭ¾tÐS”š/ßôu:ˆ¤cÞQÖÒí½G‰@?·ÇÍíà&•–Ÿ§P<ݨ£§nV»ØæPY{ÃM϶ݺ¢é½S{[mg«›D4µ«Cq+J"Ü”ö€Æ VN /]î6”¤YŽ£½Â_v¥¡„a†®ûDD Kñ`O‡â8šN$Ÿ…èóò„0Xî U¡žÐ- ŸyLµÙJWS=¶i,“2?›äòȰ'g”–7¬1ÿÅ·0§¢Ÿ$Õ:_¶^CH¬K6*¼²,@=T:ÏZb§#Û»m@¬à¤SMv#>Øñ*õÁâgîrã“bl‹¡š¥zɪJ}9\¼s×¢ƒ%üdsó¨¤ÍNî?yÞlaÙ¦]ƒé'µtÊN 0µ ŽIàä}üË ?ï²5œA”3Õbå!mH0=Ô¦;SõPeêõ¾ú8¸>ÞÈšp¦¶9`p{µÌÐ üD¶ŒR¸1[=ë ¯6[Àá°{éoøw‚|ÌTç™±gØŽº€:s¤†„±´ë|•ìB¨‘ ¸&=0î¬!{H³.°šß„Ñ:/<œœÑiÈŠNS@m^uéæ…žÔ -zvïqæP±a\Ä:º^(6V”±5™‡$¿ àwòË4Θ…Q taQ9*aЛJØznÛ¦ùÔ6¡‘+ © «¸ðZ4HA—ÒGxTàá'(ªðÓ¢U^Ì`ËVbð–w›¾åÝ‘Rw©ȦsKAßtn Â^òÙíY‚M —Žº©áƒ6®:JúvfK“—üVÅ^;;*Ïg 1Ú§åÖs€S·5|¿~8eRc2Ϻý"ˆ6D ›]Mõ}à {ƒuWS!ûõ2vÐKÕçPÓ^[{1ôд™TøÁipÆ¥†kWª[ÎR=û …è‰ùO½pÞ yìtm¬`¶ B¨{zÊGöþêvóù2òÍð”ùýϲ(°û5Ç#ž>·p'ŠxAS~¡)©õ b›Ž^‚h178Ôçkç›-tÂ4‰a9úó{3_ n'ë»áír¥_ú'Ó‡Ëùju3ˆ–(b=þ‚“DxâêóÝr¼Š¾qÄØ‡˜yyÌü<¼Åð¼…ð–áf0¡‰Óù'œ’™(Û„ßÕgœúv‘z>ÕžX¨Æ»õM¯ß®øq{,Ëò…M ûá‘™þ{ù àlƒFiÁL©=\pWè+ãž-?P!Y€¼Â À’x>«ã–|“Wå!¯®i°d—KW"Ì«RäWÄe['‚›EZšo3W‚Û×<–¼†þ#ýN;NÔõ@!'ˆ;ÚÉ·–ˆrȦ/ÚaSgsYY‚52—}Ç}Æ;¯4´:Á.™¶Ëã­]î®@¢ ù˜-7VÑïÃ]z¸Ïãb뚀 c (~gJá‡ñ=c AÒ† B,üt2'÷Y~]ÿÁ—(ïI™!.­º‹ƒ`Z†Â0‡ ?<\$•Oé+}Kƒ]«ž¯àâ͇]üì3aq"ÈŠÃÑT³áУˆ® #IseMk>‘…æ#DTþ À;¶öXsו‚º-PYÿ)XR·l\ä|æç Ý ?Oƒ/¸=©¤ŸÒú¯S¾.Ë ³M¿—[ÈqëW©‰[ž%žSÎ(mÂşϪHR‡tLÇô´|q;KÆÚ=÷.^ÚÖ‰z¦‘NÝT•BÍïÕæ 3WçÖ ­þÚAéí0¦Eº‹—ÓJ¶´§Ý‹^ƒ¯c÷'†kir½ºšIKùÇÅR“%§ÈWC­Z\áÔ¦¡È1'ç²D¶íÄ~Óà!ݱ1›Úd€œ+Öâ \¤œÀ@µil²¼Ø‹6hÓ¹´ŠÅÙ¥¸Î•)}ß_;ÄÛñ/Vʬ1}Ó”¦Jdâèi3O{ äLµç\«I¥L×€}´·Ø˜ÃšPnÍy]’Õ4>¿tKü(¯òB^UT^|G%Lx|Z5sÍq®ó¸øNЙVN®º7ã…\õ–€ê5i Ý´ïg.gd?Ïf˜£kîº^-ÆÃh0Yy‘ÞŤ‰ g~Ú׿´#d¼Zi)Å…Œe°‰ªÒŸÉ@YjQ„„¶"1ïgûª,zX«-yZ®óI6|Š‹‹!>g+xqa ²Z{8~‚M2 ,ÓeØlØ’ž2C+LÄ¡q—¨ú™”naïųÏLߟcêRð\¤SÓçŽåÇÝv™TÇæ6¥õÌ#!§­ Måߢªeú;ÿöýÒž#×°²ìPb°éÛ#o>0Ô4šŽ©ø‡æ/j›Ög®óð\Ö¹ô/…æä 1©ûøI(A³Ioø%%»?¨ÙÁ¹Ñ«'ïÔ™;È2XÇ‚¹5‚{º—ÞäŸd`m¨“R¯Ü^¯6]€nû õuÀý¬Þe€ÿ™|Ì´üÒÒ×ö}'èÄJVÊÑ«šD®œÎaiüO1†\m|›• 7IÑk!áàBÝ9p°pÇp©•µ¯Ë<t›Y-Æ2‹Ú«2E×ë-Úu£O rž‰j1ÐäØ& [«q÷[¯·ÈkpÀ:iŸoãý¹J+ý#I—»|óCK¬Sïã áÑîâî-š½NtˆLS’dÿÃþÿº¿Ivˆ)lš4‰ôîE±ž¥[0õ7ùw.Ðr’ОÅĈCJ bs®iüo¾›§NÝt·j­Äe‰‡^ïôÕ´ê½_fŸøø q²ßÜPÙv$sº¯} <÷Ò¤•S>„Áàá%ÈQ§ÓÚáZÉÜÀþ-“ªËCÈ–£‰f{ ¦¥÷ê› ºOI¾ï¾¿ÓIƒ6ŸLïR¬'Ó»$§Šj@˜ÊiÓ)©Æ\+}b'™ÍÖPÐÂ;¼òô\AêCDEýHÌê®Ùe†£‘€¶ùjÖŽ$ì”|MÛ‡²íuµL6ùcÆFañ>2e]Yk!)PnÚUj¾Ë‰0üÛ@>®ï 9ðsÑdÎu\ä²í‡*› ‰”`ãB¬í ä²f}l.³Q˜*¯X#ƒ¼øSqÕlÝÕ½Ôl•ñÐO}ÈXQxÆÓ)ªT9WØï±~€o‚é_ÂW-A•Š"~iý˜ÃE ÂìÜZ°)µwjH¶€¨nq…Ò]ˆä.R'ö…Rˆ(zW”¯ÁÜh¼’Z*/ÇÌ¡Pø&ŠªòZG¹$2€ ¤µ_‘uôš¼Q)% c%w¶Ö¨ñQÌÿpH2×{EÀ=c87þ28”²½°æx"ÇS&v͉ӭÎl¥Ž7§µ ÓaUÉ#ïîöž2cÉä"ä!?¯*Xü`B¥Ú!42õYÿ•_N>zQ‡û1ƒ[™Td&”™¤F6—»ä‡þL‹8ENÒì ȳžåä̉Pž½º5öÍȇ£ ü ”3è,õ-K};mÞˆ´:gƒìe ?¤çiaƒ‰8p[·7lí÷Œz.ô‚9JdGþëŠ(?Ø/^pñn·ïw{ìοh5‚!ºW6°é¶±ûNŒ£¾á:£T¬`Eku››z—NÀ/v ½~Ê`-ÖþúסRþÍ‹î„×®Û¿q³¿v³:mÂó:0A}[¦7ž­ÇK/jþ‰Þ f×ã‘ç\“ëP®â½ Jšé^œ¼bÒsøtdŒ®à­Œ Æ›[Ì«Sˆ޼¨üáY΄öédÖ ÞᎠ¨5GiQ½x±àªüÝôë™V äú_'D!œù˜áò3Î §šÄŠtÜ`3ï©›ì"ˆþÔº â4>_¹š1'Ÿuuµ^Û^Ž›áÎP”ø4CPaDðŽX4êÈAÍHmxѸ EîØAÝ-:¯Îcò C‘zG¼_×7¶”hÈÛKÖù„Ò\+·ÎvD+Ý@$¢Ùwä•x~÷]›ø­ÒëÀ²—§ù6}H¢‰ÇáÛ,­Ì÷„ñ(Ó´k0h$×F¹É„kµ5ÉT·eR(%ôt|=)ôíø†œwäê(B¿ˆho·7`b:;0WôÄ-@ ’º© xR ýÉ¡*ÍéÍìn7®‚³ÂY­½Dƒâl¶ŽÆñ ÆŽÎï$kGcuº¹£°ëgï€}Ù¼Kþ¶û“G.­Dä¥k} ð¥–2n“VéXÞø¨vùÆVe>¢C‘<åǪGùÒ Z´ù¨žøVnët©¥}̇;»å ¸Þþ2¼HЇ¼ØkR,7ߤŒ£ãÂǾ¬òdnùè¤ùE{®>„ã2yŒo$Ò‡œó‡ŽônôtÈöÏzÀ¡þ¡ÝA—§…Ésn æ‰Ñ϶÷£KWúÄQÿ óh1øvW qíSu 2„´GÓ¹V:ça YVgâÜÇMMÉú¤ÆN“švCYÖg&:6Â]6T‡Œ“Åf—ÄEg씣f» RP4ÕÑzö - jKÜúk NKçY} ‚Æ´öBK’,¦±ÆÂm(†©‡GL¥­w7+a }Nñ8uK´eÔ]4Ü;~!ÀJàÕŠ™ ÚJmA{ë¼JG{±·Þ)¥;ãÙ<9dÂ#‡TbC^ çŽ ï:ø¤)Dk÷¹§W‹ã[Õ7ºà¯zÒ-;œ…}G•еCä'OKñ¼HJÄ…a^ŠƒÙ%nxÏ}ܼ_¾}Ÿ“;è|GÑ¡,ƒ…WYI@•-B/UˆHûÄÐ¥º½`~ö]„¸”‘ gó8 „Yï¡ D)³´µ,qÁÃn½v} ÎåJ—Tîã„7ˆE½#桳”|þÕNÐX÷Ñbܺ¸‰ÈH“§Cœ(yxw3 šÓwM®ç¹… d]$\»‰QNÕíö5é›–ÐYy_š ŽïZ¦<€7ƒlò]í#@}®ÒV¡ ¶¤nB…&ismWîÜ:ÅÃÔÖ&Ùmz£“ œŽäUt‰“y]BÞ!Izé…>@—(Tg´5Ôò :Ê…5½Ë+Ôf‡S±…Dè4ÏPÐptŒ MÌ‚~ÎÊÓc,Š3ù”ýdß²?¢ oÉNõ5'ÀE:1Êžùãl4?Ô×ËC×àE»]òïVl&à•x>VÛ‡ên_>†à³¡›ì"àX Ülø©: |£`^ÁgÐOàErŸ™¿=õŸ;4wå;аçIÃ]ºù„R:dûxò¤Ç3ójõÜ<™j=3K~Úö¼ùópå™y.“]Ÿ‘)ể:à¸6~:Ä7[;(é1÷.!à.6~6Mµ >ïR _@:Þ7€›Ø7¥ÓåB Wd:ÏÂÌAÙÓ-ëæèñzˆÏ³•Dˤ÷êÉÁ>-UŸ¦bÙc/w,\®Yä£u‘¯ƒDJ¹d°Qñ2ÃÜìŒ:Yá—]ÒàóÚtƒÙèÕMtµ¾›V°áz9ñ£¦ãõÀLÖ× ^EËÕšœ h¸Åxy5_Nµc±6X:ñ˜:ÚÇÙÖ‰Ügcl”#øÓÛ‹ˆz_;‚×gbyxµƒ«nÏÕ¶ äDŽõ^¡ë7ˆ r†Ë°ýŸcYíÙŸäáhP FnWëéx¶ÆÄ'€‡Žÿ4˜ÜŽïì“â0áí,ZßE³ár̉iðј ¿œÌ‡ƒñô⬗ƒ! t T,~a 0”ßQïGÅíoã‰^îWµž´5°ŽÙÁøÈniTSBáDgÒÔâ6Ñ'ÞˆlO•Ðr P 6M׉¢¼¶¿ ,³CKÔÊ  P&…øÌo9ç½jei xö­gc°%{‹ò!Ðö`ÁMºÝ&™Õj-°þõ±„—ý§pw­Ÿ™'¿KŸTowoQgƒ`8Ÿ.æ3|>Aáàl‚¢ù…Ò¶ºBáËñ*úB°º™žÑá7Ñh4öâ½êÖÀ»L¸D¢Õwôh)C?-Ø2¡ë›äŒÃØæyò8¶Yža ÛLOÉY§Œa€Þ5(\z×€n:}´Û¡Æ;Úã¸kVOwC* jN¼XÍŸ­Ñl¼DÕGÔ›nôÉ€©H= pf”"úP#Ø<¥;{…i€JJÃÓNu!û3 G®¸xIÉJË¢n¾èê^}Õ^Í$Dí™$çEŠ:m]å›cIÖ%×#ìÿ¸æe±K)€hµm6“¼´ïI6˜àÕì£)«ùðv…h j uÍÕˆ=mns77þW^ÄÅ‹ äÕ 6ÐH!R~s“¦åº©‡î(¶ý³`@È:üD1Öùô–ãîŠê@9V[…ûkî®U@¨·ÖÀ\/‹/òòv½žÏþ âÞq÷â~>%™+wã* ïT°pÔ‰ sŒ·ÐXUh7yV÷‰'Ÿ×U‡~fítñÛ |`ÊF•ƒ]5â¶2  LÜužH࡬󖬊|Gb:Mª˜\=¥]¥ð!Î>å[c £«u‹$š-nÙ ¯oæ#dÆrÓ¬Ç_Ö¨S×"–ãõÝb¾ŠäûPT:-KpÆ´HŒEÅÌ£}ZUÉvøÄfŠ ³ÄC—¸H°ç´Lù᪼Lø3„€fO?0‘û}ÍjxÃHö¿w$aƒ',WÞœ¿*6mÞÕæjzÅÒù´Šåö?ïÕö·2¥±EUlùZ Sõ6‰ã']–N¬!AÁ©ð~†”†nNADb¸55Ç\âf¡=ÂÕ2O»o¼ ƒØ#Õ~®£ÜéŠY§ˆfŸæÃc_ÚA`ßÿì%ATªŽ/ŽYnV™ÀŒdKµ¨Q¸áû mH+déøˆã…‘¤Ýèe]¡÷6 Z€ó€²87¿~EÞÖ{8°*Õ±<ò¼iomÈ·_!-£óè©5Ø*•&/dß›‚Å=o èGò‚Å3:“êÐhc: ¾“ï¡ÇÚÆÐæz ÊX’|Et†5††X]ã[ƒ,–ãÕÊZ2U1p¢>}¼3_n°—ƒáÇ»Õb =’kÃÖƒKgúp0Ž'n+¯»,Âäæ1Ÿ­—sw>À¢QÓƒÛ•»²ÃÁ‚;HÀ­mW çfäo×Åàz|w»ðcFÐ>³ÞÕnQ¸™OÝE™Œ=ï)æ2º¾q3ðÖa8ŸNNÄ4šÝ®Ü­5^FswS¬Ø(½q"þæLýÙúΙúwgê8SÿÓ™ú_ÎÔÿãLý¿ÎÔÿv·æx 瓹G<ÿq;˜¸{ÎÝóýãÜBæžÜzË™ mêggêgêWgªíJÑÚy1žÝ]òàб»rrþö*´ád¾“În§‹ÁÈ­%Æ­%Æ­ %Æ­%Æ­%Æ­%Æ­$%Æ­*%Æ­0%Æ­6§·“u´˜¸…d0òÌdãÅ`9ðÙx«ÛKg왜ÇÃh:pkŽQô)¹Õ则¥k7„µŽßºZ ™7ñã®ÜRxåÀ+·ì]¹ÅîÊ-qWna»rËÙ•[Ä®ÜÒuõ‡{_ýái·?< ÷‡§åþð4Ýž¶ûÃÓxxZïOóýái¿wžö{ç“;Oû½ó´ß;wû-–ÑlÍÆÈˆ&ÕlŒÙj¼tü›ñÄ=oó-yÿôÛ¹gÜû¾ECxW ã]Ë0 a½2Œx Á'ŸÊc°ÁðÖS9FËáíôj2v›»Ž&^eË`ÓS•î¸Ëå˜T‘K"8'´Ì(ŒyÀ´Û6ë˜2‘u›Ë’ëüör2¦6ç€TõáxM&n!Àùõ|6vO8Í=CB >Í#–óÝj~ëY› 4_G‘)S¶Î] |¨3 " Å–£K÷Ì?¯ÜÝ|½{ín~޽CS üƒsàóùV¤Ô¡ÈÌßj|»œß­¢kÏ øËp2˜Êm´é`éî”hÆÆ ë–0*Þ¶wÌ"ÏÖ7ÞḚ́ËñÒ_îÅÄãq}EΖI6“Üá|éYvG31:œ‹6r×q>£ÀÃáxá†LçÌ@›<îye0s+øà^ø& –Ïí”·Wãã`=ðæw-×>ÐÕ-3µ?G£µ{y3˜\`Ëùt Bvøšƒõµ§¶î<E#¦><ž=6EóÛU‡÷ÈÇh|'âÜ~–Áb0³Å1©9[4©][´hwi=ÅÎî¥â‚+{ßÈs»oÔÇð.”òn¤8öñ¢)3!ÆÈ^¾÷ó-Ôp ?Ó‡Ävö- º»o!á}LD€_"(ɘýE<)À_®Dû`‘’¸áã°VP‡üp<Ô‚»pÞ©WÁº&_æžCÍ«¢-z6ÜÖš#u¬¸²Íy2DõÅÏø«â˜&UT¹Pºš+Õ^ œ-Rq…Ø.®Ùà›æ }’Ó᧪pÑ :Ü`Ô[‰ë|NÐâ:£ÓÕø4çöUØ|¬ÓxfeÜë>R77ÒŸ¾Tƒè<µÒÙõ¯ÖL<Å:Iï'y¼¥TÉ$À{ÔDîØ?ìWi^*Éqj]S"S<'Â[cW•X0Ðh0Q.Àíôn(ˆæI` =”wâS°´óDõÓZ­‚¼ip¯bUÁÖ¤)AͪÒñSíâ§:5Ö´NÂ~JYr «e}gp;Eá¬zk<ƒ×É*Ïâw¢Î3ø¨ô ný´ž¢é`!’~ç·õ¼)D&A׃ÈèN™\"ŒÓò£~D¢¶Å¯µˆ£æãhf}pF(’üh8Èf<ƒüª/ÖŸÞÙŸþnúûÓÚŸþËþôìOÿ×þôß@Qÿ|Êÿ‡]¬vgE«ÕzÖ"Ä‘)@ i—qºG~µÂàÐCVäWðHTm¢kÇ j&æ9 Z6Ì@Xm6Òo6¦ªÕz9ÿŠÒ~1öG %n¦X`ú“e"?q—¹=°¦Ô~l0MÞ~îHB©kO5XžÚ; L™ŒãΓŽe Jç0ÇJ±\c—¾ Ñ ,¨š V±ØÇÊìdýàr5ŸÜâ[§_ޝ#”R³“hµFª,’äÁg8­9m7r´"LkBrœø6 zƒOc8åzÎùüæ4€Û KªÌ×Ëågãâ'ù1ÝZŸ~Y_^¬/?ûtq”L÷Ud+ªõ-ypÍ–8ߎr¨ï ±vumKƒ;/€ÝÒP ![5Q8)Wð6š6 ¾ ª]4[Ùv¨E ™ïäõ"<<ß lIƒötê$ä®—Z®À;©ˆ S´k«Ìq“pj7…àý j®$_?I¼}û‡×zµ ߌLøü¼8À}\Åx¨^›šã·£‡´zJË·–‰†ã­•+€„g¨Ý⯶Òòƒ;'V¿äÇD{Ú‚móæƒøgÛ]R,Šü0‹÷>¶5zÈ«E€Ïæw7ƒÙhbÛ P´Ó[yË›â-ûœÿ4®ÎèºÒDb¯?=/×Ûáu¡Ç$•O¢™¬jpjÞ+«n¥8¤^éîž™h2%ò½­^ .iÙ|Ðj³øxŽ{ùÆi©m d[q U¼ó7lÇá*/ºûØanÞû’±æ™Ü¾”®–¨ÍÛÇ­8f~Q-«ü v¦HDŸ¼ýã-S’Ý5B“|óëÕqJE½£YÒØ3MÅk1~³ãþ^‹LQP¶Ôbëâù2Z[K1‰˜Í—Sä&º¾ñq¹m™DcËB•˜òÿZ¦œLË’_¨xeò¡HžÓüX: [­—Lr´ÌO™„N¼2y#öŠsG\x XmuS69(:ÑÖ^+ùû~Z½, fL¥(›Y³©¥=rÓä“¥Lx$ƒlû9nŸƒvÜ"fQNâîUj"]iV×ò¼H“þ Ûú¬Qy­-16‡$ùÚ*M@d>ê§¥•U°d8‰€¥†Aµ(„÷9(Çcù„Ì[…|ÝO¾ó©M[æ˜Au!¿‰Š¦2ŒÙ.Ù^ûvi¥(%žžé×·©öCTŽwˆ®Ò]2b‹Ôü±û&+( îG€SVú™Q%e¯Ÿ"PR¶i'<¤;„„¥T Bu—UÆ XáÀHKuÛ *Àlû+¶D4„ÒLÍSD‡x»ñ+)_Ð:ñ5}U7Ý“9|9àY§*ôbÞ(ØXÉùôTüW0ïé+!# išÿ®'à ¦Öé %ô!(étw€JÄ”`9ßm»03c‚P°|†‘Z碭™ü-¢ÀY>I¼GE¥T».aeÝÁJG`ýàà0m~˜ k—ÿœÄ/ùѹ§ Œ½)%ehº¸•4sóJc8é1Jâz9ˆ&hj¼K38)K~ðÔ§Çø§<£).•Ö¡6Ç¢`R·RÁ~óLŠ … X;9ò¥G(‚i-ù—¹Hƒ—ûÈ’QaÈŸMäÍ¿OÌØttÚەþÉ•¾«‹Ü<Á£­tëx°îY›ì{ùk•þ+©»£”Õ¥4n¢U2s¨m—ä&ü¾FX¿Â-„&=ÛóªŠS©y¥`Á ‰A©Š*}e-.À''Àíí5U_áMã,~t²h8ñBÊ2ÏÝ€ùÏL·ˆT„K¨8 Œ–f•¨‰9‘ËW®,Y¨‹\‡&ˆòN*Úæ2Þüø[¸bnÚ«¼èK:wã0a­!èµëÂǿŅåÁM°Vª¼O”²¦’bCÖâfÿ«œ¿ß•mùâ!z×A(ª_~Ì}T²*eêŸÿ àoˤ¼*äÞa¼›<oJ?4wº¡]k=&ùþ÷ÁÓ³5ß"âh¿ÿö‹¿ÊШ]²ô³KÕÆÒÅ ¡8BÍm( úëÝËáéñä—éKŸ&ÚÁÛõYãO¼û8XÝD£A(Ùç›h=6ÃgH”7Aù‰üPÂÙ|FÍìg’>>Q›â±È.Š4/Òê%€dp_æÅ}Á$y¨&é> )×’×#„¨|b3êÀêH¢  I’Ð*IªàJÕ£þê[t%þSŒ‚¼G´Ñ€ãísœi(sŸ³­¥Î4È#ÿa<¶n£VëÁl4XŽœ It=Xß.a‰o@Ãùô2šé‹/%Ÿu¢<#º5}aèËöàÍ»ÑûK[ûê­Älí}ñÛ•y)ZýÝÈÒÐjŽ>&“Õ%!«% e¿0oÃx„Åþžµ·w­™À†6ï2û “ô1®ŽEâG®XÛl¹=æE~~J«¤<Ä0–¡£ø$)´aUcщ]%ÿ<Æ;Õî2ï‘*ÔôÂÓ·øoX&tm:¶P²>–âg},¶d‹þïÑoßI–jÔ6A*”TôIþÈHvrÄiœWOñ!!ñh¬¸\u*‰ÓüXí˜ Ö³í³X‘©7Ä©rLg \D']ýöVQgTZyû¬JˆÝ§´<öï½OƒuhÇhvÜ‹/%¦û:hÓs¡emèØH©µQßJ’‚wÊ(yˆ»Jº-<º«´¤ 6Er<‚ƒZ@ü=ËtÓ>.çW×&ÁCë òB×óÅÝ€Ù)³)d[˜èËùz=ŸÈæ.«1„öÂ¥o›Žç‡o™åD'}¸0t[Ä?•­NgVÌ{i¼zÈÝ„†¹8¾Ü0‰yŸa°%!™Ú3y¢ƒÆE´xp Å0‹ óxŸC°ŸÓmõBp®fŠy‘>¦Ù— ôWÚ~$ŒÃÞ"Œ0‡°qó€íM XžžZx‘sÄã$؈B)zŒe”> a’§¸|j/ „é„Mq—Eÿ˜&qÉV9þņMa¼ó‹ îù¯H@ ‡ÜZòÛ ä̰aûú?R*Þ÷b½ {lœ'K»ló|eÙ&»D´¶öôBÎWÖJ\ÌWïÜ]ñÉM=X¹[ᓯŸ|Íô‰õ¶»™|€õ×ÅNÀåjâî‰ëÕí¥0ZEÖ.¸Z\OÝ€Oöž©^`xåééÊ=j˜swÅ¥~(ãhì.Ã5“H'àÃjíæ0¾¹Er|9z+7`²Ö^â†Õpâ.Ã`h{Àt€¯3/G7‡K6ø=CדÅÕØ“ÅÕÈÓPW¾±ûáÖ£&CO!§ó¥Gƒ-.ÝRÍŸ3p«‡åà# ¨÷’Öâ¹òè·ï¸Б D"÷'¥ç+­, ÔI]GÚ¡ÖpþŸè¶ƒy<ˆÏTlUä?ˆ`~©ËGKÂØ«h2 )î%SXÎ6¹‘¡Q0ƒ0_ÌöµXÀUFàéöµÁ œ¾6œ[¯¡=|m(/|¹“x}mÜ9`Œ(Ÿsã-:ÄtfiVV¼u§Z˜>¼L£‰å{Ö1ŸÇƱs7þÂôôÝ„Œ§#GcVP2z9¾¾Ø“ˆåÏÁ]Î'Öü‚§ãQtkÙˆh‰É|É@fF"õ—ì 2ßÛ mÂ~7ÔŒøñ«eRæ»gýàmmSâÆÓMZ‘âïU솙TbGÁJËÚ•?ÞÚq*°‰G,z?0û­vª[Qy l¨†É}òÉ©\àå€JmÛð(½ÛôWÉø3ôoÎ¥zJ Τ/Íâ'J¬bwõ–Rïzox³éŠ8ÝrÆÆfDØêÑÑ)cëF°•MáaÆèÑøòœ•:Ètðºó@z”­”°ï´8ªØÊ6ÚVüõr!ãb±¾;Ðo‡qÁ÷wéæ…Ô)ºÇ‹àåfdž=Š.­–Tï©÷MÿA~ºiÖáæž&0-?qŵ‰w|§Ô¼¯w« zCÛä^O~»nãÖzNËô~— à“8 °ÑtÃxóäÂmxzT~Šw©uxQí )ÆK.úØ`²F_ïj›^¡ÕØ-8Á7‰Ö©,%1ãÇ;šHfWÿÀÒ#9\îË(kN”ƒ"ìvùOû0§B5_ Ø‚ün8XŽ×w‹ù$‚¨¹¹À­~ôû  ÑÄ„ãýåwȧˆÑÃ7\1’>ÑGô\ŽUºû}Ι 1Ъo^ñf“0Cùo`ËK=ÖO/†šªÜ²^Ë‹ï£ï#Ó=zÍ_.ˆw‹¸zr2:¦»­ÐnÁcàRË52ƒëUlÏâˆlj]ìЬR¡ë¼—Á¨³‡ F©ô¶ŠØÛ=¬M$ÉæGƒÓw¶ç.Ï•®ñ‚vÂ$ã¡c„^ÆÍdíê‘ÀeEMõ—¿ÿñâûP•(E I_8÷+ ¶K Ãšpµ‹ß@ט ¼*ò}ÝmÖA=k‡ÈÓ+gìâÍËüWsÊÊ ߇ÑûQž¶si_=:6®Áw.'“ë;gm¿ýöÝe5|¤Æ¥Í#”¾¤1¥é÷°üøÙ»ï';»äuø¢êP]&…ç®­GwŸ$ÏÉŽ5¢G=à;:®Y‡n{DRëœðÈY'RÞ¤O;“ÛX"…±9ŸÐÖ9È`Í«¼§#WÉ.Ù(7h[|öe=Û™ºv9AÝò«~øÅ§XH&âP8Kfç·šë Ľgh•ŽÏŸÑ,mn¯Ò.Í™aßyÙ°$ýFžB¿J}š%1¶ë„i¸Îyj¯šÝœ>iþ¯v“JÂÐJ'×žÒØgÌù|:TªõÊŸ¿¯å³Zªkàñí7¨´â"#Ž+]Ó!¥XZ{†òϽYg=ùÆã²”c\k´Î%êÆíCSîÎåà—ä>òE’X,^µVµ˜«F§HX®ë¼q£|ëY¶pçªxï“f±w{X« ±HæëfgGó÷>w Ç*kì®y<§hTFõe8¢ˆ~·ïÃÓVíA÷]jz½y¸ÈN¸:f‚³•”îM‰Ùäû«tà õʲîqmìpfïzõ¡¨ïÎYÔ¿÷.êß Eýû9‹:F\ÚäÕýh±[Z(ÏtàÙ…]a›A˜SÛÑ:Û¸aR:³·UÔʰ?ºÕŒk ›œ»Ø”xu2—I’=VOØ$’,™¸( ÃǨ‡p“é«óÈ¡)„¾ KƒÆ?jNïéSºù }ÚÁ=z÷•º¶VSÛPºµžQ'6PO‡£„±ð/‘áÛ$ _ÍЋãØï†ðÍý‹Wø5˜ ¹Þþ¡¼7ÏD° o£^s«Æ¶!Q˜†¨»î*ÓúÔpÛMB™\D¸"k&9ú àIÕ|"`i/2½a³z {Éz3.«„1ey !£D)HX=¥åÛ¿ùPÙq¿1t7ˆ³|Ž Êv5‚0ÛÞÌ[£AÔ½zÑ%l+q^VÖý‘A$íÅŽ>ª£~w$NÎÀ~t8·žT„èh‘å )Ía–úHà@lŒ ŒÏÄÀÐå¥ ÃÄÀð%¦Ú{‘)‰¹Ì£u^hê%r^jÊ ÝÏb²ô‡%“¾¤d³c«aM93ž.Ö_ïôË4EÂb2ˆfæGã†ñ-Z&ÑÐüŠ>Ý Rñ—D²ãa‘ΟS6¿•ÕËÎþ˜þËúvàgfVPBb< Ê¿â*¶>ΘYú,ÂR¬’5o¤˜ û´äÁ,"ÑLÛÄÙ2¯âÊ*Ñ>fÝfêd±Ëiž|”µu½]ZÊ7Yí·¼fÀÛÇ‚Ñ šýå‘ǧ™iÈsð" ;<]…€#jZr”–‡]ür1´¬’ª#¡WÕá$Âô ÎÈKoM~¯ðM; ­§Ø²í±Ü²ƒcëFvaÈT­2Ó“3zÅlšûŒyêûDÆÌjÏ,;úÃüò…UP}óˆÎv”P2§ŒÃâÄb“-ŠóçÓS ûfê—ÈÎB#r/Ö‰DC £“~Ø¿\-‡iEì"l#U;ÁóÝb½*˜ÅßýüœfÛü§ÊX¤·× Þ.Wó¥•<\ÎW«›A´Äëñ”øó BÓVŸï–c~q= {3‡™—ƒ¯žt_|ùß f#,m:ÿ„—{¾œ&Öçh8Ÿ™WaÊ”*­ô½#ñ5Ýè›Mâã>ÉŽ—qa}/’2ý·rmŠûiœÅ‰ñF½L,Í4ñ5ÿ™%[)¥•ø3‰¬ŸR;‡;Xùî£8ÿØevÙ‰ðÀÿëÝ„Pã vñÑ!§Ló¥zÀÆÆÛí,WTÀ‰ë\ü9IË Bô»§½¦Í3¦¶Ž›.ˆšâRí ;„EÊ>e.ãÈuÕ×Äß·M³sâ^>VPñâµjÈʧÍ!øT ¼ ®?ðh¤˜k>ÌH O92©\6C͘²D2¿¾bO[³I|^V‹"秦>&/ãçDÛ»Iøïß›Hàú,,kÂ}þ¬†)óVUNÈ`Üÿê”a ÃGAÙÔE§vbÊŒo$Äßõß7 e)"’28aA9T\+s¿þºßE£ñl­ßŠŽƒÅ;4óiË&46ÙÝ­†ƒÉ˜Dq=ž—ƒIÅt°ú¿šD 𷃫îún9_ÓkÜ”?ˆHT¡W6ÐÃ@ Õ`±˜|%w¶D7½ímX 'õA ½k/(Лˆá¢«5G­ƒ’+ų§ÔH“Pýßþæ…üá‡üí??äoïü\¼Ó8AE^ý÷ߘÆ~¶ 3›`048ÿ „GdüÕUs‰ î À òùN¯ÑwBéîx˜_ô_Œ~ùÀ”Û«aÂ<Û0ÙÉø›•j¾fú}±ÿ#ˆ4-H$žj¶šÛ³5÷Ôy…¨ÛÈ¥ˆ2¿æE„wFõ³˜Ö•÷¡=°ƒéЇ(<ÏÅò ­Qö+û”ðÎZTÎ’ZTŽ%UüØé½u†â¶l‰EnñÔb[«c ïm‚ÐT*¼?[¥XÙ’•JZF[¶tL«— ¿9Éðœ“Du0fÎðò4Uƒ¤˜¥ˆW"!ùK];ÒðB½ñÃøÔ :r™VaUCžo†›,¨•Pªá§,q%½†\PÆE‘„%îøÃ´²®¨Â•„NrHržËUx.HkDh•ýN* ?úxØ2híËô¢Oö3›w£·£üx¿K $+ÿË™úâLýÉ7ØœëT¦ 1ß´ɯJßû°!øZ@á+GL„9vZýYñ‹ŠB „–‡£ýà&ŠÄ ”û¥~h‚ÐìR1i9Þ`SC…ñæõ&÷0û‘m@Êô&†Æ0—mLAU®ðazµËãŠ>J%¤2£2Ñ1D%À5B%Â1@%À5>%Â3<5ôÓ CFÃÒP™ñfDš:Ø=2[¬g`¶8÷¸laø°l!ø¨”ß ”¨“Çd-WÄ!©£=#²ä°ðÇ]\¿˜Ë›ùbláÍ| 7ñ›EdûªEBõ‚åãsî§«â4ãý€t™ !‚Ýé¥?VžA‹Hˆ´!(PÅ[ó7)ã<@>TÂ9õ8Û Ó¢F­ó†’¿4ЄŒ”ÌZ<Ñ:}J—ò@’Uß-O§jˆ7«›i%E’” ·[ ‰Z„¨? ¶Þò×µö¢Wy~º²s Lqâi>δbŽÒ}’ñ-$§É‹ð¤ÙË5ñåË0árxA©ñåËš_Kd©õ´6òÙÙ«µJq•HD´âÌJÍöG (XÈFl!±MüéJ„ŒÇ6‘•lU-ã­ÃÆ&ÇNPk.DjÜØc³(6«ä±tAøqTÙþã$Üç¤0¾gލ±³9¿k3yäÑ~|ÚPø•.LIñ2ðòh²Û»‰ÍCH÷ Œ_6Œ r$˜„Ñ9<Ï Ð5,}ãHâwƒl­Ä;€kÃZ¤SR­ÝEo·¶à$1§oÏ ´ÛÖÓ~ 6É„‘ù §[w×Ò­'gp–Ìe þw€e¡Z€g/¢*v‡Ê þ0aŽØ@ ´­D…[³V‘ýö¬°hM¯Mk fÕš@§]ËýNU’±lÕêOÙõrþùŽ_üIÄ—…%RòŸÇ¸HX"‘`—îS*ö)ßYÒ”õ¬5q¨¥Eè>¦reP*W^­5p‚ÉgÔ†àhó­Vg˜¯‚{Á!Ü·¹­I(¬/´é ˜çO`¸qp‰ñi"% pJ¶j;É ëÍa|ˆ7ün zÝnzœˆ:Gq©Ù„R@Ùá¤n%‰Ð¡ºÁ·*“Žþ†iØë$c¸§ðªUû9šîƟƳ»ùÈjZ 8›Ïî¾—sp5¾¾ã·+¯½(þÚ©Åïyô£†·—Ñ›ÌWÖ´¡‚ă©\YJÄB ó¼°¨°ì¸÷²b?£Ÿ8º`Ñ,Zƒ£ Yð{±§ƒ/.jú `$C(*Œ†óÉP‰âÃ!ɶÑ·@*[ïz8}nQ™ð¿<Íï\{!@2”¼ãO¡voþh|×ûù–ðmZܽÎÑ !Ulà&>Hèé0x åœvX×àñj+êò ÛO52rOÏ*Ø»}‰€{ °xÍœ —[°øÛX–$Ûežï™Zôh¶rÙÖBíb'ATL©7±G#Ÿ|DaF^B4ü"…hkYóTÌàTllûT!ìjBïµ£`‡—„ƒ‹éž*øû<¦ð­F(dÀR" Ñ~»;ý Ñn—Ñ&ìÖAÈ3 öiÛ&“p±î¸o’º„Ú¬o‚\"íÐ×@¦@ ®CIà5½j˜GÞèkßïZÎÚ мˆõºÍÿš8p­hRõ½ÆB¯QðªëÈ~Y„-!»<ÃØ3€=C×3hý‹Q×G;òN9±„çÄ»eÔÞÑÐFábøƒÐA#þò®¡àÀv‰ u?©ˆ §âˆÅaØð±ÅŒ¿i:§( °w9|í¢ÂheéÑ*EÂoN†ÃÏPü<ƒÏP¬4-e¾mAÈX $#Ø[ØTNö¥hààÃа›Cƒ€á$6.ë6 v,h¬ 'p%hx¯Ao Ìy ¡œ^ƒYž‰Wª”-bÚf€|¨ÓÀÇ"Øä«ÓÀÎG‰m9jH|ÏÑ‚Á›Ž Þu´`ȶ£ƒöCý`¡°0ÏÍåE÷uÕ vÕ‰wÆR!Fº¢b¤£+ét‰Ä‡Ú((<Ô@q…Ÿoð73 xÐãÔÈ—áé$YOF›ßãa;BzÚÞ™«ƒ¨-o£ý¥ìÝM~-Zã|íJ_x7Û´{ª k:D‚‘-=“±;A\–€Ö·xzÓõ°T!J­† ´ÿqŒ·Æm6(ÀÌ µ½¡Èö‰ q} g©%¨d–+*„ŽF‹U(úz‡`VâSF4d4¶»acÜÃY¹ Šsfl×(CÉÀ-P‚sŒcýò¦~ÃX¿ŒÉ#iúÝJTpÏ1Üg¤÷Ž`÷N ˆôŽ_÷žF/™Ä}’Bèµ(U,x™’ @îRR!ðUJ*»IIÅ€)©Ê@¥Á‘k ’¡äÍ( µ{#@åÀoPâ¿Ù’]»EÉ64U*ý%wSn|¤ýõâi‘¨ ‰ZÐsTCbþs Þ݃€ÁË„pl`Q°‹„ x¿9¡ÿl𪛕'ä¶cid„Þ!dà| eê£Lz”éο剀{«;çåA*0d >ó¥?ýòR0Tàõ@0’~;FϯðQg·tZp/v+ÚýÛéDîgÈØ{ß'#o´h`îÀyÜÈÓðFž£•ü»y¾ˆì‹hxネÞؾˆ†rî‹(ª ö±)3€Öêc-¢ xs€ƒ/€¨•Žca= àå)¡6ððtjF€a‰fv›½n.}-a˜z7 Ç®GÑ­ #!s@â÷¤àüXm¸£²„x)ÎWtÙj\]Mᾤ2|uDÅ€ìÝÙ§ZpÜ'dÃüJÁãbC¡°ƒÍ†ÿ9AÍëÕÂiCIx/KÁ>eàÜ–µ4U ±TMÐúψŠ@ÇS%ðd½ÑwÿXáxÓ“J9¿]ßMÆWkf=_ø ËèúÆËçr¾^ϧ.EYˆ'÷<ý =ˇ¯Ä<„äîtû úgh¹WÖo!{ë*Ù⫺…NÈ'Ì-¤fäPaè3zjÃõKr¯û;âÖÔàu•qiqäˆa•Øs»Ÿ¥ÍR'Ï7o޾Þ_ ÓT;yoBèäÍ›’ µAtž¼DfáöZl÷lpú~ÚXc$_óv’ÚaMjh9îN-¡Ï~ÖÀÓøµ. J­È4ÍÈ\ÓŒÊõµgÃÞ™õšµÜ<« KmYR³Rç<â´Qí]=uPÚœài[æMÝ=¹“f3›ÍU‘丹­žByꞎ3QËg{”¯¥=ÏQ!žy‡Aƒ>&ür[-ÕºÙVK}Nž n\hxãÂaäø7.4þ„ 'ظÐðÞ ½=° åÞ¸àó=àèt£¬ü.vg!@[¬ ì»DÀˆAÇÅ&ˆ;Çe€›ºnl/#cB4(6¸yã$CgXœªŸÍˆóëSòÅíš Ü1e#|á×$w¸FlöAƒÏ&sp·"T`û0ί\;0–8F%˜¬Zx{º …$#T¡ã_¥"£74Pv=Š^fÒÐworÀè€ßm0„{€6PF^Ee„îT˜ääáñF”&}x¹€ƒ^m¼Óä@“ð.p¨½î’ÞÌÌ¿Ð5)|‹N.ògXúÒÈ¢Àç2Ç"É‚Ø+% ‚OBÝš‰À&¦ð×^^€Ùìx7`~ˆõ®ˆ ±ž ÖÛ"@a( ä XA7„Û0Ç- ^Ûš²¾Àµ«IXåz‰ ¥®Eä_ïÚ2ˆ.z-(¶ò½.âmÊï_fJ¾r©xøOz‡&mò]^à”"ÙAýÂDdƒ&·b×ëCÎð½ýEëøÞ\¾ùÙxX’ögç窠ÜC2ë€ VG™îãÇDÒOóm²S˜¶#3`ãͲ*7¦€yÔÈ +N©Îô¢€uÉÞ£à;-BUc]ÖÛKó.ŒF´/é„LJ:"b‘ŠF;ÄLm^tm¢CÓr(ÖðJ˜†¬›”¬$ü¯âñ~ÏeÁ DUCƒxñ"´¯aÄ‹áV4 JX‡ªŒŸ“­Djx‚„¡}n6%œGHë°ðÀ:<ØŽ&qüû bŸîU²åƒ5Þ0Ûz~0NüP¸_•p”O•pŒ§ï8$´ïTGŸp˜§O„Ô'Ì ˆwü­r8™Ïšl&Qõ¿õD‘ &Ff!dU(+Që "®9|f‹¾ÊõÇŒøovš0aÝ”&Iý™BiäÀè)•™'Š[D™(P„)8Z4§oÛÂE{šUÄÀÂ›Š a òe¾œêÑ®®¸,xn4洛»\NÝ$h¾ìÍ%9ÞnõÕp]¯c•î~ŸÆ¸Zbë€Úgüº9¦fƒÀ^MZã®w/‡§O ªIÄëãß•¤÷ÆŽŽÁž›ÉkòÄd'é/I‘lÍÌÔù›…êdÆ÷»ΫhÓ7 AnO0׺ŒVžZê)Ù s¼»“CMˆÌk¡¯¡Qß?CM$»¤>Bo~<|¢$MVõÍ/ùž-°R}×~ÄéFÉsºáNÀ‡ôñXÈEÀ¹q­.%¬q+þf¨ 3“À…éÄñšÕL U±¾ý˜¼¼Wg;ìÞÁÖ°x4ÿ%Ê \þCëù§h‡ å64‡(Ì‚ eJë7LA9„ëÂrΘé¶û¦A”›x—˜çÞÔtMÐI³x}H+é ;¥<™âä ([ž¨|É3}Ù ’%G’uÈÇ §$.ýô²"Ê`'¥ÉqšcRK­“ýc)>8ƒb9þÇm´üÈÅr|5^’ ·³Ùx8^­˯~°ËN4 |ªHÊJ×Ýß}º»r72NK=au<ò‚ÍžÞÌÁý HﺆÀßn ²ÙöÚbñÔ€´“¯n öæ{2ã¾Nm/+»d¼FÉC|Ü6[L¹E!2…ÄdÆrã.¦dCJ‡È¦Ì˜"”5rýu1¾[Vëñòn5\ŽÇ3v±Œf ìAEÓÁõøîòöêÊu …ªlð6ã¾—êè2Ô ÌŽòj*'·ZôN7\;–Ѩ ñt„ë—ƒ ö@Ägœ=§Ežñ@Š ©ð]ÎÌ(öÁsu¹Š“:ªIñ,~Ö´ö«­x0ànÇ­|½‹1÷™Iû§;¾ æø«xŸî^fñ>éxy:…ÊN±¹øEôÜýØ+ƒZ W¬a“¬æ2ø‰ÂiS%™ÀY-"<úÚBZbœn/ãG6’Øøà6³gwÓB/Ç“Á:Ò.ÌQÓA4šÍ‚Íæ3£ËùúƸ™/£oóÙz0qã>—ëhèC Ç–êJ½ôJ@ÆlÎpÃüˆÕü–ÂHÀÏc'?BÔÍ{dŸ~ù!/~ˆyìYÇÜOñK‚<‹³ÍS^¸1ÜOäF¤[Ö•Ì!ö5$‡xÊ[±‰ÿ‹òÕùìï»!tÇ>Í܊¬dËðx÷))ø1àÛhäFó,“á-êÖr$zÎö(ZwCÀºy¿äGq¡§ƒ/×Ëh´Š¾º´Áð«Òéí Ø‰Ú°õPÅg`±m-¹¦þ(t'þ‰²‡Ü‘ß‚ó)òŸR:pHÍǃbŒ|‡ÐÔˆÁöŽeu•l"~N«Í7e Æt1/Øòæ1á5™8’XŽ6•ôš™#mƒƒÄzøBË)Þ»OÓlÅ7¤!®.žJ†íñ}<£x»• ÿ`–h^¼ö›ßyG⩎P.žruÔt1XF»¥U¡pq– v飰¿ÀbpÀâkomŸq ô{ä'˜écª-ìD¬#¡Âõ¸äùj½F§Ùs¼K·lM$?„‘]- 54˜¼yKsyj¸ËóÇÃ+ÉË>þ•î{ù ¡a£ÍÅgçy(¶ReKÕ³r-’}þœx›ïPÉ€¢sLJ¿6pv®ƒuÐÍ–ö%ÛŒ˜à ³¾HYÅd{›À’U ¸Í¨ƒ0“Q­•€V±…Ìb£˜@³Óì¹õôà”g4….¦ÉÒ>H fÉèÉ€ukpÈù&Wufå–\ižŸP!7¬\éKÖZ®ôO.ú^sÄÙUç+èÍÓužªðd'¡’QÖ½äˆnr>99)Çh·Kã][¹ß‡Þ»®zºR#Ç ÕC W‰]}@M¥{¶ž=)GŠL(T2à ÄÕæiü¬KÓàóZ|z略Ž˜ $Û6qbóÀ…åÛü÷4©žò-ÿZä;YQÏŽ §úýYmÿMƒ¹8È7Ë+~c€wœ™Ôe²ã‡J»Ê@¾ðoNU%µ:Þs—Æ…ê;oßÊT—ðÈܰérǧLŠ™$ËÁç»õøËšÎgÜ£;Q ng«ñd<äM6wüy¸‰q{4Fµ’»^ò~e8‡”í å…€{Ž™^3T!†…Í¡h‰ý…¡ipÍ%ÎJE4ô§¦ž4Š´\Õm åÔ©–É?IéÞA(6\ýì&¬"|x¿O+–ãšÇë}§…E¾mÓSÁHé/• cT EÿNÅ™$Ù#¿âïG•”;{‹jQÏ.ó‡¦ ©´ÍÛØ5•æQ”¼87©åfÃ96RõïÐÇ¢-í׿­Š!g;1!'e,˜óP¶š†ïNÎ<Éw£è:Z¯pÔz9Eëh>Lîn³oPO×ÐU4]L¢«ˆ©bòã`öÁ‘̨? \É“«ÏÑh}s÷q°0^¬[Ç6  ûG!6óƒ[YÁ$¿ø¿Ü“±y€áD,ÍlÙÕé™Cd`s¾G)ë BoKF¾Óòìs®ÁÁî„0Ëš+…ƒgfH<²œW|z%¤ÓÄ-“Ã.eÖC¢`ì"bÌ€‹L<Y’l“í <·`DVÁê©ÈOeK¶Y<òx®üýî˜ÀãÝá)À‹[R^BñELì f£¸‰@·´¯ò›Íq¿H%;ñJ¯u=€u9’êü ËŠý¹Yæ?/~ûè ŒhÿH¼ŒRI–A-Â]©bÈ•“ !5¿xãuGàáz¶ˆ…7ïžiŠ‘©Ã÷13cy@™±gbŒÝ[©:¦Úï߯BÌ-ÇŸ`Õèþ¹Æ„ž÷¹çw‹ûTˆ&¸òƒ_y:·ò ˜ÊÑÁ“lWñþ°KÄX3݆A‡‹¥sÁvüx~5‰Æs% :Ô£$à qÅU,5­}ü¦K£ó‹²mºI“’g½05 ¨~ŒTº„zÊ%¼Ú:ßOnϪ?Þ%<,ˆ+p{6t´—oãÍTÌÜ;hM*wRã‰4¾ñv»NwíýNVÔD?·MžaÜ_|#€/zö…¬ž~B×{âñ°;–O~ÑGuÙÄ[;N,x¯[ F¢ñ;wIäà9™Þ,]B oS tj QþßN´ Œ¦iƇÃR®5ø+LæJã8;î¿ðüK*ú+½vè ´mMY€ðótÚ)¹‘NÁ#<˜ Æ]!„¶’H¾Š‰`ç‚Ep.Ý¡:&Ý«üX˜Á•mo°öÜ7´" >ísU}‘!øx/RàëÃ=µ7.í7‹Ü¼œuþ"9i¾Ò(;¯Ž¢ ‘-U Hg)‘§+ÛFÞ±Ž *Cá.4.m°‰A|žâR´0ã%6‰¾yðܪ‹Fàn’ÉN`ß–†×츫¢(’]—‰Ùº¾âÉé3ZŠ¥eThãB_«Öhô‚:µ0€7Ù•$wþÍæ²~1*‰Þ‡‡æQ2i)sù¥J¤c‘gÃ-,Ìûc}½ÛìçÓjsÉ ÒÈ‹á´8ÇÝÄ$•Q›¯YGZëò¿ù&Î.á—üëXjkWŒ™ŸrBÙ?øÎ´5~O箸Þ„}qƒàß ^Ï,Ò_8gá•ÂÖ€l^{'ÙÎñä½d¦V'âˆú:Öž^—ÉJ’]ƒt˦\/¨ñj}¿„F&¡¹É),•ßÞ‹–çòå¾×÷K–A( ßñþnß"§  ¡œ(ÙÀŠœ›d’–^èpEAUOÌškBú(`9Í‘¬ŠÍB–›‚檉‡Cp ÐcÞ°óB]îZjþ°±³'Q«C¼I‚B´O`þ ù~7¹GÃá]Ý §°gl.£«°‰ÃQ½@ÂÐéÆ(|mý]FE¾Fã/_¿6ûy›«Í±Ê/£?/¯?§n½Eóú%zEa|ý¨B#Ç¿ÀÞ£•à•­Ìñ6þ–“áÛ·°’9¾ŽÍKŸ8N›½2£è5{Â!p{eûÜΰÿ© /~pE»eÁn À j0Ìòìõ4+Ë/… ©Ã¹FÅ,^‰Ê.=€Jy‹Ø…+åcÒAì’¾Ô÷m²»*(º–‚Þ´DC¡v rÿò5eZÞ•PX”ÙÚLx}¹íòxën6–Q}æ å]ÁèÚ4” iÖoö• V›·á¾h’ p5‹3;ØêÅí³?¤0OþyŒw¥ºûÜ\Ziï¦(d𬠹€ö‹!P!b4žÅzjsºÜBM¬GE:qV'bKÔ½\šÃ¢{€mwÞ_»N^ˆ÷Fé@RFâ D˜ó‡¾½EÔ#Òž „N88~‡‚Ü{ðTŸ;‘º™Ðü×üœ&×C ›·N’­Òq¬Ê߯XOÙ§• bk²„öÍ:\¸7¥lû bç“„êÑNÝLžfpI¶”"¶!q­YþÖºÍ2°ë¯Ãü)–æ´k¯š*xD€Ç”ó1.»éÑã? óQgo×ÔíæÈMªIz_ÄEšø*Þcó½í(ÓÞ‡2ò¶©ý>ÛïjmÙì^Ïìò:«ýåçCÌÎ%Ì"³é=6—ƒ€¨bp¯f…Y:Ì1JI¦2ÀYQŒ!á V‘Ÿõ æÈüšN=¥Û\&“ƒà”,¹%ÇÔ÷è7Èh©p{…ŸRHÜö@á½³;q‚v3 ™©Ý³¨ãкë¬:Hg[ë ¹o`‚up& ;îùÒ ô"ºÜÄÙ.Ín~l!§@#|ƒ!n?DÐé‡Oô¨èt¯bOœï>ËÓçƒÌù$ÚI5â\@é~t‘Çt¢òr½÷LõÚ÷`ù²µ¬–µK;¤Ýíœ=hBˆz_wàd(‡}H…O¹(ãÙ÷®7?‡'ÍKÒ3§]΀rÕ49¹‡œkuŸÛ¤ÓÑ…Ï }Ý $°lúÞ!áä×ï Œeï›$Ü OºL‚oiæ»gR¼¯‚ý‘h)µˆdû˜ðÍe ­kãÑõøîÛx9¿»Š&/r6¿›/\($Òþ£¨ ÜòDZ¥ñ)g-׋#giÎ°Óæö—ëørµ@6ãW Ž!åÐ/0Fe=ÞòÓÌØƒnª·ár€Ø¶o=p<Ô¯3£fvj8û°È¢çÂÏI™¤öû e_S¡>“P7^”û–6M8#œt>¦??r•íeEês(úÍ |t²²U°íE3^¼ëÆ £¡¢™s5™ü¨ÑüörB(ýl4¾ŠfÀE: ’Ÿó]Ì=èQ¹XY¹%³îýœ™4%]yX¹Ü$*Ìq7-#ãÈ@е¢ ë•9vòF¢Ë(ÎWd 7ÊâdñoNy3À4ôÕ.ÙÂð £X?xV{øüm‹ŸÁ‡p°ÇFGb;òêˆéZß)%ŽlZ~„&ÂëÆ¿ ûÐUeõ¥›€C=´Õqà¿ðTGÖ‚<g`¸‚¤à!|’eów6Ä™=zMÀk§¼l:ágãk,ѰM¨C XâØ5°øQ⎄ …^¢Ìé<Ê!Aæ0’«@2ò{”Ž áûÝ;5s´!Á.™¨á5”н‚” ¾Ò% ¯¥Èîê)/úI¯¤ô¦$XI2¬C°ßWaàto†öH³Äò¼¢Ô`:6"‚ Rm`)`¢d›`Šlßöî[’tß’Åû6@¾oCü6HÂ-t<»_Èoƒ¥ü6DÌoƒäü6DÐM0 Mu íõ´`78¹ˆ7?x(,>i1(’íÝ>.ø‘â¹"–?µC„ŠgvˆX^XÌÍ—Š¦‚e‘©h^è’?÷B-3,ŠLÄÊÁ/Š‚wDë VÖóµ ³×ŠÕµ3:{ ­Ýû®(XM pCɧlàN€^EÁ½ËÆ©CŠFˆsõ‘ƒ\!>\Ý®ªÞá­^¾½c[!Îx\*Žî-‚Τӗclœ!8Gðinù&Žþ9­íà)s3Æ' ´XÎãå:Âfž¸šOÇ—ÑÚÓ7˜L(Ç´Ôqº„‚‹tŒøv{ØÆ•:ŠFz4г\Ú0"öR ?É.ÔYbêœNµMngµuæg´ÿØjg~ÿÚ$ÎIéÈå1«˜Êj“À"ÔÚºB{³-‚þˆUÀ¡z“²x¼÷böñá (3ݽYÕ]ÊÓ¼ñn÷XÄ/ù!fýîE»BÍ,lã«d:zñʉ5N ®@¦è‘I`6ܵJÉeó”l~ v;~˜y.º‚ÒÂíMýQƦérS$•mÔ .YO¤»•ÙO;úxŸîð5sp]Heb¾a \^DÃåÙE°tÎþ»\D¸7×MEvælü¾\7QoW®moO.Àwäb`z—OãZ  1§- å­@+棅¡ôÚùn(r’Ô'úd޳Œôǯ‹Ù × ™lÙ"†_ yÁf]Â(,ë¾™àJ )¢ÒÃu-Oùø õ?ÞS'"ïõÔ©¿æEÊ C,ùŠƨÔi.«©´&\ƒè~šàÑõd‡‘‰]–=p‹[E;ë _dC¹A_½ uP‚’!Ÿ¶ œ;m‘» | ¤MwßúÚÂàc§m2²K¡<Åôº@Ë—¿!…Ýw¬?õaíÐ%Âþ‘6ÿƒ£¦Î²œù i›×_pÌÔ—÷+2m³}¥#¦$þ}˜ªŒ_ùħšUÿûÑU.õ³?.}Ó—<ž Ñ "ÖíljÁ¡„•Ç—üzX‚)ªV"‘Ø/ƒÙ8« hz ×ríSLÞ[G <~bªß LÓdŸ/bˆQ÷ëmزqˆ]d÷ GËÆà·  ÒÁÛMla¶uãÀÕSëu¤À㌥Tlp°ÇÝî^hL çVB÷Dú3C·9ΓlUôgv†â†—é´ŒOÚ7°ÙñB›_*ÝcÎÖ·§4Ê); 6·,ùYï’2ïàH(­òh»h¾_:6¸ö]=áÜNÝ7‚8žuïÈ΀ó©[ÀÍÜ©lâmžl/h]ʃõ˜N¯ˆ-È’Jzží¯)¿öZ4ƒ<‚ÐóVJ1Ó^¦r[£‹ô>­¦Ðovå")lƒmGÞ–à£eU#VˆƒÒs ¦‹Ô÷O¤ ¦=çŽ?ŸîÔMØÅ•~Χß_éÊãQøO›Ë“ÞCIáÛ*´uê{u$‰-º_G§îÑÖþ›= ´·IÉϱ£'·¾÷;zØÒïdçróa@ ‰EÊÏõ‰kChPìòi ,޲]Å›*Ö°š|ä š¼úpCƒ,,f£dÃ}:¥<í¤Iœïãã²ÉY½Áȼ 3ÇË+]Ä´ u/!²«ŽÐg’·˜‡¼>a?¾î;P~²§)ýTƒáËŒ,ôYï—Ú庈ïï)!‰úP‡Ö¹QÛ²²ï4ö=€&¾ÐDØ!¬B|B´™Šã;] ؇¨ó«7Ÿ=0V0¦ì¼˜äYÔ@ü_Èï§¡vñ£§D×ËÁååxFÌj@~Ô²´¤XI¾ÇüTZÄMæ&W–²m´:•Y|ŸÕuÝÈ#GC·áo<¬Å~Ô"âƒÎ'›|ð-uÙx¤F¹Iºªâêß&Ý’·D·) ªè6•. ÇQ ~ʹ“‘ï`‚‰ÇO&˜È“Ž&ôdFÄà NÜE`e'ƒø¼ÅŸs.vIüìtDA7Ù#ü¼O{¸ˆÏjyóéá›WÚ9~ƒ Æ•Ž–­![üzž±O3ÛRèÒl¡Nƒ·ëDdÑ.·XPîX¢e€Àh¡Ðpºtu ŠÁd”–ê îj ð©Š@—& Ü‡™µýóóiã6¬¼±À´HõŠˆui²mCÃUµZ×)táàfÿ]sœ= G#¾JæÃ§t·­ÝÇ€^¢ñÀ"õO,ÚP¿khœ–•2é(Å?»€ÀÙ¼vîapöJʽڌ¯ËÿUËïn»¿,ãs×É´ïÌ×KóµFǶѣýø Ê‚`œÔˆ½2oLb™Ú8P=v²Ñ—²¾›‹:eû¡ï”á©ìp7C‡™2sÝ‹øêFÌj+Ù‹òí và…°˜íŽñKC»K3úí»}q€Ï+8Ðwnàê׺(Y×PJîÍ`îtûHΖ•°ö’zè5ÜÜ:=`bï˜sA òèVrnIH<òª?Zæé,ìé.ã94w‡ù6?;$ê «!Þ“.w•û¸êuäf~ê]ò¡¹i‘ÂA6¯?÷°D›í¹3¨Œ_ù0ƒšÕ©WÅ[Œ¿ŠU%¿ªc¼“¤õa¹‡üâ—:+)^V³+ $YÍÆÈ&­xŸ°æ¸Ü囀}¨æo7%½Ì.y!•Ç/BA…©Ê/…tÁ¶éUªË—oÊÚYžÀ?-G/Y¼O7ÐfÍ>>hâu½‚ zYò?¥PZ2‹fïÃz)‚ƬAZŠèWÛ½ŠSšŸ!DøÝa^e/åS»rBöàr"ßx»½¸tõ©!)¬‡¯Çzôz¬¯^µ½–?ë¯Ç]g¾B^«Wc-Cäÿ´ÊÐÒã<ø<ÎUš¯L~ì÷—œäç¸Pɇaär¨2°—BNbi¨ÒÛ«#'}”iÔö ÇI=ɳG•üCùì¸o?‚þµ¹pR))jÉO#ñeÈ'dÓÔûp«[ÅžÂxuF=@:Ò´Gúä•lÑœè¸Í\œ…VûÌ©rÓë…êß×­ÔÔ5òð–ÚÓ!†…¤nKBÊû/_i¢ä¼‡¯È{ôм¯^‘7°Ép6Þ^‘·=T^1³ÕëñV†Ù‰}Ù*’?³mš~jáŸâÝ.ÿ9ÄM'ßšÒ˜‚•&íM4[¯îæ—«ñòpǸƒ²>–<ÄÇ]çõv+ÈÓ œCÇš¼,?{VüìÆ¶+‰ºl^=t¾¼•Ý+§E ÐÉ­T_é Ç× î,ó~þ+€aOÃàToH5—î1 è”'µp -F·.£zòk¶¸o–õÏenßžë$D"æÈîÄç´SoÛE{u•׿ñ—*½¶‰Ú“Û(}Ÿ¤ W}-] ò«÷–4™²…¡ŸùgõZšVg]«î†u ßSõ®äzN^=´8#¤î|Ø”¥%1'l¦¹d+pr¡_æOàQlïwâK/bûq,Uºqîr`dþÙÆ ôo$µ 9dv9Ïã”v:á¾ Jçx)‹³ÞCÉñ˜yÜ;eÙ¨Àfkó•¥çLwã`¥ê¡Jø¶W~,‹wÛä™Nç)lz 0xxH3›ú{R„qÄͧWÌjõÀ3mgÎá,•ëµ£d°È³ ›³&Θöœ]ÍÏß3óxþ Âï™&Rm>ÙAÌôÖ ¹þÔŵ«ºòbÖÎöPpÝñª[Z{Š —VëžEHKµy •§éØ»@þ .4D&tq‡9ª B¬£ßä‡ÊÙáñ†Z6'œg·‰âÒƒµAr(|¿?KGì» e«ßuºCâŒ0a €É\igÇýž?> ¿ÒÑ'.±Q~kj‹Ç Aå«€•³EÌ[1è¨ÄàºH·_ðKÝPš¯4²Ïáxt¹‰îˆÖ;ìÒMã:ü8†|€¸Ûþ_=xÝв/"Âgn¸v¦6=tÊSî<³YfiõeG«èñ¾¬ÒêÈçJ}=MŽëŠ1—¦‚á ªTrK• A/”2ï“燂 ×­Qô{â_뎳óÝåþw·»¯K… ÓÿäûÙì°CæwØw¼£w>„_Ýá>r5plãsåäc[ çºSâÓÜq†ª5wHœ¡vÍ|tZûÞq²éî¨p1ó¶”q‡…‹—·©<—í‡]®¢Û[)NãÖŠÓĸÕâ4ñÝzaÀQ礊s<¿ì~1àô7^÷Eì§tÐÙ8å‚ÎÆ)46¥Äé U£¨D/§N#žV·ŽÏi5£¿6AáCÒV¼ÎQ?’®BW†kÉñb©]“|ÕÛB5Fú÷TCMƒ?¶Ä2?|b4ˆhÅÊÅs‚[7å Ósò©Ÿ–Y*ìIŸä©öñ¯Ë~lÌIçy3ÌIë\4: »U$xw6‘8œö¬‹RF½W©~ÖgX¶º2yoŽáˆOj/rÑ0Ò2¶áû¨_}AìÉŸ²Dõ°p=Yæ£í¿¾¤0î»´óðî½Ö#ñÅ×Xtò>]qâZÇÇÝû`š“ƒkãœ2ο0ñd×{m@áÛÓ0÷°îo“Ÿd’ò09›>ŠgÊ) ]±ò‘Y<žP i¬_üË¡o?—;ZÅ1ˆÎó–Á)L­vÿëò£¿m`î {‹¨ßÖì¹´ß·¯ìäM¸Ò:?wüÔ_°›€9Ò|?þVÅT©9 N`\ åÊã øU²Ýx{r(E@‘J|5bSðqvb_ §0P\AxZ«(X¾»9œ&¤\Ý¥ÈÞÉ%,x&‹·[u´:NMtvŸÛ(=$"˜¬—\Œ£l›n” énZ ò{ŠKÚËÅÝNvèL—¶d±Ü{!SÉ.‰ËÄljËÊÓ¯Ðe¥u¼À¹†4zåNnY.ü¼Ë¶‰s·«á`2¾¯·“5’z5XaI«é|¾¾A—ãÅ$Öc$}°îŸÆËÁu4»¶@°#¨NCSvÇò J`â{]ć§t£E:5ßÞCõV³…ÃÿÛus‘:N*xØ9}-yùC”•Ì6ÛÈ[ò': &“3ÙEü¿íS–¥Üåò7$©Ód›Æã¬jÎMñ„î›™›‚™8ÒÍ€3Ý w1–‘,Ò˜µÈIªܬ;"[²nü˜ ÿå9! Õ/a~ûfK“ÙÖJ©-›¡ Mê}\mž’ t’â¢LÄs¯†·ÂŠÓÍ“<ÞB—ü3IMªÒ©²$¢ÊöÇ]ò@ïóªÊ÷ö÷Âìtù™ iï>±É&ͳÛhd#•S'"QJu2åhl ¥½/]ƒA‡JÛVR¥hÙ¶—̨’ýŠÍ€›ªÛ1BzBG2;…™¤l6Ê´I/yf«‚ßÕD}Ò3q9¿’­ÌÓ8r4˜Î@ÎÀa…1Zaß«›8í“J¦2_­­Ãñl=^ZŸ—Ñõ æ‡Q­ñ.}ÌöP†÷Ì4±>fñ>ò·Ø5§…LsȳÀâ\§ùRl‰ ÁF˜ÉÑ,¯Ò‡(×MΦ²â¸©Úágò`Á6Hù‰ï¦Uue›¾æ—;Px£M&‰ë¹\ãÍê¥XP{”u¹à–¶äö%?VÓ8c:×é_Ó¬Í凶YI‹2;[幫fUœêC°ýæ"ß³6Þ÷ò£p‚ƒ ºíy­÷(ÏC‘<$3¨ÏÊUª¸ýìÖruØ;r½Ã»LÏÒãˆ1˜ò›¨Å—V$¿À tÂãk04{f02!PxÞñ-éþÒcv·~ q”–aoÿpöBR=¥åÛ¿€–Á &@x‰‹o ù“TO·L"$Äz¾;c=ßVÏàZ:çU`òyt7ß®ØBš­e¯Ç£»ù'ÝJɲ¸JÅeLRh½ø‡|s,½¨}~,“1·…ÖqÁ†¬—`s,ʼ˜g^`%øMⲋÛ?¶^Š´œòÒDÙ,°ªi9Ü¥›óâðg„Œ¶EüøÈ¦2/pÇE©ýC 듇6x‘‹åüË×»ñ'fJÞM«^)Z$¨5ê0¥ RÇ›MR²áíµPþNªÿ©ä1ø¼ŸôåÎ#/“ Bm’Œ¯çòâ…€CÛß[°„~.üÎ’zD]üMÜ^‡"çýpŇ»ÙVr‘Ó%QÚ¬æ÷1y¹5 ¼¦­’±¸uI~E"µ Ȱk³È•‹¿O˜¥-šl)旅M8a˺œR±:¬²Þå±zeÊìŠÉPÅ> î{!‘ç‡þÔwzÉòrõ>þ•¾FÂ{%GÙ”î8-òŒ. €B„W8+ëæ‡ppî²°ÅW¾ .»]¶.J·÷6„+Ó§2îÖÕ>¥+@Rݺ1½îs˜\±Igš°ÅëFõfò¯j唇uc 䛘ßå8ÏV¬‡Mç[ÛaýT®†e,™ouj“/š…o_ë<ßýHµà…ú“‹YeÛ¥¯½Ó¤ƒÖ=cHBæbÊIs]Äl Ö‚íâ¸?¡ñÌêQ+ÐÊ‹³„‡“ú‹QâÂRD½äj‰Cѧ6¼8œîƒå·‘bæÝãîÃ")ùE‚¶ŸÝ²Ùø’ÍX¿áAÓð;óшT¾ÈNÉÅž¬Äoc¡·ß|@®¨,=æ¥)’žUÿ”–é(¸ØÁ¶)1[™×²W“¥y-vQv8V¬1“xÒñýE¨ëëÊ„'¡§N±5—ݘ‡úD]@й’-#vñ&¡ÏÛøDÄ]tê,¢LËð'L…ûu~¬ôŽ5Œd3à vV)¨JFœÁ‰šm©|Ïô=«ÒöŠ”´ Üí4«Z%ÅÍZ5™FzЦ’8¸œ/×c„r¼\ΗXâp>]LÆZĨ‘éj=Àyæ3„Ôç§ ’ÕVX2·$FúÔ H Tc3ÖC•Y‘öüøøëü¦h“8£üÔVõJ~ƒ«Ì}J-õ‰)W,Í'« ‘Ö&‘×&‘Ø&“Ù&Ê&êžÖˆøªöõ¡‰T .&…o^È7 Æb£)"@(l\y1qE^”ƒìÅg-„¢ „i)èD~h±j»êÙìL¼']Tp’¹$‡iñ°8Bè)9–ª@^” Èú§ÜµfBèÞQ5Jô¦}Þ&ÙQÿÅ$˜¾6ñ±Jâbþð`aË›dwàš)†ûK|ƒÝ_"É©{Y:3î>ז®-™äIðØÇnè7Û9µÔæÖgÐúNê.â3jÒVÜÁWy$÷òÕ”°?ÈH°eVr}ÛõæX Ô|ªjºxœí‡ûxÔdÍÇãã×­Á %'°“›V@¸B(䀃"ŠëË’«s7† Æ—G ¶%R®¥~0§#–Fw xÕoM¬~Õ½aP˨%”v›†Ž¹²îRýÑ•qÆ_à»V}OZfÇ˸xWÌȈ¹55;ÿþëpž¨qþ×ä<գ̛¢°)*Ãq­.Ri¶6G¨Ù%5ÖÇ<¹·î”ÄÇLh@}òôž ’“ŠC†²//µKJ5U ‹hTë~ª^$ß3j^!í}•/'Fõ/Oì©»$)¢¾”D²ëh\B\*ÂbŽªÛ8щ꭭¤{ù¯‰¥“”Dq·šõ³(ä!wÐsµèLÿâOì¤Õîe•8Ø$?e é<Û½à…Õ¼°QœºI£<:»âªXÁx½5hÇÂŒg¯Ñ ]F´C©“Ögª~!>‚»Y>Ü¥ìÃPlP·ì£x¶<Ñ )!@x6B‹–7€Q¢ßJȇ¶Žâ'‹u‘$þðºÏkªLÉkŠ$ÀªUèò²"«D!P:iÏ)IeàšGTýá<²(„dÖ¹QÐeMÒü3H$І ¨S"¤T‡54ƒ_ eíJÚñS£P‚œWÛ=3”@¦À჊j¥Ë ñ_oH–îÉK`öõ”%‡ À':™LH$ˆ¶N5þeÓŸ¥²Á†»Hï=u jcugÑs $i¡t3<ÇcŒ„Chûû”TûPãAPñséêȤ6¸8dwßÈð]ï -ï¡;ÃBM°ì½RÔè,.S˦`ê° ^’œhb2¡Ïõ‚ªç4_Óžò¡¨aCD©ú oVRŠXöÓ'®Xî>s£ÅýHÌ%^›t,“rõ”> ´žy¯Å±» Ânþ¢Ý3c7¦9Š`:ô~„é6¸mR xŠË'¹®@!a¸%s˜ž~šæÛô!å‹{ómÁÏ6¸¤Bšëß…Â:š>]©j½>i$ øMnòiš¼ØkÜô·e'zë’ÙÆ¶šê­fƒÏ‚iˆ^‡¼LõÓ­QäzÐܪO¦_ícŸ6—Ãf•aƒU¦9F­À–gæKéê§Ýuñ @,=™bæM'Öé—ǪÊ3ß KêÑóPFÃ8{ŽK$#€uÜç¿•O*#HT8ÕÖ +¯ <Ú£Bõïë"×ÞnÖ¾ë ò!Íœ ¥·vyºIˆuk¡”à ) Ó¤ýê&H «©º›ü5ÕÐç:ú ±&ŸþõƒÅ ƒë/g«~-ÆX¯yæsÒy`˜%õH0Lt*frêævœæA; Іœ†È­³¾ÈwÜ 9SÓýB„§öÅùŽþ‚Ì{V ? ‚±3À 9 `N#ÔÈa`M: “ÂkfëuÎcd´ƒÁ05|6Â"ǃkhmz§_}Ÿ<¦Ù§ú’8PLT4[ú±<†,“¯G)H|ŸJ™âdPõGl±?’ê®@Åýýeú/ÀY @×iµÃvb 2]¥»$ \œ‡ó¦Ãåt£µ]X›ž9”/ÏäìGÿŽW=Gí@^0–´Fj‘ám[€ˆÕ$bk4Bè¶MXGg¾öÅGè) )+(@ *wb%CjÍé¸9ÕFÒ¯P•´Þ»„`ª’¶”hä%“JA_0µTÀáq€é6Qà™:z®Ù¢<ªlÑ»ëpüp­ë_£À³­:1³ªƒâ>ñˆbÍ£Ô×*†$ø*–I2)N " 'b.ˆPg€Bª ¾öÅò {¦40¾úÖ`è¢Úto9LLê·ãôä :­éPy¨,^C…œƒÐqÚMP…_4@Í/òÃñ@®¥Ž±M‚lµ)òÝîž8¶t4ï8f™FÙ¦H°Ò¢X0#Œ‚™ÕǤ[áµàP¾á± ó$Ù‚““ç¡Òm)ë—YlsË&úÔÉ'L¼4Ü’_ò2å*’R:FtË·¯Û6VœÛÿ9–âh&·ùˆ–wÐC]Á­ A‘ĤŽÐÀæ¤N›ÆLÆÌÞƒ ñ€ Fˆ˜>âý‰U?œ\ïúòƒ%+4dWC¢ÑcõwJLجhSpn\°ÞoŠ=¶@¢Öøó¨˜@š?€N¥"<ü€7¦Òþ¶WHk*Õx[?cL× Aàr‡Ã¯Òd·%÷p‡îeî[,úØü:“p ]§ïc¦ëxGmžòá[j áŽÁñ†û+†Xç|N³mþ“Ô3 4ºžÍ—cy¸6œÏV·S?îj>¼]ÝÍÆ_ü Årü)šß®@éö×Üò;ß­ÓÖHVøU9÷ìF †¹*Dô¯ÝÌ<ý*ýånàTйXh­Ýúnæ6¶ê[’XÌÜÜs: ¦ä·VS Zj5ŠM£î§ˆßÞiÁõËúòb}qE4µ ¦ŠQK37»$-ÆHb• 5çFZ‹þrñ›]#öý+ô]n7Cµ)•|G#ÀËÐ(ÄP¦Ü5îýta‰ ÷®/`À•Ñ_x–›cÁÓ¬’G±ø>Ò4\å™R<Иm™ ,;à ílÊR^ÓñˆÏ„=…JA²Þd.¾%ò MyASîÅÖàÔpë8-í{ôÝØo·bÚ_¦oâÝæÈ‡g½¹ˆsÚȽ¦’ë ÔtÂxÊÑJ·t­Î7aDjD#HøXo¿2ѽÌ©ú½‹’t•áïF*UJ˜tXäeÉÊX÷¤JO­„kiMVFM‰>maEëÞ–I §A­$LJC¢…©œÞ”'ñŒ0¦üHöqŸóQ[Ãû¤"¸Ójr­{àÞ3zßæáë~½×z¥Û!ò²)}ï…‰c|OÈÛÙÇÙüóìnv;½/ïæWw‹Áõx…PzH÷ng ±­ÑV‘™ÐÚ¥ÆN³Ñj8XŒ] Å|¹^¢µ ³/Wã;C6È€ºTó‚_ –º.®å-m‹H\¥#w…Fœ¹áLPo!‘ñ_°_ýØiÌfdf$÷•ÞÀ†B Í6ý®ˆ–Ò ¥^HÍêhY ¸<5sð8RX4Þ I“ñzÍtÎçh´ö@nÆÆ»ß*f/e Kí†%¶"Áwyk D`} êíUÇh¨!¤‘cb2bB‘ñb¡RÃ<ù• #ÞÀr債#ß æûK^£ë Ò×Bù„v7þ­ÖÀ´Ö¢fó»ÕíðFLÀí´v"W}’bpŸÕø×&9ða‹€Út¸t‡Øºð´/°`J§x PÎ3±é%¢Ø(ñ‘ò{ľi¨õ!ÑüäþUYìƒÐZ»¥ùïJdÞ¸Jè~6í`°r·k#÷‹ßÚ+F}¶Ú$ ) ©,à5öh›<ÄÇ\„™Ä0×R¡'{qdì"潆cÿÜ%y`9¹Ü–Iѧi9lÞg03™Èk3'ÿM-g·ÄˆuÜe-ÛŽ? Øôœï¬@Ú,ÎÀ‹1?‹fNu¸ÎÂ$Ì·¡ð®Ï»œ6ÈL/)GPæ#Ø c°4ß|<:®Å€Ñ&‘{yà”‡4×E!ɇ;Uš…nu¼ˆ÷ŸI¹LÊ|w´—c-Ž5“tJ¤EYA·Qü㘦ÏeÈUœî¬JëYµny#à@q×+Ü:ô/ðë øõ§±þéRžÌuS—äp³w ØÍ®¤SRí ݇€„Jxѧä×í›!ü4 ZaýÂfgÙu¨7[l_Dø1ÎÝO'^))B#ç7;]z¼‡½×EÛ~4ÙßfçæK‹Âéðô]W€†¾ïªCž @Š Ò(H‡°5 À¥ ¥q¤}EÓŠü'>¬ÀÛÐÔdh_VMeQ‘dr¶¬‚†DZŽ÷‡Êxï¦K†Â®ºÔüXmøi¦‘<ÓÐóá¤ʆÓ¿!P€ÞrÄ…Á ¢úç97•í°Ò +_­ `¾ †¥)ض}9friÙ(ê¥Wo?&Ηö4ŒyµßIX&ºš¼Ò¨žå zµQ‡üxÙÞ–l©«WØÚ/Et°›ù2ú6Ÿ­0ùÓx¹Ž†H¢(˜²ñÓ–pš<‰ s”w­ öàÖAšœcÀ¢èÎ’¿%YñÖ rq®óîàG U –ç;ß±w_ø¯àVÃå|2¹,Ww~áÁx4¶§o 9ù<øºòÂf<˜FµÆÀ(-»øe‘ïÒÍ Œ}î®úO>h؈—e# ê3mÊe¨H)B"ߦ¿îØ,³mzÜþˆö|îßCEÚT©û›/‚~›Ë·ÐâñÏ®³Õ¢)×Aá¤Î‹²t¬qוk"4%Û•Õ§þ5rÞâe@Óäç!/h»¼ ©ÃNé;w…Ú1’ˆÇÿ´2¤n2Âwpk㵪e¨#r< ¢Sº/8sb¡½JT;w]K›Í|yð!\ JŠ­\M²ø5`îµ®>ª¦Š|¯pÞr€«xDXrb[ fã»ùlòÕÛQ”‰CÁû¦J²APC“j­uηð5X“›6c= €ñ¥¥ ö¬2mïBÒ&A×”Ô·x4H<úYAöQÅ ù™×fÖp¡,Ól"×B @;Öd6zuˆù$@û×^6 ¾ °ÞÅ–AôÄðŠ‡ 9'#À.e±RÝéF¼x…Š›½#C’Ñ#ò <=¯%|kLz1'_b"¹+ñkHn`ó›ÒTù·8I„Œà”?¶"SuVã¿Õ&“ìÜ^˜–Ù‹Ç<Ôe/û©f¨€FãÕÇõ|¤ò-ôOã»á`alã F@C^Η#}Q¬`£)sæÊÞÂ: ð9šæŸ‰®Mdz[G’‹Ô“ä#½»‰®o&Æádäe×6­8œÏÖÌlt§xËÞà&þj6ÐÕÍïì4úèÆµîTþ®æŽ$WÕg·SQ°BÛ¤üQå$•¿àþœ cóä%Šá–Rp—y±M0Ý’f”| ”#géÌû§¸ýÓ™H wf¯_e&9(+w’‡ò&}|Úç_PŒ‡WT7¨ÆfP¹Sýô¾R×°‰·z5Mx÷Ö˜Ñ'ªu»¢Òö;’u.»¿K âX+0d!¬"dú% øßóø0X|þÒïõ¥±öSŘx¡’Èá”/%tÄ­¹B]ÿÅ[´È"ÿYBß7ùî¸ÏÀ$Ãß~‡}ñm²²±p9×.! Mœ‡é«°]È=›ÏƤ[b¥–îÒê„ᣠÅTõ¾H‰–3]2!ÑXæšÉžsÇ~x0sáÝR »]ºzÙ™¿Äî¸Aîû-µ|â•}ˆ«€wN1:ÿ» *eØ»¨8eX®K¦>ðVXÙC ƒ^0%•ôІ'=žÑÒ„¼¡ 4ݓבôëÞЗ<ºy!< D¡ yüÃ$s¾ùéãv4â!¦Ð žÚüèQÔ¡†A¬'&õû( ÔžýðÃÆÙmâl°á‘>Ã]z¸Ïã‡òBÛ%f¦Î NçÖþ¢Lu)}RêhØ´±VÊo¹­ÕD'Ÿ""ÒHfLØ}Oê|°7mU•‚?Y/³ÒýO`a(ÕOª–þ?Ïào˜\¾TÉ)} èI iÆTrþð@òÐ6 2?VÔÜ”˜=CRóoD°yXªa/õ­r»$~N¶‚ ŠÂœS¥œ*Š‘êt —DNND$É¡úå@âRÀ4!¬‘´¼i")s¨.\ú“âÏB^œsÊ`$]'‰ Õ"jà›¶=<À{ó-d='¡öñ/ 3&Þ‘ðæ×¼À̺òâ‡¤ÙæË`ÃßÇó¿R_FùOD ~ë%†Ä,N…YŸ/¶¸¢±ó‹ü'¡tå+]Í‹š)¡tˆÕ ¿§™É6-y™ØËtøÀWRƒ’ õ‹‘åÿ0ÁÒWRÓ6l•*PÁkçâƒlïCËŠÀ5€RVEZ•&©Òsªå7û|ËãëM¦ ÓÜy¾û‘VîG:Ðs¼{{(òCRT©öŒ)“˜f_±´h™©çUÁ5{Ë…úRDCñŽR·w°Ë¶M Íôï”LÿîÌôïÁ™Ö[ ÏIãjü3”ÂàÄÖIy?Éðæ{‰„gi—?‚¨,½Z“ØGÞ Ê÷Àf÷”ß«ÍâlƇXý¯ÀM»*݈QúÆb¢$ÅÃØXÍ€TÚ ËU¿­w–^D@‘ˆ½Dæ§ÝšõoSK­TB•‚™)˜€tÄüSØÖÓ¸ø è›Jþ ¤I™‹ 4q¼Ùåñ6Ù u0ÿÂ1먘ru<ðãì*Q›¬œLz×j/xv»¦ËERìÓÒÜ3¬ Ã&Õ‘‹·ÓîF[Ömyy̶úÉ5ƒì œÊ•Ý;ÕÎkT*ÿ; €aöÛ­)÷þ±jjñ¨¼‹y9ŠÁPµ%ä—û„Y¿ÃDpqï“äw‹ˆÞ‘®Þ®üÒz"ÓÒßç÷eR<óœ"ˆŸp_«J»6@~ÐÞ§I’¢þÌ/‹:¥vÃÇÙs¬žÑ“,^ò³‡¯í}þKåV²ùÕ 4Žü}ì¨Jöç& Í¡ørÊÓM¢ñç®ü³‡W³‘ Þ¹brœtúÒÃöXVù~x,Jí<§¹R/Ñ,e¥0‚ž“õ–ü`]~v—zTÄ×IÉ— l¹•?fé¿ôÁ7ä3Rþm¶ý­„z5ad£ë, ‰Ô€t¥pZæ_¯˜x/P–µÅ §Ë‚áù^¥;»ñ»VtI¾E÷þ—`ÉÛÜøW7#S—)š‹iÌíq£7½½…rCD5€C–T¿ß.'ÁÔß/Ã)´…º‡fß'êõKâ·­øWwãsáVù°Ÿ€6)=2Æõ¡Â…ÿ´¸ð~.—qa0b_@^컟¡àQÅNSèüFµÕÅo‹—øêa”Ž£ÑÚo6Ã&ÅÍ´»u¾ŠÅdÛ%QøÞkÓ~C¸Þû:‡{ij¾ŠùV²X6 ~Ž"¸Â`)¾öY!ׂN]ÿ¼à¹½Ya%¦2ñœš}÷!»Ê¥%~ñÛw;sœdš0ÄF5?ùWµÇ”ƒ2=ë±æ WcV§ÌGyÈdÔ]Q$¥®9d ­8–i—Õ[¿nŽü½î C±³Xoîqô¤-)fû4¥iJ`‹)Ó ?i g… ³[¼BÇ4^’dØÛ‘¨Pé5TÒm\Åâ§¾ŠhN>=Ç¢I,n$3€ƒ8•Dý<2].0Á.þWº{™äñö\:Š;eÉt8ˆ¿yÊØhyÄ Àà“ô¾ˆ 'D;Ýü=q™c6ýªòr:y˜(Øêéøp¬£0ƒ]%`ñ$³Ww–””éÊ–˜×K¶Ï¢+ÁqN—¥Š›/ÿ¸c©—Ñz:X}Ä’×ËÁl5¹Žgk BÚ“–ÉÛ?ÞŽä­  uÕ¡°vcœµ!ИLŸü´bãÉn{‰vß!\c~ÆEÆz[ö¹œ‰¹k ¼¬vê|1ži× ×ßK¦fxþ3K¶òo.Ÿ@a’øÇš5Àñ)ÿù9­ž¼ã Ê–kV3Fjò0k;تN}È7Çrúð3º´­riª€qÑ*á;ÜRƒa?u“èM²ü(.™Ø“.uÞu¾ªlŠäá÷Ϭۗ<|ŸI¸$Œþ³ÖÖ~Õ“a&‡ÃîE÷¬ûн”^o}Ía“gU·ÁÓ¬½æÔ´ÛzoMÌ;ÆõÓð,©ZÁ)uZÐ)žfO—׉bõÀ†ošâB³ƒã$Š”‘«/ó~W“`bþDiw[³èDù †+ÝV¶«+¥çP"­B.0m¹Ùá?«j›&Oüa]¨@k³I+¥î¿€ú5-Ùè§(šqïYxÁd&懈•†66ñæXh&¼Ö‰[\:9z!ï°•|¨I€ËÁÈ?%q‚Šä´LBé4jÙ`µ‰³èq@©¥ä¦ìIZ_²8]ñóÓMæŽM½ý‚ÀDÞÒ”ˆ0¡Ê/1i®ò«"Ï*8­^̆³ž‡©ä:cÀæB®}›E(³„Á…)Æ_Q®‹+5®+.FÝ­~AzuEÄÿ»‘³Àï—ìïfF«…€Ý•Èwù}¼»I¶äÝ<±¥÷æ‰Î¶éÜxf)?§ÉþžY‹OéÁ,N&6•Ù h-ù»ÝÒòñ¬MâŠÆåÐ8ëB³”RZÏP6 T­F*IÊì³8c"Y?¹äSq³–êïµ:˜:D­z IùZÁ´¬?%UÎmÕ ¬a¢ ¬ÅFû­1ÐÜz‰ÎýÝDäÜÿª–-õ–=·Â™´Ó'k­_¨÷*˜ØšjÂR•NP9ëºþl ¾ :ƒ{ã;ßà frØèAtÊçÞ”JÁƒi‹äÄõI+&’Ã9³bƒ9˜~š`JúžÅ_§¹•üEj¦)ÁCZz–ä)wøÎÃòÖkòçåýªóœI«7H¹I©β[>(ˆÆ”,û Ä´%»ä‘ÙÊr!:$hÂx—ÄåÙªù—šz!þb•À7S¶îxŽÓ¸kŒ ­+ƒÆp¸g¾Lžù‹Y×'dÜËì ÇÙÐä]/’lË=)=2 ‚'¹C° òzÇí RgQÉ”!$H¸µtB $®;xB/™$çç c¡÷®Š|O§£[.D ’l_kÆj¹/´úž;ƒ´ìøçIXZ%;÷’¨s (rã/¥ &ë —E’õ¡ +eÛgÈ_ ›éDi;!Ûï}M3«™ríU-!ItL†ióD•º#f>=ıû}QÒ*Eü¢‡1BGj‰\}‡kCÙ4B:ØniS°QÁàN·r^ ;¨wÞÔ&ì?wµS–ù-ȶ§–´®Î©¦à j[LœéÏ…®?jzí¾<¸C(8ÿG±9Æ£jêtyªR¿öUhN+¥É´]kYÓx×Û@‹‘¤®mÞ`Ác’ýœn{*“‡£?N“‘;S-`ý©olG…zþL›Íúm˜E®×Âg/¶2‰÷žeù9D§åÕõPÙ|k'Sɰù.ëê:òT¬Æ¾§‚Õx¤Y³¦\&½¹œCI ÒÒZögÕœçóéÍž]Tê /’]6ã¡$kfªµ˜­¿õý“ÌI„ÕùÜ:u*O©Ei 4ŸCv§Mš0[F”@WëÖ|¢B‰Ë§6wk²'§›NkÓ8ãÜ^NêÒ@ï5£‹¶yš¼§-P¾yŠKTR»=Üž ´XG@)Š$òW ÂBtÕ9Çá·>ºìš¹4uòà<~þкÔÎé·—ÃÕJüKU3Ì 9©¦Ä,Ä9–?^qOó.}#R¯—C aIå¾­·_±M¯Tƒ"ùç1)«îEÙs27É-ÆØ|®©Î^;fÖ°.^‘yÝ5€ ù„)ú5JË4¨<7zª‘CÌOœåׇ^È:¨Œ×-²Dÿzx&¯Êü|+ÙðLÿ ;´J¯Õäá*ÁŒ÷þ²ëk0¯Mí×S†Ò€véÃWÉö9)øAöl;_î™é\µ¢ùo3É"¾ÞLq^“øu­á×0„M˜ý>/ó"yy_ <“q{^¶ç³æÎ8Î;®³îÜlYUdqþÖ8o™_kZR& óz‡~Ü)´ 9©6úÅ=y¨z%9mùÕ-sϲšë?Ô_Á}f—nÃ$';Úƒ©Ô`Yœ#è,|ÝJHÜ`·k‡Xƒ©çOOâŽzû¾ª5ßKûIo¯³¬ãÿ:cFDÆå9›-2?MÅ€,3¦X· +ÚA2ßSÕ‰ä„úß5ˆƒTr}ä—ôÏŠîð×åOû8ciKM¹ü™{ÀjÑ^K !µ=Õ¹íÔ'n÷î^|LèêÙ±t ¶G›žìcÖçNÓñ½²>ô>úÞoÚ¾^:¸‰¿úüÔ?lI½é/̺Ÿ%y¦¼{fþ—‡Ä(AmôWŒy¥B|ëW 6Ú¿.µQ7ü¼ÇMžÿ8ýÌ%œÕÊ—‘u°,<'qàñ¬êÓJ6¡>ZÃ}Ñ·@òa”š m¡Û§t'•ÍœœÏ36z:Ûì>¼fü”xý| ¥Á÷9ŽJÌ¿ïéˆïŸrÚ•œïÞ–µ~.¦I%}o'­žy‹Q䟣‚Ç©9mõ-ÞëT¢9¼f\¥’iÀ*ôcxeSÓóEYÚW6ô4·ÏrçƒÉôœ÷6ؼO½ºáx^<Å òo·Ú•åUÂW{/¥ÖÕHþÉ|û·04¶új2‘:À]ÞÒ,Bk5±ÝÚнD’V¿r¥‡g°Î}’™HÞpï^½áÞ½y†.U:oÃ5‹•“Ú¯eÞŒ-醼mR ßõ7‹º¾/HÞãÒ‹C¸œq¶2 Ó˜Íð3ßý.š>Sq‰HÓflÙ,–jÏõeÃ·×ø„èèØ5f÷©©åS›¾¤šDê‹‚`±j™2ƒy–ð kBºå%Ý}7'ˆP˯~²ºG‡Þ[PÀ ›azï.´>¼}Øæ@M·žãŠüÇ:¿-“ëcBµMÊô1[§û ¼D .†“`šOa4M«‡éýÀ•`OØíy™PØŽÉ9²¢.4Î’W`fñré9ñ ùn§ª\õ¦PVÊ×?ù²ô¶ÏyÊçC6âÃ4>ßXÖ:ðgØŸ°!òú!ªrêêðW쀘[1Âþ×ã/Ûj Â͆ñ?ñpªöu ¶¼“¸œ&xÒI÷¥™ŒÎ¥“~“—3”íðÒiðî´fÿN{yÙÓ u—šBú%H`¶ì§´Ë%ï5ðÊ÷ÃAYžx1=Sãj7êÖUP[U˜4ž÷ÆhGP³!´4€%ѧhþ ™¡2!72÷)ÀJYcáÙ²ª{åä¿öª*rïs¯¤ezŸîÒ ÔÕZ¦-24#ïÃtTFÑË<@ þÚzúï"¶„¯õÀO›C9jô‹‚À£·-Õª[£‡Òž|SlÃ)K’m¾ê\&Ùc»„Μo·Æ×ÙÖPgÝdÖ6^O¶6Q6Ô=Ϲìé×}2+¤ܬ?W­P³W[<ŸÃ7º(ÐßS¶Óש.±€Ë£÷¥Ñá| »ºOdm™/ïþø¯_ü—õ÷w¿þþΚÎgs/+rpb•gª!åÚ;Þ5_ñû{z‹ê‹sC†P£ä!>îä¾Q¶M~™:7 ‹\Wb¾© R•´xQ#¦."åY”h?&8~šTOùÏÛLÇ95ÆyÙLvK_¤Rbzÿ-³ ø[ðhú.̓uM22Â'‚BçÍÇèœMqÌà}g¤ržh¢Ä _Ô‹G¤†´A«øîåSþs”oX]²Êäåmk1M×ÛìV³üK¨ï<»ªŽ÷dÉà˜­ÕŸQa·d H­l<˜mr—î¼¶ùÆ‹qŒ à›®ûôžñw²l#ñç2¾(ò Û¡Rç| 8pS à4¬íÂåèìC»ˆ fúTà»–¿ÙŸœìÒr ì|ô [i¹…VÁù^Öí^÷“› [£=9³ Hs ˜ÁV£È)mÊ:ÞÝ( n±œ/ÆËõ×Ù`:Æ0®y[sªUB{uDw[´»º×/‡„Š•‹¤2 ®¬“|„LÌ$(‡†=fé&.+,ÍÔÕï*ñ¾`kˆho>çÍvòØ/LcWÍ~éS&O$'Ë5 À‹ä;ÞkŒ#åJV€SŠ&=TmXk«dƒ#ßÓA~ ïRß"è_T®)}~M˜ƒtÓŸ¯ýø:ÎÐVæäRÝJUHÀ–|‘jfa®õ`º&x³æ)÷tkÓ_Üð€žÒíÖ8:`ƒ¿ó±0n¶µqlmP´udk.<3=X6d›–‡]übùºldeù…l ìBqÈT=¹œ˜³ÖJ|‘XôÞÄå“h yÅçý±ÎDâÒÙæÂíù®Ÿ.|68È ?åʺ~\>Å»#äs:ÙÌÒr,ž©; ä}䢂~p©w‡wþ9Ôu0ˆ­kAžP¤® H9YrÑ/WL0ˆ«¥k>¥¾îì¶ßdÒ*ݳuh“¢•Ĥâ_‘‹ MøTS:![e¶r븠4!ñk–žNìX™éÐ!5ŒØ·où6¤"ЉÛe-ö Á"”Ú€ø8œ° °òîfâ4ÎMM€ìô½M€)e‹ ;Í¢žkÃS4f²µÁoœ¬´âá³ÓÅF¶¶ÇKÚú ‰i¥žšÙA×xIªV·è%¡ÆâØÍΞï1K6¢Û0j»cù$T…uc¤»*ò} ™oß(î }an.ói,NnX'³è¬ÜÎYÖU«nõ)¯\òµøñ~—nFÚ õ"uÇËä¿nT}œ007¯ÆIætÅÀ”uNV½Ïs“Ͱs;R`f]m,v ·ñ`Õ¸ï*)˜1wõ'è­´rgÛúd®‡¾¹˜¬Ž÷b ¿|D7ÍâÉ?ŽlyH›Á¥xö±2d— ´€KWOEþ³³c­ÖÞZ™U¢ÇY”{ÛfaM¤dQ®-Ÿ¡Ò‹Çù2 ø ÂèêÂnEo­6#;J @ΖC( xÖÑæÏiõ$cí% :þ¬•ÏÅ8,â‚kÍo\<`Ž£ú<€ÑÞ.î‡"ݧ<&SxÓ†ÓÖʼnŸ”Ù=×Ï©Oôf’`û<z€è(ú臈á`’"Óv±íS©2Ynò#Ë5ˆê€9 p–ü§^`¾ÛÒ€<ûøQÄ#D[/ÚÖöÉ t#ÞÚõäÈcêJ{oEèçu[ô¥_¨Mt “¦›½¡Ò,q§Ž\v{ šs\ÿ­µ[\i¥i¯>ïK…±àU®0´´–0ð}]µ7Žâ*þÄJgºy\]¿Ft(:•r5åÙ¢Þûå€b;%O~1Ù"\HûóÕÖ¦Çì^'+ϠܬkVa^Oq÷‚!äáúFàÑë~ŒÕYÏnôÎä5ù¤«%Üñ ‹Ê¦mµ ` 8„@þD‚è}~̼ Mž•U§Yâ…6oSöÓÞêÚ€tí+‡Hœ36âÕƒ"Γ_ߨHnNqÚ#᮸8’`a‹¤/àÁ͈2sè$3ê9•—|ü›ñ¹ rØ)ž»ÂklúÓ±*sÔ«=F`©uÊ)Â^ê½ü¡W‡f³×Ø×07kÖühP¹NŒ)\£µ#”ç5åï %Îq˜ïyÆÍCƒ,±½KA,ÌdÆ=ʲŽKÿvŒM¶´­éÒrÁ¹‚.j0ŽSƒµyû\ñá)Ý4*ŸZ²,Yæöéƒß+Ym5÷²òÔÓQZ!énC»!”&[©ËäåÖ §q?Râ: .ƒ‹ä‘µ]ñB€b:ËgźiÜ™:¹K†Ö|»M|ÙÕ„Yá7¶Âxîß%m~Q˜É~J ¬™¨‡)*vë ›=y rÕè$Ϩ'RÇ9|/:Ðíûѱ1íëSÑ©_o’s¬æIt}çHõ>êS¦J…Ï™fL…cŸ‰S!ï3v×§ÑÖixÞÙô•]!Æèì;·* zM±-}ðL«ìy£”aªäVq:ʳj ö?êÜ•…B{Μ*s iôÓq¾8j í¼)DoÜú5 FKYœè¡Ø:iH ³‰êŸ¦ÍˆÿÝ'Êæä‚BIÑ"R~ÍæI9ŠfSvÍæg/©IÑpžÜ‚T¯2œOje-I†ßšpK4BsŽ'juÖ$‹& < nîÁPÀÀ„ÏÐWÿæ’«ks&¡¢053DO—¸äà<9`3à)yrã÷ÓI÷„òunîÀ«ÇæÞ ¹Y›{0¯°Í=˜G¯Í=Œ·h_YŠ ™¼† Ÿ´¹×=ôãÑ«Îñ¤‚ S@Ø * Äx-E©«ååñá!)’­"mÚUº«’ÂŽ³CÈê3O2iÅ´²~|p6ù±=Ú†@yéìãâ ´ã±xn˜íŒÃ€Ž°ÁSh#qÜÝõyÚv——‰·"IV‹d~à7·x énçñ†¾ðÖ‚£ê‘©î!h®â¼Õ ï—lÎ ÿ "K~Å–§.åôpñá·ذSÕ‹1îÔ$;JKÆ=ø!Ž^Ô`ŸkäâØœ6L¦øÁB­ÃòàD§£ú‘ï÷)!Èò§Í·†¥š´¹G“26+€®j’ÅSh1žk4û4˜D£Ázn0†TÊÏ 4»)@)jºU¦5À£GkªB•ž¥Y¸§Ò ÎTÓ¿a%¨`þ €xO:|É¢o¡T/îJc »øtµØ¨ïT€üis«aùu¤ê$L4ɨ¨ÄAW£ÙJV ?}Ó…Ù(ç@k0ư‘ŸÁ榼i7t ÕÏ@«Qø\£³L Û§Ù,þmoý”ÒópÌQ¹ƈÄè´§´—*œA6?líCi9äݱõÀtÛBèö9„àŠÍ1 SKÜ÷K­áœH£‘!,btƒ…´å‚aRŒ5Í…¿Ž©‚Ûвleié^†jà šËˆ¡ ÒÀÒè4•ACø!«¬9„{R/.DÎ'EØÑAN•…Uyûýâ·ï—~¸wËÙOBiŠrƒt¹ˆj»ÎË2}¬ð™_pñ¬XLœ62ÌDME›‰rŰpAŒ1e&7êv¨6 Ò[ÍÊÊ&Pµ.œYáJÕDZú˜Æ4zñäcc©Øç±rM,6½†t»n‚ÅÕ!p7 V¡‰° >áh¸ai>Påí¦ó†. EÛ™T€r!>K¦B‡•ŠRÕbàÛ’4̳g¹»f{p sn{8ˆq@½¡tŒß-væ±×0|Ø]æù.‰3mð¦½/~»Ä’y©/~bÉ£ü(,ȸÚå1Ð+4ý¸Û½¦-ŒÐûYÇD<†%ÂRý+yŸs!ÿ€%‹{«/~[aé·ë«Ün3þZNRwZ‰Vç⸒älÊ ¡á¡ï–˜$|Ù-l8†º‰`ÒÕF9X1—ÝœR¯âPÙW@øP@®q À£AE¹Æ€CF†‚DLJ‚ %*:VcÄ((ú¸1ˆ&Àmƒ|¼£;Æ¢²2tŽHi{ôy ¦R+Õ–#ÙÐŒœoNЋ¯²ÊŽÈ;€FŒ3'Wáb äZÌ‘ #Gå• Â³lb|p!¤°8™tÂì·‚wà,"že•dygÍ¢´-W ’f›!·³±&ÁVî`=Pyt®\a˜g hPÇH0qtÉU)]£ÂÄõËÁ=BT¤sœ¨@ÇhQa®1£âœ#GRÇÏx~E´ï5$`ÔCé¤ü’Ó¥ÿâX‡ú7€|öi>¡QZ‡Ä¢0jÙš@Q™NqP$?”ƇC¬n€ÊOEòþ2÷FERÙlåè[DzÃÊA§¥iÕþÀÿä›FŠXù'~›Úƒ1›dpóI¦Z•tE©ƒtýJÈfgKá úf'ˆe6ò”l~ ²í 2¸æW¿$›#ãòRŸ@{o3Ë÷¬µÕ½hKu¶Z|¤E›%?ù/ "yH¢5œ^¼ÓÕu²ß&»ê ù}ž¥•-£É?ñ®„šËä“üJKþ¨·ùý‘‡1²Š½J¥ø¹ˆû2ßkþd´<ÔéZ4Ã8Ëùó;Z-œžƒç/¹`›¹ŽÜYXZ¡ée](ÊûÂ2üì“ßQZ¸=Åå•Úf“–M7Ùâ”–Œ»¸3ôJ„Ǫý~[“Âf¸jšoÅí¨ÚòU¦Öõ´¾§üÅIü€ †ÓŸ¿¤(ó÷DzþGw&éèÁŒœÂˆ¢:,ó¼òsÿc›v'ˆÏ€ê(¢¿;2^t{60Ù—I5Q»ÿ„àÛ<ÛÂFsƒ×ÐÛåy=½ÁôŒá®ÉÍ›™PM½Xf‹&©ñF’d¤%E¦¡vã¦MaÙ/ZÙÓ*•..åK¶q¥?3SykÕÆ”§•kP¼áK@m¶äXlö¢7âÛAfh(t™”ÔeSúTL”½‹fµTšW1 6…]ŒÓ>zbb§br¾gVykçèþr¢ûË!tOøØ¬>ixFˆG |`ÈÎp–WWüÊ%â:&Aô ôwa)ÅMÀYÄYpSIèÞ=LK8}€ šðR8ôNëjhÕ7'¬:ôÄt‡† R†Öˆ¨>,šÁýgJ ¸SŒ¾×€‚"/Eƒ`‘û´äžü¢Z=¥åÛ¿9°v«¥4ZÊ=ü\־߻,£7ã/ãáízŒ¦^FŽÔåx0BGãÉØA;˜LдÙ|†îãòš¸mr(¢à­S¦Ï ŠˆÅ€%š¾±Z› o—«è“£M£ Þj«ñâÎÏ‚£œlPý«bÈž< ‘_hM¼IJ6xð±á[ÿØÌþÀ™}Ciɾ(…†»|¤ˆø—i0™;,Ó¦›2‘· 6ôN„úJ ¿"mñ€bqµSM=fy‘(å ê .nö„¡²äg÷k˜ïø‘üµ—ßÐ2w ¼Ñû¹ §-½¡Â¢Ê½ƒ`¥Q˜Ú¨‚SЈ bãíÖ%'É.Ùó7›Î“ÏTdÇ=÷öºúKáAY»É—zh°ÒÍK#JXA“ XÖaºBT~ƒ~õRVÉÞcÅÔ ËÁÝøK´Z¯°Ôåøúv2XbÉ£ˆMTëùò+¸‰F£ñ LE«NÝ4ïÐ 6bCHÌF}35NC!7sÀucÛ½L*¶Z:G²ÛQ¨ñlQ·;r³d÷Õ&¯÷_HYi{2$ ~¯“ WT¬÷ÇÊtçbm¡\ÊDÜ]è»_Æ¢G~DéT·ë:Ý[­ò%”y*|¡îýj±{:΋iç_R“*û¤Î³· › -Å÷^Ã3þè‰CUÝÀ'˜15•ôÊ»G+Ü<õëPf K«S“6h½1Í·‰h,ŽlÄ6u©Ê7ñ}^T ?Áж· 8k{,xè×öj€"‡‘[kkX®‘'6šEëh0w†€–uÏZÒAè™}$(q«µNò=×t |kiMj<1pÞ9̽0ot´÷–ÊBÚÏ?q¿|\Zpbµ¡XswOèlÚcK‰øæn#l5½þZhèl¯0“JèY«å¿;Ìmw»ˆÜÚöðÔò9ÿQ·t”y˜Ø,ø“›¢ÄsŽˆ^vH’òà‡Ë°›|ÐKwã¸üE.·; ƒ®ØDæ%›0̺fù¥€ïㄵXšò Y¬Î+ÀÛ=p¿§©ÇßÀXóŽOå÷G#tæ=Ÿ®ù›ì3´)C绎tþœEºu½ÀŽr°/(EpâÏ©/ü]â½Ñ!Ãî"uÃíÛH!üƒùZzäÏPÝ„Z(]ò{¯x²I]þíÍZÌir‰éòõiÓB›)O] óÝ—ÎÄó̻Π`ÁƤ9Åü³ü³©¶föÞ4«Á0§N¶ã µd ÎH‡4 ó¶Z‚w©³j;8÷!`*tEÃÙ'Ðuwùð4òÑiäW§‘£K#ÿp9,4ýù­N#ÿF%Wƒt h˜Ø› ŽT,t»Gç"Ýra8Ø.ÝgÇçvÚèu° Ž` ê(v° Žd êhv° Žh‹Þ£ÚÁ“:²,¨£[°8y„¯*¶(”q>[,ü'€K  ¢ÍjË—©{"Í})¹éÑˈ˜qÔ‹N/Ø4žóJs»@GªéàÎ~6 HßæNUëÝpÐO%ùüÚÚíØ—Oï$w/vÆX¡œ-ïìEþÓޙѓœ­Áãvƒ´>Œñ&­^ÜéÚt讋qz­F ¹¦ðmTŽ[*3qËkðÆ5yØÅw3÷B|j– ZŽ“Áp<¸œX›Dn6_ßQ±î­ z,blI¶Õo`¿â§°)íGÛ<±û_Ù‘óN A$I“ý&¤…¶Ûº«y½ÝþbÒÿ&βœ5 æTP÷*<Ô„½ 7‡{õ‰[çš¶é²:$›4Þ å.$É9 09Þ—UZ+!T>ŽvÓx²è¿›â9x Í^r?å³²ê÷Qqšù@š¾ªù.óRÀmàf•ç 1z,òŸŸõ¹ÐGÂo«ˆ²2) 2ù„NÝ‘G;Ã%}—ç?އº1O7ѸEshv­‚ #‰û z…VÙë½’Tù½Ö>ŸÓ9楖cÙs8  >4f…µ©.xÜ  g(;¶¡îj ZÖqãÉì¸Û 2>u%1TPŸNñù”McQäU¾É›÷Gp_«jÆQ¸_Ö€yg2y·gS¯zß„F=„‚­g˜\Hß3ImûĹæöãM.dïrñ-QR.ÐSO¶Ã¨ý.µ^†rå3E¼­IB`¿&å^Í„ëE…¸ÝlìÇxÑ …Š¿Ñ-G›`ýrHúêî W´¬YÐy5/„6oç…0ÏñîífçÆØçtÔ( â„­³$Þík“¾ jƒw„6xGhƒwçoƒwýÛàïAmðw|U©Ãz—g(¯ ?._ø»;AÈI%èôË =ËZd¿Èbšðý«¦Ñ‡ÔM#÷ÿoD¨ §¸T|Rt=xÝùÞ.C]T?C²(ÚØC¶ØöƒE)j7š-ÄÝ$R‘Û´ä-1í³±ÉàTAÛ ¶øAÚØÙüî*OFV4¥ÍpÁ–•x°Ð'Ëš" UûÄYæÛÉän°¼v–y­ü˜¹£ì»¤ùÛqdëTcò8×éìE_(­ãœJJ3ú,[¾î7Ë]¢ÒaÇq´)Äå”%0ÿÃÅ<Ìá qÿ›þ:%¼÷þÑ—ð§Üß­ê²ZÿábᑉšÇ;g)¬èv€ƒ³4û`;‚’õöì£ÿrÙ%v‘vd¬³0ùÄD)Àÿ!DrƒiÞÿ—X9£Ô$‰ûïþ2[ï¾2ËNf¨½p^ ©‡{í´bS(Ÿ!3 è.cz¬ýÅQö{B _E蘯2L \Û¡³"K×C^ˆ?.ÂX<ªÀ:«H¶²_>ãøz¬O&á‚f,éÕÒ×Þ=KëÌxøÌù&1ɯÝI=ß‚pk N]&ô ƒNQ!}·µˆÏ·t/‡d¬¾DØÃ*lNêMZ© m„g&š/ˆÇ£\§ ”ŽÍ ;Hs‘mEv’¶øÕz9L旅ëÈ:à`?—«h>ó¡×ûËÁÊŠÝ`ÜÃC€-ÇWãåx6¤°N«Õh¼òÖ‰aç—ÆÃ5ÈêÍ® ÀÁr9øJ-%¥'óáÇÑ`= `dzQ|9^)uoyNæ¤&Žkš˜L_|¨û¸L>·ç¼‚:¼/ïÞMÇë›9æUá¢zw”6càÕx &Ñ7(4€¿¬ÇË™àörµŽÖ·¼íîãå4ZQF#ÒtM“ñt<[9,–óõ|8Ÿ4ãûî`Šw> Íóˆ«3âåù0‰g'÷„+d•… QÏJ,¾Í$ÓùüåJ€Nzš Và¡u|ÈÁ#*ˆÕû_ÿr¤¶¼[]Œ]ú°åF8Æ Rx}ÓžóÝp›ö»\R²HYÔyŠÑéõqSŸì»ªÙHßÕ:'ÅÛë”õbx•ÄÅæéc½ÞyçF{¹«t @>y˜?¢»RVžFp·Ãñø@²[K£’wï ÖŽ† 5±%qZ.ŠtŸò;ÃÑe—D–€—*D&˶¹€LØJR1Ï€ _ct*ֵƨ«f= 3sM¼ãžà›ÒaâxæÓ‡Jò¤Vz;»ÀËö\xRôTó:òœÑñ…Ó{éñz¼ºžWæè¦ºw¦ëÇ„ítÏk\Ž;Cûµ-dF‰Øú©Â@ZÏ|Ê­~–‹‡ô¯s^-øY.¨ëœ2Yƒ§¶¤[†Uìh”üÐ@ë0Að+„‹ôlÉ7[hÑ)ÛËsè¡À¥ñþ‹ ̳Œ).õÅ- Ã}l«T½3À‚ÈãnÌ"ZŒër-ŒyS±P¯L¶5ub¥ZÃL4:¸-ò¼ûîwAê~é]’¼aF˜,¨MÂm È“›D™‡‘0àv—Ðí`V%=·\Øø2Í~¸Ò1!pž7«a7½g:0`ÿÒó°õ©ô‚'^ºßßT1Nõd`œ|¥´ìÞ2tMŠ©¢:ÓBu2¨€–öË¡êw[í,µ÷£¬ГuݵšåK•‡%¬*ÔDóu) ?Z©§bêÃ4Ó¥ãTÛTÅ*B·¥¬r ¦–RF»qQ3JKûËÃú¸qc'#Æ ³oL½k?®ðUðñ±Ê¯xÁàäªÇ=‘Df”ϵ1¤$n˜éŠ'²ÖÕœ€j"ÙF'}èDˆÕ¸(Œ3fQ APRCZ…Ý®¤fÉOy.’~à_ ÝÉ#wò•;9r'p'ÃgƒHx`¡dãѾ“ÉßÝM³Ãû¥I÷2p·.¸Ûw—yZ˜Üm¼ËB[Y§ ´ó.ó´4àm]²UEÒnV2½ÈðåbˆhKß´£`rK‰Õ ˜ê¬“aÕY'òç;WÉ!.bí^0¦)Dv#Táᇣì]ZŸn•T—–Å'W%Õ²u:¦eµd[hɶÐ’mIÕ’m  %Æ?†Ç†’†GûÕ²j:¤et/wë‚ZÖ¸[Ô² °•iZÖ p·4¬eÕ²ÒJ¦™æI³)ð8­Øú ÈËæx‘"ÓîÁ„õK@}Ã'”6òǰ' @*@aª€òWWÇÃ!/ø ƒš¦ÐöêY¾*ؽûêB3ÁÐÛˆ5Nß:q]i8R¤,Zn J` âZ€–”$ °p_„ðÍ{¸ õdé–3ÃÆ¼¸31¯í2.éÒ!†‚C0L-ãl›ïåI&H®K,èÃÖ‘†£Ø(CXøGÏÖ•›‡ûÔ“-…„ÇAŒ”Phþ±‹‘~ï¡dÿ.ò”G.kÇ*,,¯O4*ÝE‘{ÙnF90žÈ‹È’}¡¿Ãaô¢þÿÍýÛzÛH’. ßJøÀ}TU®î™5O}'IÙPQ¤š¤\mû@LBÆ$ÀHÛê«ÿsƒMn""#Aºæ_«§,"ß7r¹‹„]‚î›K(ªæÅì½Î¢€W—@œÿP ÞI"¶qBÝW’@Pø‘$˜æ¾‘¢ü·†@Xðí ˜…=D¢ý—ƒý.…Ñ4ˆº ö‚€mÈhÄæ»¨µˆÚA»³÷l;qFÌòC->£ÌôlîªUöï“t8Ä>è2:ØÜŒ„©Ùcp:¨^ò˜§}VéW×Blx> !ýv¡äA.ýgêµÔšnmöWð€î‡ƒï²jŸ×uwþ±–ŽûóãËÏWioúP3e ;ݨ—Xƒ8ò€ÿP.G7éB—Uu:¨—"Ï}¢|@õ„°üô®Ë/Y!¯ÞJÕEVÎ|Ý WϾâÁÖ|Þ ”/Ølðàùt:y¿-qÈêäîavMD!æ˜Â"³^åp1eµÃÜ7*›³d>/ðð¬Ü%µ¼»?æ›´8ÞáÐz'ŸB‘ÿ—{ùÎBÓŠÝØ×LÜàñúáÏwÉzºº™7ìØ$y›¬IÄhv÷nD"þy¿XÓ±Œ·òŽ9ÒùY¯¦ ¢êUøŒ Ÿßß^M‰æ% .–ZÆbýκ$ãUá×t‡‡d(ª•ÐÔÒÐd^µKý—â˜~'ãó]Òžn¢á¼‹.ëÛ³˜2Ô‡t“q*à›¨-ç‚"2môóMU„äœÃpÖª5rÃ`<{!#)‚†Zt×±p°;³ÀèTCá͹a§»\¡í¤åˆ…¸÷l¬@Ûª$çiHPD ¡ÓD+ÙRðÒãé;žVZ0¤Æ©‰¤‡x¡ÄÃUšZ*PàØ‰rMÎ>$¯Çê0. ¶^8PÐèa +˜¬Jô8†ü”Ûë"^Ó¿#L¶öí)À ÎiêQûâÞCÚæZè4hþ^'‡“¨{QM/j¯â0#&™@³ãàY)^_Ëk~úé;nZa”JÉI_ÿú8Ýí>w廬3S|¨ò²²Þ|@›æ;°v^{ÿh„æÅooäâæê¥>fÖÉ‹æS¯‹UœîŽ+Qgû|SîÌês!Û*ÿšMra“ŸÄòå1ã³èl»Î÷^ ßÐl½!ŹKÏÝùZkÓ³÷uVIÉqù¬f¢[/×DËŽ$x˜zô¹.w§¨“׳ì(ODŒi”RØ4H>ãëÆü)¦\¤€eY-žJƒóËkªü 9–_B S‚’¸~Љº«²Çü;$³…©¬”4«X¹%¨B'¥^gä·¥J?E඘2±Ev/b×A¥sCeMÐå|nQìb†@eåà¨%Þ±ÀäaôY[˱10y›Å4!„âì uhkVËŠòV˜-Ò&7ÛÔNŽ9ƒr7ºý0{¼½mam­ãÓdè~¶;ŽÎ•Ñ0>˜ˆFMA‰SÙ¡y©*˜c•¶O“¨³çFhR(kó˜Þiï©ãgñ9S°&"TŠ[ø!`p¦ˆÜ<ï³c¾q: ]žŠ£ÐnïA™pq 7Uú¢lÏÅé¸x¼*OŶ†’‹bìäÒ,p8ÉRD¬„½•ÅW“ÏÄóyilì~L/Y˜õò~ }¿ÍV`€ôI}ÿšîN€Ü.&Éu2]>̦ëõtɡ޷WÉ\’'Éh¼LÖÉx4{¸-ÿà°ß.§Ó?8±|X&³Yç¯‚Ž–¢.’§ ßM¯–Ó?Y2GW¬È'Ó÷£ùèíh‰´u»½MçoG3òíýòöþw<èHíš],“œ¸Ý&3n:»{Ïþ1šÏGNÔ·£Ùèƒø¿[NôïFœ\ÏF ްäjºf5¢·ÓÅò-³½æoïg7£[N\]1™$Ò¿ùˆSª_u\V.æÓ¥è¸w÷óñú~d¸±'õÆýТ×ß­W£ùäAºr×?9ú~)7øð°úp{µ˜Åi¥a®Ë¶Öj³äiI‰”1Ýrà£årñ'x;Z¿›Šÿ(}¹å8Z/X÷6Y§³Ùh>]ܯÖÓñ»¹”Á*½ùz¹•œˆ:^N9‘-îtå©ãÑX”ÞÃr:^¼'Ì"êw¶XÉæ+ÈŠ²œ.“1'â«Å¿&ËÑŸýIR­3˜êq˜5ðL·ÓµHËÃêÝèŽUv¹óÐDdájÄë7´‚UwŠëï’¥zæ½úÇh=úƒ½ZÜ-n×Õè7ÑIïDš¯’Y²þÀÕv"5W÷Q-JVc§¨Âº­û·”­429÷siM’Étñv9ºcEÖ”Éêƒh9W3VC[ ½¸x;ZOåã½SNÝ-“÷ÿp¿šr)^!ÄeKug1DŠt'Tißà«IiQ\–MÜïF³k¶µé癛ܕ0Df ýð^w#ž’Á3ɱâeÖþL&ëwªu_ßÏfú;ÍwÓq2b©¨Ïò¿òàò±æ¢9@dÁCÇNL-vùhŸF€aÔL’7ÏV«hËÑ$ù<ú ­ÁÙl"Ø]ëCîç£Õ*y;GŒ½ŸÄ$uº„~Ð*FÍ2Pëd=›QÎ\-„ D#æ¢ÏtÓSÑÏa”hL¯4Âò&¢ëˆ.¯/þØ·bÜ"Si'!:“BÝ@zXMïFÊ DbJæAŒ T:<lLA8Pj˜¼œa5H^ÚÑ )ÙÑê]Юùiµ-×aØ”a#ɬΧcQa¨®© Lšî†DiÏl„éQo1¾¢Vä{¢©þe¾ æ„ÁÓO ö™ „†vÄcáñW³v /ÞÀ«ü]ðïÈ’eÄæ@ÏÙæOùñõ8ÁÂc×Wå-͉’™$Xöäû=ò†v¾ÑÅ0Æ"o_âA¡UÜŸòz’=æE¶5Îzù]8 Y-Æeq¬Ê‰ÚfÅQÇ©’§¢¬Ô~#¾ö”;aåðÑÊ( Á½“pjQ !,Ž/ª½&HVò2Y ?P u~Üe¡¨[Œ_!X!÷‡C8Ëv—èpÔ±4KéaÜ(“a–*ÖÌÆ°Z߀ÅÚ>u}7’ö~PºÛÉÛÿ“rŸæ…LâN"꣨ýºÃô¸ăÔÉõÛLîe7ç×Ís 3+í;º[¨Çy(ÑšO¸R~aÄÒÀ—úË…Å>5kŠÿœZ#*Düe3ëÏÜ“(Ͳí„~óÍ%uóvük?èU;óµùÈ_™É¹B$â—×É0!“LhŠ*ÛÆVŽÃû%žxùŠD-ÛV”÷N Àç qHšt}<H¯5’İ‘ý28³»^¨|U¤%ÁÎ_Aš†uB‚¨ž·f¿çýÀF Ã rdª½°ð-«!b¥KRõ)|©x­Ô1ŒÒÍ÷lyó !´‚ê>1̲PrÊc¦<:iã«MAçÊðÄü2PÎ2«ËSµ!L¥";þ|¿œÑôQ­/àbrÛ (M:IÉ\=ßÌ„aÂI˜·¶’Êku¢×9kÚ…ÕÒ¥œP^W¥•“¦‚¬¤}ÛOÞ;B£&d/ÏáEö­‹ñoœR2¿ðUö$mza­ÊTÔ yÞ\¹aÙh'¬¡FjÃPZê¾áíbD7S·ÒÚ½3®©sæŸñ€8Þ)sÍÏ«ÍIŽÚÇ÷ŠÅ,/¤^ó®TÀ<"‰4"•Íõø˜š,Íz¨˜åŸ«´za§ßf=§ÅωC‘7‹S<ü£ÐU(Nu\é«m+7²Q‰ÚgÄ«_<™šctÂ’úB27Y‚Îínxt9¯jë€cªBvâcøˆJ?J@`à¶^u»^¹Rí\(yƒrØ€‡ªéÆ›Mæ½0@EIoô’ ¼UVܤ ÿ,ïÈ«ô >JŸ²Þ술U†‚½ y-V·yÑN0%kÔ{¶Eó&ÛB¶mÚ†´cQd­îe›m)ÇÁE<ìEîzõþÕ<ì©®¢ì©ÒÕJ^ɰW2앆Q¨uûÂð×í^§ÿfØ ï3x…ÏæüjqVÇTûA(Û­7—ofzhÒÔ¶‘e>–=½ ßMnä–êJÍžC6 #Ï9ØDMš¬†1l1£¡·Ãuž?9I‘ºëg¤\Ÿ³ßƒÔ´“];/ÐÕås‘è°¬`™Škp*Áu¼ÌvYŒžtü5_Ú…'Ö]“ i¦\Y£ÖYÛUDœ¼Ë¤ª:.¾˜‚Ô8x™Dé1SøÖ£’vÆÒ$ …È7¥äi/-ç——¾ªî˜WbôªOÅÏÂvÙÈŒußYRÎ//HÚ%ÊMyén—UÆGþ~s/dbš€¼{Io=³ÓJO³ª×›‘”,\gÆh®^³þÍ"zŽá˜%z‘6s¹M_æ…šŸÑk‡7?-ä"Ef‹ºdÁÙ’/Q|ýDW©(@ î°ÍV ‘,yR›  œ²¯x))ˆQû9Eº;;QÀŽ-&}ÄMzC’¿†„ùeó¤4û;Ñó#“DM…ìꀋ8óòx-½ A{5ø&Ï ž€ó)ÙwŸ4£XÖŠWÛø²~®ÊorÇ“'R¨—@{9 )ê‰j55_Wj”µKêò°_ø.Éx´Þo_e‘…Ÿê±"îÎÓ|D{D™HÛ á™û`jd„…ÂC1­XamAØTN†ÊÇYR{źMY` Ü ÿÀ4àÇ {aÞ6¯õ[pn²‚ íÇg í軵£ßT$I5»Å*Y'ï§Éü:™;WhÌ|úvĤsà+x ® ƒ.Ð5aîõ¸æ³wC¦ùNé÷‚´À6T‡M¨ÀænИãª&ìg:̹pBÀ* A{¡Z—òuË«üX‹\Ý 0ÈYU`^ciШê&¹vÒ„"N«ÚPa–=ÊJpOÑøá š'Æ•A0m×”àºlÞ(½ óªÕ+GY  AQ_YM8÷®‚ Ÿðð•ËlŸ›…¨˜R«OŸÏÌBÜYPõž8i$ki#ki"7ÛBÖA¹ ‚ìcäšÇú«gëÏÔ¢ˆmÜ‚¦±vM„…Æ ÆŒf šÀ*ÈmI8´˜5·„u8ÓÖ`e¯KÑ•í} EˆÚÊ:1•u`®¯KõSh@bM7˜1í_Ãá¾)m†€$TªPe ëì­Èjë`®uì ¯Ypžm¬'¢qx’mr¡HéQÚÁæ½oõtGçÙ“Z PÛl3ý®¯q’0y1½¦Å$ù¬´³ˆ. š_díOõq•—rp’ûÚÚ€V Œ¼%r›Ö_(Löý‚<ÊëÞ 9+9ì0WyJ–€ŠëÝÂW”¶˜EAÖÿ>ý¾ÿî®ò"P1û¼à"ÓïÍŸá6Ñc9ÍP¤!-šRú9z–P““bvå7)…Ìt-þÞe+F›ÓÈi¸åià5§ýu2ƒ­ÐhhÌP«ÕÀÛˆâ28uÙp¢Z‹.Ùiúü²Ô²ŸüúË¡üÆh,¬hÊAŒøû%jûû:+X…ÎKÌ?ËÁ?„)þñ9Pð¹¶J^H)åq„ØðJL²K*œ²†Mnû(ÈBöQ1-þHCE{…É™:ÌM{µþ®üö7¯“!NY{X––mñ5Û•¹­»ÔëäÆ]p)ͪµN†½RÉJ\ÀŠ7‘Ç2 rç¸î(Ké–A²kŠJò€b–¯M߈P} ®±Nöf/‚/­¢Ó!мëc¾ùò¢¬,QdK/µSÚ’0ŒwÚ^O>ÊÚv íd·6ðN²úJ \&Åq¼åc›ÏÝ[FXŒ[äneTO'y/öþ,J'Œ¡£’|[ N)N£Ÿ—"EPI'QÉ?'Ý ¾@J×ÏRw¡éÅ*H (‰J=E`æÐ Œ]’§œÁà&=üvÙXâ^‹»Ð›oIñœUùQîÐèÚ›•kMÄøjGò¤‚ØÍs¾ÛêÁ=úP &R=v}›œý,øˆƒ“Jé'”÷7ï“"¼2þD`ýI;8æji~ð°è AÊÃqÛ‡Ég‹0‹‘¡­ø˜=Yç ü)H‹—ô»@h+  tWüÛïþò\R¥Ûü»˜¿‰ÿ9— ]Ä}ˆð6ÚjK¡Å Ó¨.ÜFtBC›-Û>hÃÁ&ÐÙ )à&BWœ‡ãÚHAè ¦E0w"Z8:…iŸ+ñçÉ&…$‘ÕS.²™Ò#[%m0¶qц«­ 9_ŠH˜nv´€£˜3iõÒL¡ˆÈÚ»ì{4g±9JK1’Å›Ýyøè¨çׯ}!Wþ³m,“·ÿCµH曂½hÄ‘wÜñû}^OräÖM Û& ¬ªÓ!æt4ÈÁ† yé3Ív÷¬š“…Ó!˜iÚ„´4td!¨×U0shVXt\V¡b$”ÿJ$ν9‡ìUDP2ìª0dÌUaØ€«Õà‰•M<ðèH«Baö&0^4œ~ŒeÌ–Iá®68NôMhtlàΠʣñFT¸™1ÇÒ†ìêãÛôøLÁP€©÷å.ñ>Ui±-÷Z£¿Í yøÍWªhÎe|Ì*}~Ç=ìà¡ô!k†èi††$Óé´Êäjyov2±U™‚¤Ÿåøûµ­°ºïŽñÚ}¿±û™þ¾)‘ê¼€Ä, xçb“å;ƒÅž}?€ß…¶.+0dW>ß÷éw8M2à*B@e(n BÜË¢ãp"ŽC€qÈ}F0ÝÚ_C!¹Ú¼š$?r $ kõ¿+8¬™ËIöTe\ñÇr™nó´hB]-ѦRÞfWù¢—â `? ãyææ¼T«x“ìQ_šd.dƒ48¡’›ÄÕió¬Üp]ôD I…QñÉäNn@N0mCkZJÐþ¶Ï+GS‘X6 ¥qEé’ÂÉX˜§Ýî®ÌåŒ3º§CT8’›LikæK¡f| I£ Ã&kM0>/jèl§ G¦M(6!hófÛìp!5î„îHÂ2ˆC ¼jÕµøS!Ú‡)¹ùŒØ|m(¶‘7ËC.Ã,s.Û ï£Mhë2à'´A#ÓÆ¶PÊcþøÇ£ÃF»L»Ao@Ü©Tÿ–æGX ¹!‚°êåŽêm¶/+Ïéw`iÏcÂ-Añfã¹(àV»G)oÆ–»~yû`޳ pq©Áv|ÜRhר=Ê(YDGÐO‡/O5ôýTíÀïû´¿ 9s¸ªÙF=P†N—í`aäWPh¾?ìPÉ2¬ƒ1Éu–î®ÒŒè¾.Øk4]¥¡N •פÿM+1(òǬ>ºÎ ™1¡ÍóG9+¡ÃrúsÕ§ Pð¯1à7øJŸbBÎo¬Hµ§Líg+Æ_fÈ\+_îkŠ&¯\Ø«cªã„F”­»ÎtÕ1#øœwx 8P„~y wÁç a¸ß3H+¡ö´ïÚe‘£ëÉaÇVS¨G”œ%*ä!5"U‘UaQWìˆX ²~êq7þ3‡à}„‰+16eÛ×`G…‚`éÕ­Õ`ç*»¸ÏwU)u#m¢4Іl·"=UéÚâmhö=çtm¸tÙ -Pí¡M:áÑ 8¢0!¦ù¤J‹ýZöeÀ V•=þ|ÝÌB/θXiDÆÁ—§¢d¸D¶ýki+ØÅ‚-Ä©”Ö²£ßjq±ŒˆcFÜý¥ÏNz§Oñ\&èÍD¼­ÊÓ¬.W+åÐ÷eö˜UY±Éи~ú÷);Á§¢Îã9úkó-œ×ìÐC•}ÅCEÎÅô{N@¦È« ðÜ­Mr-ÛÒë?eáý”ðëë‚àÄÿ&´J²~óRÝG$ÿHðp©ÿX Û-Y·eõe•mÊb›V/ÝçX) …«,+ÚîÀnƒóâkù%kû}2ZW»MÛ—_ݵ5¯Ó4?´ÇVzMfkÝ'I|—å#©ÇºŽõÒáÀøzÚÍ錥éî9-Žå>:UïŒt$ ;†?®w´W3¡±ƒ#¬'Vºlt÷×;õèWC *=ˆ†Öÿ©qªô@1‰¾©þ"àhÛCCe ³}èAÌ0E àb d´ÔA¤ØæÝ‹ ½ªQzƒŽ'áW\B˜üƱz.•øÍ.K!mÚ#²Bµ`ŒatmŒ×S-V]d«V5© WhŠÜÜ$(µñ!p[¾xõ± (²l~šßÏfÈtþÏûéýt€‘}]Cž)Mª!œ.ß ™8VÁ’¥Ü“‹ï“š-tÿn÷rw¦ mBÉ¿¡@mkU>£m ›´Ú… ‘‡êcº?аEÏ$Æ*{[l”!óg–~‰.I›‘&q¹ÌŸõ5|¹Ùl ÔLÇÓÕêánº¼MV«d1g±DK®ª|ë– Æõ ‚BçuÿÉaŽ˜f¤Ì˜lÖ§Y˜ò;6qÑhy2Wk I—‹‚Èþà·±$lØ2®ÊR#( .áŽùr„.C'ö¡6~N¡)mò·1IóýawDw¨´‰žŸÀŽwMòœ;w+!Y³¬x²7 À»%>ϹuÐEwCÒVò4È[á<é&ŸgßÔ/ãíS\*PAÑrôíê °xAQ‘Ù«ánÆl!D?ÔRGE:ÚU€‡õ´q€‡wµI€‰öµëélI€†õš›í6+J‰[XeÅ£¡˜D,ÿùOTïÊ  ù Ë>;fÕúå`;„Пwz_nóÇ<«‚@rÀ²â焨ê @Qlr‡sD‘1µJÀÞ'f ¹m æ5¬Ø8çPB½³ªwHr‘njjNèÝ-žæ4%Æm7·ÔÙöLsÑ±Ž¥CÝ“†vèQTJv !;‹†DvM‚MBf¥u"ð‘*72NÁö`ÇBF)ØìXƒAÏÆF8Ø–ìxØø›’ ÝàÞØ‘± 6;VH/uÀÔ‘°q¶6;šÔ\±U$9*äÁ°`¢º¯Q`¿ášx ¼ã ^Ï„{bàu4¤ë ö]GC[?bÞuD¬ù#Ö]ÇæR4 éˆm×Ѱ6º¢xÃF©¤øZ6GÿÒÊ´,B÷“¨+8aöQýŽãƒRfï¿Oòœ'‹±“.•Šý‰ñøOX,ýP<¿;g†?t®Pâ9 Vôm¼,æ@ïî¯f 8h7€Ét<-½ 2t`ïé¡ñ¯Gâ ^&òÇ@«´!£fiŽÙ¥M0f˜6ÁUv m$ÚÛÚàiÀLèÀ²LÞÖÓf±žŽ×ˆªlQ«õhˆì:™ÜýfGȇùøÝr1O>b{¿˜‰èftÂ×ËÑ|•Lçk5W_‘d¾ž.¯Gc5ºZ‰Çtl’ ´njQy=ú\å ¯‘­ªÎ1pÊOÙ£¢ÃX}•ƒü×ôÈC–Gñ)Ûr°bÖo@éS™ ¬rVi®^Š0Ï uì2 6OQçYÁý¾Ü‰ÔîÂ…p2ˆ)’¥þ÷.«öy]wsƒ:Ûœ„öòóUZç›>J‚/‚é:m€X¤›¹ö¼,©;vŠ®qŒ¢0¢´äÁ¹æ'„@¶ž»`*0ûžmBw ôåŽß#èÀ¤(‰?€¦ÈÖÝãÅEçG×±¯ÖE‹`«,Ó×ÔŸ-àiƒT¼ZgÛèóÜæ=¡n¾d^ _‚ÄZ·ˆ: Ö%"ÆÝ"Cró§eÏ4ß@м<T&øÍ-†>Ë?WiõeÃ9#fúL;‚ú%s¦³ ¿`ØcyLwdC•æE–4»'"5*Jµ…;Nw»>7ﺞ ­KyxJkôWÒ°‡ ˆ>•9Fy™X5©õ÷ãóÀFaq©»M‹ô)0‡q±y1~Îì#„>¤}|zKÁôûªÏDÏ*¸R]Ú±<ÌäkPæÅ¶üÆãèÓØã]~ø\¦Õ–GÚÈ|޾§_…a¡ÎàEðô:’^øa¦q·c€º¿ƒUwx„ª, NvrìšÉËGOêAß-ÖÅÁN2õ6[¨ eÓy%Ã_ÉðWN8EEŒAÆév²‘=tÊ#×µ³®­žåÎ….‰†[x#A—E!TÅÀìж,ÏÕ%œ,L²]v}„¹SdFÀaúÆ,”î‡E¡»&+SOAÇêäiÁMÚ9ž ñŸÑv[Iƒþ"®2îL3¬Øî\å3PL§~gºô!“3¨·¨Mž›ò3¿·‹ÙÙ!«ŽyVGs^Ω’eÖÍMÄìç:߉ک7U~8–îßẍùÇ/ïöã9%±ÊŽ×©<1åºÈ€ÑÊÙIgðð+mmYWÁ]P†Ú><§ÖLŤÌÀ2¿Š™ˆÁtå’©züÑâà¿„ðzËåܬéït=1¿œ#G!·œ=±° !¤„Ö¤0'ŽÙ÷chÓ  'z:óšnÖ¦û' Q< Ò–­™í1è,·€€öS—szÏ `D6(Ïi=2§,"óFÕD€âãðÚöܺTzÈWP4|¥ ‚ÞAÑAîC(ú«÷ŠþLÊÑlâ¡y«x…avu(ÿ‰¯‚@8ëIMȨó_Îܽ×`ÔQ°Fvžu âDXb>„u¨z&Ä;fÖÂ*’@ ôeÌõ;ë W,8ïy ¬‚™l´t¯³Ë3K‹¯Y%êö[¤S[€ OðQsyM½§òa¶:+ê\îË*7qêz½-DF’`5}˜wŒðK¦#`¤Pú{ùøXgA=|ÿ|܈ÑMTÃÑÑæ íø™ &U± ¹“9_>ª£ž5VÓ‡d¾šÎW‰<šð°XN¦Kˆi÷&4–$ŸÆTxph ÑW§ÇGÏY’ÍùäN¶PwIÀ †qyTŒúTÈ™†<&½.å©ç®e¸‘q‘uóiŒäm#4’k>c°õ³c‚OOBòT”U&uŸZlR£$:P´ôÃËûFß‹²À ¾¢Ø°²b[³¼o¶x¦a¢éâƒxòÎËzܵE°‰¦‹HHy<ïŠ z驚Ç2Û¤ÊD®KùÍèeu¼¾båŠHH•Á1œA̪ӡ¹ziüÑ}^Ê ¥ƒ™½‡câå1† Í¦Áb|>&df,DÂÌMA¢Ñ—ÞÁ0éÅ®,nÓãæY¶[@dö-›÷1†xØÉótc¦BªiuŒR.$NT}’GsƵ>É8*í¢¯âÿí4ËYù-«”†ãÊìš | «³-s`ÏUZøýá™Èž18‘U¾gF×Np˜Í«…Oâà×qpfiá¡Ç80ŒFñ?ÆÁ¹¦Ä×Or´‘̘ê4@dÂÓ„"³›&´]Ò9%a'1 ˜ZØpÌ´!<›¸á¤é6jìÍ\#ÄÚ=“ t&h L&Ð1˜LN‰…šãLQ@Ïc2¡NȦBý1DÞ¤‡t“_@3¢Å3­®?¼43|« I¡¦ŽÛ4Dó³¢>É F“Oª«fßi±eAÃ&slV!ë å…ÐI"wj¿¥èñ-u@—o©꣥èô-õ½5¸Û·²ôû–:¤ã÷Ü!õ@L„ܱÒåkœ V¿­óÙxÛo'àêSt‚«LÌ`Aû4Äl.íTÓ[wŽÄ¨­.»Kû‚Òw±3ŸÅ‹»m§ôtS¾5w%_…­Áw1ŒŸ\aEI`EYÌ uš#ðH’Ï€Ô`©½Ûêv‘–È~üC3é*øXž hVUÀ×ö4t¨ÊPèò|J„¥rÚ¬L¿%ï-k)êpK²€£hNC¬ó}v›ïvyíî-6…ÔAÞ-–ö»P*én'¦ÀœC§?óe½{Ö¦yà€¦àÈ8CªÓÚmäôXBV|œ­|+ªWÄð®]  .ø·=%7ë® ~ õ§óÛCb©4LCY7ƒ ,÷fOCÙ§‡†á:ò‰*Wù²mÜNÑp¢aMב~ûµ‘Ž<z‘¨Swò…+Ž÷‹ðK#)^ƒ¥‡ã‰#ˆÁ0.E‚™‡p_¡‰—T:µ¯t"G_@Ä/!î¨ì½DåÊ ÄõÒ|>Ty鎵M¾aòO $ËŽåø^‹²Úe"sPè6Íö¶ÕÖÒD-î>—æû3jžÜ«,Í÷>6g-@yñœÉ“¨ÍñYyÔ®*w͉;´(¡_ý#h]&ÊÚ¸¿cIR+Ô5ž0yyzM#å™·»e²X&ë@ð|±¼¥Âå¹8"±§ìç˨0£#O,…ñ¡Á•‡F^‰MvHÌ¥ÓG I7úЩ8:“ë¶—Œ@ jq[—º–Îc\×4-ª±lÕ/à¬élOûƒŠΊÓ>«¤ƒ‹O~\` 3ÿ1ªVÛÙÓ¬ãÒ½Ž?ž}×èZ¸,Üí”F~ü-QmZW§R~]°{•Ú ÷ÞKkõh'½š 5\`¡IXº ùbþ·Ì]ëÍ ¹!‚0L>Ò¤ÿã\Í´…ÙêÓÞu(g…!…Þ:Üð‡'°µ#“ÐTÉG,3öx×àÂ4¿`]–zj¢ÜÈGJJ äDˆÝÏ@w‡üh*‚OµÚA¡‘:çn³7ðyôÊ¢“,=>›îÜö&ŒxìÉÐB ûTãäi¶ …MX¶O¿ß¡¦¬†4½)kU‡~Ýv»òÛJÕlÝ5ÉÔ6`´éð@p¡,[4˜%,3 Àë¤%Þ"Ñ’Bf‰‰R¡Û­Ÿ.*ºOm‘dµë}åÃ#Š&„Œ+«9ˆhk‡AK>$ä5…{whŠ5› KÏ‹½Ö ZY”¡×Qî”.‹°ã4“¶º euVݨ0EˆxT0¸BŽª¦·ÏYmMMóxZL‡Æ(¡>MX°v:Ù‚ˆBAŠ>xQ­€P-”™ÐŒ.Qր朊Mzzz6Ü#ûu€Ú=ð¸¯Ö-ûZ62hJh ñ÷mzx5-Ž•ù¼Vå>ʆEÊñ|ØàØäêw8 xÙü¼xÏß½±Šd "…¼³r#ý5*R8«üÄn¡-™'ëd4{îFcp ¤©¥=&¶ÎÿÃ…J›²~.w€m â‡5[G »Q¢û!RÏè‘­ë・CdG¸¼Ž‘‡ÐNÅS¶:¦»Lv³Y¨`‘‘ä:ïØ\¦8…ÐÑ£°ªnsÈ’–žü%ŠN-©£#Þ½ ‚t¨²¯Ñ¤*“×eøµÖœ“2jݬì3gq"Ô–ÐrüdÖx9£½×zíUiPÝZ‰„;b˜{=íÉ *ÛEón´z÷ÌÇËé­ãgÛD‘;7 $è?p:§™›ç|·ÕgMé’t+i<&í6¨#îàÁƒÑñ‚ÑÅ´/ÎíŽóÌì4'BšÃ¿üô˜ÍœküzÒ}ô”!ÔyÔçtóE9:…ƒ·Ù1Íw·¢‘¦O„º`Ñ£°®`3Ö¸Âc.O¬˜o€ó&˜lúnòƘÅõähý€ ŽcÚà’idÖrzC;z_|)ÊoE¤ß ‹¶%7'?EuzÌëÇ<ÛJnÊä7QÙ@’’4ÉNâép(«cãä©émnRUØuYíÓ#”\\–ì #:ù‹ƒ\F”b"ÝúÒ2BÀ)¼ˆ¼ç/ܦa¢Á”f:ünBí Ap8A8™°2§OG)€ë J}D )†¯Uý™¿½i\ÞÖ¿èñ96ðsnEèpÙç¼Mžñ¹ù‚ÅðÓsZlí… +¸>nóâáqKÊÓ1€Èª*€‘Ôj8 EFÉȨÖ=ˆß¡'Ðêím»j»AÓq¹ù+C$úò$ð *–Îõo—Ïõß"±ļ„3Ÿ…þ×åóüßÎóÿ»Xž7»²vmK &]¬³¹XéÄ~·ç4Vjà}Y "•A.ä,Ðcsú›ô”i‹ˆ}¾ÝeÇŽwÙÖ%± á[š…Q÷Úñ)&Œ¼çŸ¯ò§I¶É÷Öb‰utÖ…i§|H`-ý9`að<Ï…-÷óÉÃýOW«Ñò‚k²þ`@Œj$£ ”Gò¬ãðQ¬¥¥Ÿ»›LNÐï£; ââä°œ|…H^0â6ÿšw׋\V—rZV¬0ȹ§ »ær›Oã{…‚uˉ@^?]È^ú#ZIEÔÚ{^­a­sŸ~¿H[ÛçÅeä”_³»R”Ê,{ìÝÄ’—ùÓs<[¾pؽ\$Eö$í†8’\½Œ¸PExC’Wz"²\z^,1*Ì£Æ^øé³~¸ò.WAêuV¬Ëõ³«9z% ÇD–=Æ­É 5xÒÅ¥œ U[kAœëA‰Yf ¯XÀzjÒ²žZ˜nHà>}ƒêiëZPmøçü86\ÁÚ#¾+¿ ‹y•¯rLÄc^ÕÇyYü'«”#À9šVy-i¼˜¯Ö£n‡Ë…Jy_«ÆâJ þ8]. Å|Š„¬ÿÄ8ºpˆ‚E‹UôÊ|'šêGQ&8J–X„mó§ü(Ÿ š‰Ñ ­œâi™nóïXá­ç毅yˆÖË­näêbæ2-¶% K]ΊáË0LÕ Ã78J8¦³NX­ˆêžÕÚYÔqrЋə—îØ2LT«…ü¡ÌSDD(åq¼?ˆ¢ÕC!CÒ6»,­®rßÈ d%jN€‘¼ÒĈ ?¬´¨Q±]fûTú8­0±ŸâäR³ƒÄŸà ^™»ü0 .©H‹yÚ\¦75þxE¯pÄÌnñÜâ“¢OŠ:„|#ü³ÜK½«ä«³ ZÄô©7B¾ˆiƒv^/Õæ',‹þdiXaú“¥rÊËT®ó&¶ñ NRh‡SJÂ]÷ò“˹\oΛtÂà©â°”ÁSÅ©çªP¤&`a€ÃVΗ3ªUD›©Æ$o…f©0Œ4[÷š\‰QÐ9W(?¯ÊÍ—ìèž*ô Pð’—“˜æ}î¨ôx(Iˆ›*ùN×;uŠŒÔyI‰ iýf¥Ý/gM‚Õ›ÍþªC ‰Í‹½ü”¶}ØÅÃ$úrü„MÒcúT¥{ùŽiv¤Rä ?Ÿñ@ëQ7 |gî á©îÅ8à`*N¨¿â ü5VÅ…!úˆÇ@~êp ÅêsåÃÌ‚Aîb'ŒZ¨Z¡üÏÁäÖìÔ}Žá È*ËÆê;‰¢ëò¸ ÃT¶ÝÛa&TkPNlùþ°ÃC7ZAuk(Èín.òîwFŠÔ±zBwÍĆÀ¥î`"I›_ûÔ!^"˜õARõ‰ÅÉÚæu/SGû†h…ž¯®-ïê=ƒYf›,ÿši_ñ+u,’&¬²b.¥wíòD§£Ò‰0jÜîädÍÕý-ÑL ûdûª½üá]„T"ú8_I)ô®m 4ìWU*<¬ìs.Ÿò‰î\Šì÷¥;p&Z–}pØ8% ŸÏƱºS ^h7, h˜¸ëõ¬_Z"`¢½¬Ë™òÀHry8¬:vYju¸î!˾`Ô@ŠÏééJÀàÞÞ°»ö3ÃdY…°qãàú:„º}3çsÞ»cl7"ƒyöm—F€›¢Q0 ïI\žtH¯}Ûûó&ËAû‚[,¢çJ‡^„÷ÖÏ!×/‡ìº$¦lè=S)óÝñx°¦žvmtŸdø”}v|.·$Dt’CYÔ™áO€Úw©aìc)=á-³m.º×±f¤‘Ƽ[¯ï„1ãåt´žNÂÀÑx<½c!ç‹õÃè~ýN:ÀÉ—¿9y4mÝû^ °Ëéjʀݖ҉Px{?[?Œß-’1#¡·‹÷ÓÉÃÝtyËÅ®§·waìj:}X¬ßu÷v1I®Neܯ¦wËÅ¿>„¡W£‰(ÜÞOWŒâ½Ÿ7Uü‘“Š»ÑéXC‰O–Æõby•L&Ýõ‹@\ËÛ¼,ÞNEº¹ÍX5úÑÕŒÑ4T)«†Ïèu³DÇ:¹.î¥-:Çõ,3oû£–j6¿]¿‹¨Ž»åT¤ááz”Ì8p‘¹dýáa½X<ÌFË·Œ‰¤hø¢»D¶¾ÕýÝÝb¹–¬¿aLv°åûéòaº\.},ºh9͸xÙ®Þ =úçˆÑÏD×y/ʑת©ü¦"r¹Jt·—œ¹Ì Z%>›…ûȘz¨„k{àìr¢Œþ ‰6ÊöQ¬Ÿû `¼Í¦Í­‹;>ˆ€ÞŒ°g $<ìˆQûEõ1P?µ›KâÜ/,áTëmµï/ª^ƒÍ˜t¼§›çÌu8é™㹬†k鯜#Àìû!×î#ÂXt3ÆŸŸÜ3 C*3ï*Ãs4Ãt.zL÷ùî D­#1¨B@ 'íÅ_<5Ajíã]Ycm„<¨—ä°´/æz‚r–ƒíD”_N‡µá=@¤Û$"¥°Jµ¼p¿9kñ&g#+À^íg4Àˈúˆ‹’Nºg}©&tþâ‹),|vÙe˜[>ÖÎ º®Ê½ìL«¬úšoÎK¬”ºÛ]¡O³}‚—\Ò~ùñâ>ÆËÃs+I©’-Þþ¢ê@öSgy(bÀ9Å&h³Vù1¶,íï@÷”·Gh…Öêæ&5 ëKŒsdžÎ>lÓcèþä0ZDw¡ÍÚ®ÊÊ¢¾z‘©#nY~ºV#'ZìÖjt|Kj6d±‰nÚ6a°ÛcZM‰×Fö˜H,;µp“V‘kh£’Ë{â#…ʤéäØ0„(^ÔáùŠG‘Jñ(Êõóéè<Ù*"ÿ¹ú= d,ŸI|”•¤˜OÎÄb#B6 !iÓ¶tÍâŠoÚɬ›™6€!@–:Ä—ß™tñÝÔk²&ÄÛ4/.R·i‘?f½^íD´¤€CZÕÙêmj !9Ýå6Ý=–Õ>ÛŠpçØ—œÇ. _0Òa$’¥T;EoŸöž‡§Ã8wB“|!`ÊaLB‚"vþ]ªRÐǬz4ü‚£)@÷vö ²­ç•r™ú¥¹YQ»zƒÙôÞÚU€kâ ¸Í5Dï¬ÍÍ%šŸl=z•ÖùÆ{Ôg…/*GpX=m^.K¡›Ö¥¸£N€"L¨[ÑPV:ás»”µ…0Nµ|hÏ¿ä¡ùFâSà±UÝ8.†à1‹pßd#èÊV‰Ù‰! ;ðá«ÕÄ^sÀØG}º„„Pt–},œ A¡À »µ>ù‘8Ĉ(=çrš} „à=ƒ0Š?D1ó$ ÆgGÁpϤ`ü¸ƒ)˜”ˆÓ)¸îB‚?”R`gH sÔŸoÆË)aÍZ…²iMH[âZÒl•|nªÊ¶½‰¾†fX¥ˆÕbüÇJîÙ®jË,]NïfBÐñâöv$.¤_À5y•XûÖ.¬Ùx»ÍíÃr9½1GAåñ‹d2¯£H“äúZÓ¨‘M¦–K«YuWu/Û£Hyˆƒk® I¸¬ 41dr†J#·Ì#Í}ЩMâ×4ß©…0¿“¹C0çÀ´KĆ^bdžýð„y‘ÉÒÜuI/B1…¬úvȪê?’ m9>#gÛR©„sDF†=Þ³½Ð"üãÄ!òØ"T!-³ƒ»dêBeßSw/éÂ/ff4¾ ¹ø9.÷û´Øê3j{kÈS2 h*™%ŒJS¤9à·£¡Š§¡óÔ_ UB5i ûÀ3úNmšôt?g˜9zÆigž%ô1²jÕÑ¥Ô £íUdG4 ÅZ9ÐÊ×\H„× ,œ³ín…=êÈX0”„câbsàon·ü#ô}/Ée#· \rŸÇ«6DíEâß•!pò¯æ :¨Úš0":ö+D½`üÕ c=b…x;L`¡´hÎË á #qoÐĽ‰JÜ›ÈÄ…“æõu´—ýÛ Y«A4gt ù„ÇGà1~´ ™àQ0[„PzCÕÁ‹°‰ý8$>L±v€H[¹'RB×: …N\ç4ÕþL4ç¬ÂÃáa¡¬7‡y9Évé‹}\¤Wê¡›˜†ú§n`š£D“æ8oœ‘ÆQ"F›Nˆ‘w°[ Џ¦‹ÆÕæ@³®·Iƒ*Þ¿ˆj.sxç/@Ç#…9­“ Ƴ·(^²C¯Â X€¸öZÿ°'æîݺ‹ñŠ{Ђ†M%õpÜ‚ÇYk6™L¸ha„W¾[¤A+i€.24 O ØwúïþtHõD,Ú¾Ò2› ñÝÝàdå#¤&à˜í$^=pqf‘I¥µ‘ÄŒ‚×¢ñ¶}ŒôQJ”¾ÀIT’põ—üðú¦stŒ€Ô—¥)l]ºçw*làz,/ýM¦3ë—Y-ÔŽÍh2YR˜åô~5%A‰¾xšŒG«õCrM “ÏbMÉèüËad5Ÿ\Ý“Ñ,Çï)D¤jmiAסy-Õ`øqš,°ó[°÷[ªûÛÀ¸þoqÑ~m¡¨ŽmçéÙH÷!õ@´ïÄ ÀSH&̹¯Bàèü—Æ£GÀÀÓ_Ç߀õ ³dµ¶®{}û—B,§«Å̺àîAæö…\?’ÙŒ –—\n23ú‰Y&ï8À}Z¡ÂSµï›ùdã\Æóeh#1#¥|ËwÛMZù³ #û÷üøüû]ÙÂ}½‡%§ •ÐMdÂÕ©>ª ŠRœ‡P?~PÄ»ZåÑä‘yݧÓ)fàD§EYè³zd¶š«\7"¤ ä.Ù­è1 €$‘<øªß¼Å8“gmMB×™émøÉSQV™‘PU¨îñg¶–]å99w¶l²êIy'¦Øt7/ȋɘr>°²Š•ËFëÞ¦EúñyF±D’^iÀæ¥JÄmæ¥ð0’¿ßüë6€÷Bƒ^f< [i´¿¯ŠÝàç@j§z*ëlQí/¯"óú½œv¹˜Ž’R²¢ ‹®Æ и{Z_F€JOŠI’jmŒË½‡³t Ù¹k¿æý-XáK;–ÓïǬ*ÒÝuYí éº@Bϰ‘ï-ÿ™ôù"ëåñ_ÓÝ+g5ÅÃT¹Ïñ ×–Ç=äÉÓK6œ1ओ‡¸lÖùg¢âoYÿ-˜­ßTá%ó›Ü6¤‚­bñ&+ƒÊæ7©woË*›vs¡ºÈ¾èý{D‰þ=T^•ï¿mÿˆÈÁ?T!D½§V&¡Ùe„dKXÿQÿ¥2(Ÿé-‚¨Sµ#šÿZÁl唓eOÔÀœÿwDÎÿ›‘§ÿæxˆö8Ãï¬í¨–’Áάâiƒ·`yRŒÎÝޝÏo·8E ]þò×À³úTü,úë¦ ‘sö߃2ÅeƒcÉ2«ËSµÉ¬¥œÖµw Ê7T6ì64R 9YªÊš3}w'HV[éñ„rãã¶Ùc^d˜ßò3³«…Ë @Òï&fjø>fœäÄF§ˆuÓv)§ÍtpÖÅ”C¤‰Zu$ZŽX½%Q9¿[YUÅ^÷ã_z—Lá¼æõ*Kwäî«jÂ’û IQÓBÔ€«ßÐ4H¦üˆX€ ›»†ç2&tŸººß —FÌ¥Þ°ä²³ð“€Ñ°m©¦ÛD¸ž&â}]y$ðJ#ÊÏNêî“Øœ4ÜD àÊ‘¢kJ˜.yCˆüñ¶Üæy¶]墕¡¸ ð„–xì_yà`T«$¤Ak»F8¼ÊkÀ}Ž;*§áJ ßCPxyÝÀ¡+Î&&èÃÎi&­Qaôsãy W•‰– ¥‡ïýЇµ¦äª4¯â©LhW£^óõ猶=îj*H››rËZïéíÚ$õ:$WÈÝ—'Ýb²Ð Lô¤ †•ê26š‰r‡sCBp¨Ç†Ù8—="«Ž/\u”Û)¹P2´Ö¢´îÀ¦Cð@±}/ºKÊýLÍ×y¶Û†ÎÈܳ Û¦‹Ï¾¡ ÂðY²uü?²—èÂHìa,PkQ·<ö,­mlˆ"¯xüè× < ï–÷¤§OÎê¾§fÂØšƒ“îsS ˆmê#dk×½ö@ ŒÒ”gjdTýHŒÄµ;6ù[0`8erÔôàH{to1‚ûöJH3>aÍÀ™ŠÖû4ßUX74üòåÇ,8!ê°x|¼K+‘-Që¡5ŠP¿áïÓ™$Ñy×e³£üÉâ$v#ý0ºBf²mðVý;<1ʈ &¦EmEÏgÙ¶5}aÔ&­³Iþø‡¢s’@gÅy9¶VQù¶±HÂl³QO.À`Ûö¶DužÓ_Ÿ웄NšÞg~9{;ÞŽÛÙMÇ×*¹5Ǹ>ˆQô%B74úˆ‘@a5kÎΙ>°Ìöå1söAäT Ÿ‹b_:´{ú@ ”#îW5+ùy¤ÿ”7 ûðZùKi²¬§ÉAØÝ= C *Uùö“£†´¼j.£i%1DUH¯$ê•@½êQ¯FÝŸœ$;rta¾ZÞ&ã]. &}Ò÷ÚZ–"Ítjs¦4-jÙ²$øzŸÓ U2o…Z|Nw»lÛ¾”ü8É3¯…ƒ•ò;„Šû÷è”Â8Õ®~Ï7)íÿ"¯ºuÅl>²ïòp°u¼ª×Ã耇µ©p‰ýÅ)ºxýü_äð“W¯æ—ö¬'è2 ¡;ÓÿE¤?°NÙ™«R“×i y¡2†ºéÖdqUö$ÝZT!qÒ•È ¬Ÿ º?rRy*¸é”ÙæØVÙu*fóÛ(›’!%Ê–òØ<ËóAÃѦ `“šô$ß@ ”F‹U)1^£ ÑÒåP°šZ°|H€¬²ú˜V¼¼EUyKо²XfqÙÈ>‰ …¾Õ-‚5G¾p üè4q *|;%Щ2½¡x[,(D>`ŽM^†¸‚šò Žsm9såΚ>~N&—ºGߪË&¼òµ.§pô£3˜ØZ6eOÞfG¡ÎùøX„ßräS¢‡(žãËú¹*¿ÉÁ?J²¼œŸ…^ÕfÈ9üquL7_Ö•z‡," .·ÛºÓö=Ÿ³*Ï/{W?äÉÎì!Ú$mEŸââ+ 8_›ªÁòmã✬¦…xkt÷…z&M[’Å˵“4x_ŠB*éEÀœ›´*X¦’&lNU¥þŠ„sS/ «aÒï™ø´Ðnâ#Jr\õ±RËôRcG‹Õ¥MÚ‹”q…c tGdžîª`Oˆ²’¸RUPæMÿ°ÙÛYÆÞ™16SRn<—ZYëªn>É´U ñ†e•q*:oVhƒgî |AKR #б*_šT3+YºSVj*˜ c¦¥]ƉKLËb·í°©Û Ö;ˆãYþæy÷˜n‰šè¿Ÿ3ki~[½¼Ú2³d_5¯ÎL‹¯yUòå0Û ¶ÑŸÎ’QjgÉÀü2Y £:cæLÊUçpÕׯåewÕ$fÁŒBž02I!ÅGÏY;iÃ%Å®§p—ízgí®GgÅW>øP•~Ûf#^p!N©›K͉±<«Ù†Ðjbº#pýúÿ —Pg¯ŸÙ’¼ ñO¬4¢"?{Ï’vÎr›%¨=ϸsâ*ßf¶Ï5£Ùð¥ÓoÉd˜v¼š?EèSà¼)xˆ<Þ$ͰVxbÏíQBı”…àa•þ°:ž>cǧD+v-dP]iê«}v|.·†íûðKŸuþI >æ)w5(BtL^9'ÜU@-2v £a¹}ĪüeöÈíf¾.7Ï×RÿêÙ§ã P”‚Ò|7>ž† ÍDŒ¹Ö¨T¦üæÅS½eÅhZ}jåÛ.qg*4ý míêÓ :Òo%j o.\¤¡øâ®IþÿÇÎx«×÷£3ÖòTà_´ðÚÆi/k1WnâåóÀ˜MI›$ÑeÝÐVVëé­òÉÏd (¦Pfö^ím 4¨lšä6ÞÞûöÍ)zN77`oU°WÉ™ÉiO£ñëÏÕ dz#SÁë ¬ð#¯´ˆK¤0¦šê³ZÍe«5*Ýϧã¶üV0Ì’†ÑŒR)ä_VóÆoí°Ößb§’ðqè ܸQÅã œôEò ]˜Ëõ; Ó¥pÙ̹2£rç’c²7ÚI+õåª<î‘^ôÌ¡î‰è ‰de¨¹¿u<Ùãyñ°¼s]|÷ q#ÑðΑU“ά‰ŽÊ.‹ÈÍðöióóäí˜R{-d³ËÒ¢õ f,c‚´šgáý­Rxï9Û\^*gÊ™ei™CZÿÌ‹ åFƒ¾î­É¿îNBÔjòæå]yÜx塜”á¯ÿpP‚L¤ò”‚dÒ‡ê ¤2Œ`‰U?Í+ÝÈC)òýäÕ—ú¨…WVú`*pSî§cÖ8½—Öϯÿöé BòÖA:8¼ðÑçõ}‘ÿûäî‚Ù±æF”Vó8DA{XžFãÓ¸ú̵«¼ÃjÖ{Ÿ§ÂT@ Ô#6Z°hÞ P”<²UŽ×ð#T¤¼¨¤]î¯a<(Ý~ ,_à¡ÍxÑ¢„§ã`úsºEyT9¯‹q«ÊZ6„¿ÆU–ýPçî$uÏpv®m½'I-v-‡eCºò¨qÂÖŸÿ÷êå˜Q5%›D#U.Vq=Ö×UÐú¤Gã í)£¼¢™Å6*çé^ÔU › ã-{ø¬t€µá*c²÷Q‚ûâøÝ犢0üò®EêR­¸/…˜&fÕ ~n¡€ ùú:”vú€VKVþ¼ð¬eç“«ìœr?è±óruÚ<£3sÜr€‰Dß‚ 13ÔyyŒšnûx2y.슕®Ñ)­šµMê¡J†Õg¼»>‘p»Wž¿é}±ëîƒÒg*€KÊ:»à|Í„(† ý'žÝÉÀzLT_éÀËéÛdµ^~p·É|ä }ë‹QCF`€XƒÆ _ÎÀaÃ3‚xì€36’Ó$ûÃn@ÃÄÉÓ/ú„“S]v@¾@ç=PMŒQ.Ô»¶ë QÁfñl–ñ¹OëŠb_ u‰äÙ¸›¹¡Wdã$àwbÕ(§ìB–‹f&¢R Â3+8ŠÊÒ †Èæ¡( ÛMœ’–f´c'Žf°™*‡/Q,Â$JaðÊ7–Ì] käê79ªÄ´'Të,Ý6õ3Öñ˜ÉÞAæ² ðøýt [î&’•ôS³@h(A-\m9R€æް¤Â>jè…ïÊ'{á Bh…E>Ÿƒˆ@D«d6¯)ÄÕ2™^S€÷ÓåÕb5¥ ðÒ¿£;¹Œç ë_X¹îØÍ!% "¡;V‘´Ýè2HiÊ9í,ûš¯Ø&µv‹#<ÀB2¬òR- Ð O­v¾NháôéJûæ…õƒÚâ|•ʱ~¶š¨lT…ºƒ¢?ø‘€4ù æüÄECÖ^Hú¬”Eåï0š<Æp¢qÝt 65d4^'ïGëÅ’ÀLÞŽ‰ÐòóÿâEòS-†2@7êÀýËŠ ~Ê ùòX ¨¼FxÐ6Ð8R5&lâÆëë÷î1+‹Æ[›¶(ð&¦‘»Làam@éC˜¤¸¬9º_:Ñk¥AØL‹CóЧwزý‹EÙ„=Mífþ;nÔ^±u;eœîvŒ"0ÀÛ²ÈÀ¶k`²ïB×è¿CPô³…$`#©ÙB2–YÝ`‡©²<½ae‡Î|ð“¶YÓÁ»Îxe9v†agÁ %áü%Bør$"JkYLU­¯}5ÔÇ@ª?§„£/®@bâT GíÖºÌ?j%tÆÅ·|ÙíTb¹MPbÓÖ¨ôÒd'$ªDÒu2'’Þ Ã¯()0/¾–_2¿– )"OòyÒŸoÕeNÈŸò kzMD[ EöMisDB“àÐ_;FýžÜ`ÝPEOE^é…S ÀšÕ½”wá݃׃ÇU½·Eªp,ú†*fwð\ßEÜNÕÀIûÕFÆáå;Aî'½+ëcŒfìùb"Çž¥;姸ø|”lø¥ð@#\÷ÁáêpWJ“RìõZ‘ò’[†ÎKòô°a¨ìÛÈÖGTÊ[ÃdêtOî%×Féç.ŽFˆû!\bùÞVæ¶Ÿ¨3èoÄ¡LºQ)“NÑOUÆ_†÷9ú§™cýÿ#¹ÖUŠ"6Åb„¼¶ŠÂ  dHj,Šýl3…lWÏ‘‡p0Zóî3IŠ:WØ\qQM:(ÔXî6¿Có*‡Ê”n÷X®a þé­½ô2’Ëj µ›àpzñU·œñNL ­g0/«ÓAîJÏ9ø Ey(pØ’iQKiqÐ=V–Xö¹Jy†!†ÈÞn ?Û`É-I]ßÛZ°iln‹¨„ú qXg,Y¼5ŽË͗IJŸbj×Ã(«œŠˆ1¿BÊàK¶ËެUôºÍëCzÜ[¡æêyïG\ˆåå6¯÷2}CN”à2õŽr‡4ÎF˜hê×À¹é¨Ìø2ø™ñ¹q:=^Läá=œ"‡´ œsxH*"ˆQV3®¤b…D–Ó=k/X¢NêV#vÌ¡­{u óT Ã%(QÏBuÝQ‹\×hô2tŒ'aóy8h1Ÿ>¬¦ãÅI9u¸§·ƒàäf@ áQû'÷ڵ⻮4ç§=¸VzÚ¾÷¶†¥ãPlcøÜ¾Þ¾÷·„e´Á aà îc¸„©3xÈM lÐAÀš w$Åà‹¹õØ.•íaå‘,uœ#±³žxBh5ÁÁ3#šb^ìØ`¡\Ì„ªƒ œ¥UˆNÛÚ‘–u|ôc¥ÃÅ^¼zH2ýVpþ«²Db†oÕÃÒtæØ]•õF)6JUÙcVeÅ&ÛrÌ1~2~@§LtuO«ª¬8“N 5&Œe‹J$4N7‚bæ1.%œÌHÛ›ÍâÛÍ "ìPa©È«Ç fÙcœŸ¡M;a"•À¬º8.7ó÷²o‹¾ùÖ/D#2ÁyÙŽbò3­î7È9Cd®™mÏÍw •ŸñýÇ;‹Ì´‡æf™Oäd¸nÖ~m6Y]Ë=îªÜ5[ݸ7ªM>ÖxØF€·Ÿ™à6·ÒMM‡Uñ'ÙçS›é.ä®õµ‘9Ÿ”û47vBq\h‘2•ÝOý/ ›×wUþ5ßeO«¬å®@GD³•›ˆbç£YHöÀkô§ËT1[ÜG¦¼Ís¶ùr—‰^Z×ýù“^nÂMà¦Ü΋ìÏüø|çV\Û4I ¿³¢ ¯$Ñ|µ‘,ê\$ ë”,9þº¿õ¿f¦U>R¶Ïÿ“q‹/Ø×c.‡$D aBÃÅ` ƒ›­µ‘jô·¨ ‰Œ&ŽÝàw™G^¬ÓJaÛÒh‘žZiCF=£‹Š€ÓÂ\"ºÖðóëÆô£ò­^躔òm&Ås&×µ·„ËE£œÔMÓÍNÀÑ‹F.Ýn§EïlƬÉb“Ò[s Q‘€Á¨•ê”x³£d"¹óòØ´8íû½g˜×º<÷8 JŸ¤ÏJlRäÉ÷¯Ù)þÚr솊¥©VûΘJnSÔ`ÑñVÃmZT  F ¬yÃ,õV^SäþÛU)#¯çÙS*ÏÐö”…<4²-jºA^ªÈdlRnv´u¬¾Èð®FG=¸Å"«iàÙª0v¨bñôcÅœ.Ò<¾ÝÞfûÏÝQHvÙ4ÏA×ç°÷Š׸4S·,NÜXAÍÒú¸øVxëÒ᪘ŒŠµ9,:ŸÈˆM1XÍ@#E3P°ÇPk±[y(û’ó: •ªû^}°ŠÈ€GL£f¼ ížJñÇó^íÌgòÉ–ÖÕAx²DpUù5ßvç xùIü\òZچŬI+‡!¬ª<²ì*1w‰¬ ª}kÚ£×¾½NFqì‚9fd@–ó<°AÏ‘tÁXÿÒt´XGM‹ˆ([¢q0#‚ãÄ®V‹.‘-PÉsÄÕ‡lVâó–ÊW¤"]÷]&éø2ÍËŠ§¼ÈÞþðþÝÇ•\¶e8‚ÿòJ¬Ô\1úÔzÔa 9uÌPS«VŸ§»ü?À– çŽHõåG¢úÃ’1-6åV®¡w¤p@ÂÙ2ÎŒ8Ý,Ë×êUèUdV—äÆxá­þ!CJ#õÓUxh§¸„5]|êÈA§6›ÈnR‡öGKØ_Ût‡U‘%œD´A5°1örØNG q;w2Úwé.ÀO„É"Ú"c©È€¨˜Íd‹Ø¼Îk,(Ò#™É¥vŽ-`¾?ìäJ>±ËHf‘}ëåËÆôíˆìAœŠîÑœÃ7(SúGâ£yÍÄ¢ˆ"¿-«lºËöYq¬¡ýw”+ÝT6Ĉ6°8´côf„™¸{ÿW~ƒ,?˜[pr1-n‹‘“uåÎ\ÅñzT!Wioh(—÷-ßm7i啹‹;¤Çç&âX›:DX„t©qzÐešÐ…Ñ…žŒ~ÈŽ+ 3Õ(-œ€Ñ®ÏR5¸,cO"4NBuO¤–Â%Eë)\ÔpMµÉªãÏcñŸü1—/àÇUp|9xéŠP>7Bax\zÁïNŸwùæìÅïomˆW1y%£¥<.¡¦ü²ßÅÉ_³*ôw‰KDªÎT¾úÅjÜÖ-h®ˆ_í§èâdÄ_Ίl·ÀÇÝ›°î+×`É÷ÄÆÄP“Q(Ë’˜$#èƒb²Ò³Î‰ñGe-f“‘r¡Øþ’øã·@a¸q1qöjì êo^ÿ°ž FõCÚ1Ó_ÕWɨc3Ëi6óòø!;¾Owùå-LP6»…Qìá–æ]ZÕ?bäÉeçcÆæq9cv|Ä =½¬ 8ÑssÁÉëe&ßð–~¼Îƒ­IÈœDosµÔËÌM9* ‘uü¯üò?F¹Ú.˜ Wf­®¨.) ÃH†²š¤æ;´ÑÀÔJݸC~•æj‰^˨c*~ì¦ßY!—îÉÄ^"\eþuLZ'EdêZ:Ȫ +©ëSVMæ7(hQÚÝZ2†;ÜkæÙ˽öBËçÌËâ²¥*Ý©>{[ªo"®²Ç²Ê†‹X) ó“:ËßHÙ§Ç矯ò§¤8fO˜IÉÊŸF»'î…,ZÊBVè¹BÔ1]³…yEz”ÎäcH'5ø\¤M7²†4êõÕÊ4Û"2Ð8Ðàê—ç´¾/êÖ¶×)^“»JX;t{?NS T bú[Þ´¦–Ú*0¡g)V-ã,…ªE̳ïÇûÃVµ¾"i¸ç«E-¨±ü™‡«ŽÀ©G#H_¥Œ*>¹C•ÉŽVr&™£Ü:Õ“2çIè²7PH¤kaHDÌ)&ƒ6ðÑÞNÔ$Ê<ÿÑk«®Ô~C€|ëR 0Jõ§6Ó×ùî˜UF·IÅ2bb¶êKgåÄ:œVÕ¼!¥e­ÂÞ?<¥Ã<=k‹ääü5àµÐÇ©—üŒ?]% \»Ù9»€â­0-Ãì#NK2ƒàXd¬-Y ª1Y@·5Y}yPiYâ/Òžœìã Ê^¦î-‘1ª ëwC€›ú(VµsDAa*“ã²å¢ú4Äà+ViI¢Îå”Ú!RBv A¶5Y EÔ¡Kæéܱ!~¡4iž, í9f­/†+.›zî¨l³â(þcD\Mû@ãõq?ðКó("/K<›ÒßÇîB7†ÁŠ‚Ðžà"8ÛáaÎ &¬dF(éX †æ>” iÁSÆ{/BöÔ¸²ˆ˜ptœÇÓnÇ]KîHê<ØcËÏ ªÉWõíqíÖ€ò‰‰Pßmš?¦fá{0ª ¾d¹_½µ>¢ÔÓ Ð[ÄÇÒNÙÎï3uÓ¨¢š|m¶ˆôN@Œâ“ø«V‹cœ¾wñAíÙ£NÚ[d$ŒŒ4„—ô!Ú?@8h©bh?à: #^‡kžÔ¯vÜÔéÚ.9±B堻e¯^êc¶?G•kQ®Žqøëè<YI T§Ög·¦Ú.ˆ³Zw­壣šÅOÍÅø‘Ué&«ž¬F¢ÒƒzÎg´v|—\6Vƒ¸ ¹KóGŠzß ^'Dª îÙ‹/™“ùPÜá¢Ñ‚" ¤!É] î!&àî\ÿÄ0r_å_…YßP bh~†EâÿuVâ[Í›öŽ™ôŽ'RþapÊ—]!Œ«cdê=®ÚK=ŽËìQ˜¹áu$¢9ABÅùÆÚ¡,„Ì!m4(”h·ñB/šÂ‹¥Lµ—6¿h/ƒK“ Ûr{Úê³²×ÔW}?÷üÌ éÆK§;ž—5SÒ9µ–_åásß[Ö¹»T Áø,ƒÍå/¹62E‘a93ƒYìPò!ptz±úP"’Ý.{Jw£êé$ýz„R?  .Qòœ~ÂÚšÖåc³á‡Åu(ÉÔ¹=„טÎkE‚ͽŠo@Q­»ân@¾¨?Kí¾ÞνnDÕy×èÜPÀµ7CºÝ %PóbP 9.tiÔ’Ýú‡Ý>î‰Ãe^0–¦ÐðÅÖC̶Ôéhâ/,üc•õN·(¡@æqÕq_ÙFSj½EûÃ:Õé–ÇÔ¿ µžD/Yí·i‘>eÖPa£ ¨&Aà£Æ¹"Âi© w蚊Àv>[© å‚4çl$aÔÙÀˆ+jüÜÊb yâì!‹~®üã _'gÔååúÚÀ.öÃ_¢ï2í7C ÙøR Tʺ\u:Ò~|Á¯D¤œ]zJs‹‰Ú›oyìDüôÇôÃj½XNÖî¦( òHÒ:[¾4ÀC…Æï¬tÔ"h¥Ÿ;Q×шT¤uÄvoGÜ”Å1Í‹z$@JÝ;„ÓQõów惬ÌÄÚW?øõ³c‹63… ã„üñ³(:ð&ÚY¨²þn#Z8ømGSÖ${LO;¶'“7Ò+ÚPyŠ¡ŸMš¢>áé$.gEб£Ë:¯–v'¼浜àÆóveÚžŽvnƒˆ"Ã{omu,Þ`§## 2Ôå§ñ€ lÌè>]%>~Ò‡Ëÿ"w(t%P#æÖÒ9ÁÁý¼vÌcõ!»®éu¥ÑÀQ°—0<ö2&ÇEk=î X)±ˆ.?dÚ1]hìt×FÏWŒç˜ÎS÷¦ Az¿04ôüÕ ¬˜þÂ!ïYcƒ =HÀA£…u] ['µ@nJ úª 0ABððTÈsWF‘6»²Èà™'‹ßèïæÂ¡¿íÍ¡Á7LI¦P1:`&~Ÿ¶@Ò—™0a€ñ‘$5.…€·ä84êz¡Å§ÂB-_‚µaÉçÁ*SÌ­Ô ™ VÚǶ Æ2T©(¡fälxœÃßl5¤´eʸ’ ³BÝÆ…fL¹Ö`ïU?Ù¶ )‡sùåOašÝº&0›”!1ü6;Ìô.»!êçÏÓpJB¨ºˆ£|ð ¤øçh%àŒ>Pîò çΈ—J‹ˆ:]¤YÌè:¨@hÀ¹£¬œ58h –&ŒRƒ}$ê/ßUŸƒ¼y9VBâèy½’S^¿ãëà*{#Á3^ºu—l8ZtRÕ: 7š3‡éH13‘ŽDMD:Ðó˜t €ÉÎwÙS¶1'.!®Ç;ì(ÿ†89‹§ø3é. ÒÚ¨åü¼ùa•C/Ž/L9¿ZÓÍ—u•n §.|n·y§ÂCþ)ØÍî]ÑÀèæ2#[ZyÔªsRîÓœ¯Clk¥¡ƒÐC¯çƒXx§Õ8£TN<ò°b'ÔSïF|Iæ@6l¸r…š•»B†èR½°÷Sol‰Oy*ÀwÙÁU¹6òYÙ~Õú Ïäñ…0#pc1÷—§G†n›wÀ˜EÄ g%†ïŒ¬§ì²´5aØfŸOOq21Šñeý\•ßÒÏ;蘈W9ÁÇ):F„×J“÷EzN÷ÀÞäAú˜Ôã§R‰B’¤n³.¼ ˆnßuE¬¨^˾ ï7™2G»9×¾MT®´?5ȪŒˆ5fǰW)ò‰{¾8½Œl§¨ø–B©(Ÿ@¨ ÅÞ<¹Ä¶ Û åB ’¼’djÊ&×eærñÕÆ§WK|ða»I…Ö •N Ãþ¿Í+} u'·:è¾­Û9Èmö(óÊ/àɽĽªåO–‰é·߉Ãñ9¦JL¤éÒ:Z}̰fô8 ;"ejãpÌÁf[ô·ƒ¤m ö²ðƒ¤Rÿ\½^Á1Ü}u컑vX ü‚ý´ÅÅ f8„º­Æ*±pí½Ì•¨î× pÃAÇ42©HcɽpLwUñu8Ë{JÉ•àT²'ÈmayœÚÛ•ÅÓº”ÝaTUéËë›A.î¿Ûx ÕÅ­nRzÃÄi!EÉ9çäâY=Ôw Ã*çž6guž“wñc‘߀Ò9Ö˜¨Å˜Ž÷†ŸŒ7ÒÐ}ͼ HÄTÖ` K{Ûc›õ‚°Š3UÒê¬áV¤¦.óJK²?ì†&àSxMÈŒŠ¨ÌȪ»Äº$/œÂ3K›ªë†ðF«HVb*²M«md=/݆#BA/Eˆ©´ôäFaÅܼ+Œ‘÷°^—LÌÆ—B,û€ŠÍ1%h¨\h¥2Îm¿ÈVt¨~·Ñß 3DQÝ’¿¾Ù t‡w€«´Î7ø I€?Àæ°#ò”?éQLP°¬ÀKϬó'h½É"k"-{]̾®p»»$¨€ˆ\Ë@¿ƒ.!Iiï³*Œz¹ ·¢ó ì–œ%»#Å9Tãå MÙI|Ëåà÷B”ö“ÕÔ«¾ÞFö[ì;Õ‘i^Œ^î!蜶CÜÏ› ÄÉÇ©¿XÜÁVÉÛ9ú~ºL®?àáð:s£^ûÜ#÷„;k¸wÅy÷ƒ=q ÛÅêÝ î…F,(wRã•§?£Žb4F½Ä^¶µ˜1ëÙ]•x±8.5 \ÎîèùY‡N­ô‡DŸ1*ÛðR£$ìÜaNÚTô¸¦,ê¸BÏÂ/7{péÛ‘£ çbƒËMÚÃé3ù°…æaÅREo<+óQ錿æÑÈa2î|uˆ1ƒS޽¯Ûˆ‹ØÒÓ„þ¥? GîñÇBú"ã?ÚÞp´kWåà݉¯õïŽ&7þØ?1v=•Ð>úJp9¬öoÌ[ƒaVsŸRŒùêW ’®ˆ—yQ ìGEQ ‘oóvrºFWÑ6í;‡·‡7 ‡· w±FÝTœôi+žˆøÆâ‰`¿;‹‹ˆ|O¹Ô‰qíÍby# Ã[›Ã›ÃÛšû¿kjvj‡´4WB|Cs%Ä·3WBäã×JNójhT#s8Y÷“ƒ&ŽCpúaS„ûЩÓ¿h+Åœ»DŠDÍE‹¿8dJ³ÁKfÌÊ"ÍÌ(Þ„QÊÝãÕÿƒzÕÀÀ A’B-â0š;BÔæÝ÷ѱXº£˜2PÚ^?Î'¬—¾#xöÛçQÄ}v‰ÿg$¾MVl<-/"¾Mu—Ùãc¾É£ÊáÇñ0fQ=×c–NÔ˜‹‰¼³*øò"ã,RäSw¡TY½}€ã©&ž ãÓxŠj˜¶9£‹›·Q˜·: +Æ®`3w«%~úâ±B•bObx#ǹs¢F\‹|h…x³‹s{É¿þñËÿ\ÄÐ…ì€Â0s`V¬•#ýnʯªý¼“ ü\Ë—‡¼A ßÎ…¼)¢îï txdèÕEݺ©vóËÂÊ÷WxÈ»Ñrtë= íïæÈ2}¥Ë”E%nèÀxþAYÿË€Çhˆüº-Ê‹pŽòã\=ƒ"¯i ~ˆç ¸•_Ò¥3ÃЭED˜úDä;ÜÈp.OD|A\"Ö‹I1:qìxÁ&ë“JC áØ+À$G‚ëO4 .Ú½h@Þp/¿*æ÷B ðôw Òx§ÿÞý¬î­£†h LÝp'Îøà›$n”r,ÃƽJëL?wšPÁ!ÏR&g™Õ§ÝÑð%C»JWdq$8ó12xœÖs•7Ïú¨kEŠÐÕ?gžÑˆ‘ô©E庭a=¥r,äSrQyg‰‹ s RÅ+¦‰_“»ò3¥T¸ìy‘V/züiÛ·ãä b)— 7¦Ÿ‡6t×<#sãÊ:7½±7ß¿! Ÿ®T¨“7éPN4äõ>¥ç©ŒúàNØ]S}ù=ÄÑI¶É÷é®#·Ôæ{”ˆÁ2D!Y©Wd•å.K Aü„Šú¸+®~í49v“<æ$Y½™j²¬Ri–¡*“·U–TžÄ'‘‚Iy½+Sé æ:L Ëa ›•ÂÞL¬®â«200“Ô¨”´Ì_ÛãÜc³z.+™îU¨mï„­Aê:ßÛÍG~`²͇-©>¦ûƒ—õ5†ÏHCf•=åõ1«Ä¬£?ðœØC›5FÐå|Këùi·{ X»ãÀ(7nÆ«Q½Ésî ×’ÆÏ"Õ¹sëåë6ÆÒ¦ÁY>7íõ&Ô`±Ár –¦Œ› ºS¯ààYEàõ$µ^Žæ«Ñx,æóÅ|F-§£ÉÃý|¼¸½MÖëé„ɈÂßMGëÑÕlª¨aÂjºT×)%F+‡»¦U!ʸ¶mQ UÖZî÷ù–/÷ ÛœNtçQ“$‚,;ÀéXŽ›Ô}DQãô˜îJrÃãÜfÇTŒ¥ék{lM?‹™V†³×UZÔz95SáT¯D%8^ÌÝÄ eÍëå …ú5Ê럳æ3ÂË뱬ç-ZVà›X6¤yùš‰¨âÜ™ØBUvH«LêDâö%¤5 ´ZU¤È¾m’ ½Óèí¤Z©åÊ­ÊÝîsjylµµÕY>°¶·„4‹ÔµJ2Ø+ŠÐt ×”{ï©·kRƒ€‡=Tå&ÛÊ»_j á¾øR”ß c^jSüñTuc\îNû"&Aš‘Ä…)CëLGØÅ3/¥Uó°'Ýï£ÀŒ’ߨD3RÒɰ‘Œ4|Fò²ü¶Îö‡²J«¶ï‹ ô*³ö% $?µóòxWg§mÉÀ†ÍÓ ìcáYI±ax.ëâ¨vÀÇi½–5-Ú¿P·´Æ2à«ì([ =/GÁ:·…O²Ç4Ð B¢Tí^-«ªÞõ2——ì÷Ù67\x3tÔQ…:•Ü.gôRcôQÇhn.Æòí¼,‚b%NNÒ88å_*\‰)Àæ9˜# HŠmö]ù«Á|¼;Éù0]×=\¾sÇÅ.ŽÏYò ÓVi×#mJ¶m¿B´µ„IÊ*“;S ÒVüg"Ý«Ié8=ÕYm¨Qh‘<¥(·¤0ÄÔ! "¹G•ðI&=Ë+¿Ä4£ÌêÛô»TãùD¹nv§m&—VCQÉ•P­õUÅǯs}nŽAKºŒ¢é°1´oE| ¿ñÉûVD§­>–b0Ucñ½Ÿ¢†V¢šÑncé·ù÷l;$ÞŽ8,ÞûÃaX~;bt¼§ƒœ´×£ù*ùŸ7SùŽõ,ûšíä1æµè ±yƒµjöl"¸;ÁR#èŸùñy´Ýjý:ˆ=©ÊCÝ8}Î-Ùv!8)äç۴ȧví,R€š.ö{ñ)茥ó„´‡T(Åhº*üñ«jíò´V«SLRñ5 Ž.: é¦_Évû¶J÷{ù4=—Te¢þ³íêôùß'1wd·$ù£/¸Q±uTÄ^)Áâ;1ù£Z[צm›G!DšNÜ´L¿*}ZÀ\bR™èÛèêzkq:á¦ÌÙ…Ö-‹Å ¯²—²Ø¶+1Ly+Nµ&MyPÚ‹gù¨€\c¹N7ùN|bŠ˜å_2=7ïän%›¶ÏE:£ ôV´éýi]{CÆi—:tļ¶x~ØeUKÐ[KZ÷1=«à‡¬Ð+”õh#÷ÂX[Î({ÙdóûÕ¾ pĦAë“Ø¾ݔçÙVÛÖÑ´Æ/9Ö5>1vmN•ÜÝ|a_Y]e’š•§ÁÖLÇhÌtü3lCÆS¦c´dôp]VQ5½’vþÖXçdÒ:##‘ÇLi•×I5ØÓïyÍÖq&1Ý?O©VÈ[.ûÓÚÚVó n· Ìï ~¯QØQpõäÔM³¹k?ò$Ҭܤ;ùêá]35 Åbrjè’„­«S±I½ûÒÍ=G¾Î¥^ÀƒíÅ)"½mà¡¢„R¹†#޲.…9K£šëÉÉÇν/×Ä€÷ßl²sjƒú›c^-Ù@¹J¬¬ªˆýŠl…SGè'ÞéÊîY4÷ö›v㇈¸ß•§ÊßúSAÂ<©6¸Ê6†ëV(”º— ‡¶báPuÈÇJ‹ýšîNÙ⑾2Ñ·pÝzPçSÈ« !ßr;}±oÙ|ô ½Ï®N«zï_Q·®ØÀǯ´\µ›Šžùé1øŸÓ¾·JžñðÒùiæˆ2Å þßíç!wyZA¥¦p’®…Úª?©0å )˜^¸lä'Âæ¿Ðñ„E—>qZZ Ôéô3цïʧ¼½§<áBèOéÈ/,¡/¢ˆþ‘ã-Š\}ù˜ BL$š‹¼úûk·¥ýNÕÑÐÝ®©Z³9«³R]¤¥oÈÙ~½Qh‰¯=~)¥?uIßµ#W\ä^Øå¢¨à΋©Œø¸­ˆ )ºQ†Å„½CAÜYÛ5ûàbrVÉ!®îø.W q;Í ¾b :µ|‡¼¹JÒŽVÝìÀn“ÎеYÌ`)ÉM9ƒÅ$÷@W(½ñ5<~Xèá,Ä6«7Uî:Z€UöïS^c€…R¦ Ù<—ù&ó6 tÆ£éÿ®èRÅæƒÓíVíGÙ ÕÇ©‹üÝ´¡Á³ïÙæä®K °Š ûKðJo×@ŒÜªï¢jé(ëÎÍQ/B{9 ”HmûËHº>dúËHÂBLOGZ†ëçˆ#ÃpO5<%ÊùP_ Ê]ƒÖ:LúÈÀ*IW< ˜v}b@]$}þ$Œ¬¬yYŸ.”ºyÚ@š1Èö®k¢×K“0´ñ½tF&ÚuF§½/Ý„êŒGb Œ  ÕöÓdy«=ƒËH3Af°•S(S{=2ÒÛx…Z1[¨!%jzx’ åÌi mXëö<;µò´§³ KÕ}‘KgäauëŒì¢n©±\³|ozb›Þ‚®§ëñ»‡ëÅòÏÑrB –Ó÷ÓåjJ îçÌÎAÄúÃÝ´äa1Ÿ}ÀQ«ñr1›=$óÕt¾JÖÉ{8NK#Ç‹ùø~©½%¡Q7 û»‰ö‚ÒÏu¹;Ý}0ð(ÆYZ;ÞŒzÀç챬²ë¼Â!¹¿“¾Ú#Dw½d‚<ÏK} ¾ë»”aÀc^´'§…‘ •7¸|xN$<9w 0­² 3”Ц€)+Î &J=ƒ‹æà"²âfÚ¨±eipÏ®˜[PM¶Fšz!¥y›ã{õÃ$ÁsQ ™8ųÌ)߀$“ªó¨KUM/2’tãÄ¢/%ª»Ø!²X“—W 818ÛRQô³Rù™…@ªQÊuvÜ òEÓ,`c ‚@‹]Ú1¾`š¤·ÃÂÀîŽËan•ñitS¥Øø9rèC°€ûk0ÈOM€ÅÛChdÞ9rÂ{z ƒR<Üm<œJ)ŒxÅ[¬`í£uà â°EúÞ€CPß!°Ïx꼋ªuEîœÙâ«H»ÓÅçÈ/®!Ó"=ÉëÃ.}ilH&i–~Îvg$ñÌ6·ã˜‰íös‡Dx'Œð¼ÖVx0¾Õ&ݱÖ{t”¨ÎñZ<[ÌOG1ÕÚTÍ#-ð,ÄòDSg«¬—!ñÉ‘‰ï.=¡ÍM½l÷"O=¦¾ˆÔöË`9^qÂR{·ÚpþTx¹  -Gõ‰ùHáµíÚŒù(hK’—®ú·]š5ÿ[­õ&°'B? ž4ß4²=ÈiAŵ‰…ÍŠmYÉ—¨1„\À ë \(ƒ^弈—"ÚÆ´ªtñØZß…ÍE!uœ•¨îûï„€¶žÂ °§Õn¼H´psRÍ5ÐC4F¶vë¹`êU°á1/®YLcù!¼ï0cÞ2µ©rw”Øú¶ÁͲ€¥¢l„œÜ[{Ò^°|¶Ä<=g|¸{ºxb4·nzŒ‚õœ×Ún´zâjm÷Yá‰k8Y¡jiíÅYÁÍ ‰Þs²r ß5² z¾cmòØáœ;CM-ˆ= ¬'¡úŽFýÝ èÙ H CæÉ¤¾k»jÑbxk–NG£ÈÞ#¹œè‘½ÅÀ˜¨ûS]7'ñMWÿH‚do¿ !êןH ¼~Öwy’kgË?äíà•2x]ÌÅëÎ?¡0ºÿ_S½ãO”¸¡ÖR‰aO‘Éï÷”[U@¡µ:X‘t3–&줫$ÇX£€W$¼¹¨à/!øê¢Ù( ¾ón@³Ï OðCDxM°•ÑØqÍÏð~¢A­m*È„ŠŸs ¸*—þ6”:ƒû •'o[U>›k‚¼³¹þ+ É)B“¬O Ò÷±çEš¹ãï” æf Žÿ)î•û­pâ`–ôfÙ7ÅÒï×y¶Û†aËò[M!Êö]Gg£×B©¯¡:/‚7…¼+ÓÐã†0Ü?¬`átåkwŠŽÀ¾aÕŸyd÷JAÓþ攇£ZùxüˆcÉ=k ìY[ «ÉÐ8ÕfˆÕ «!zŒ£µ›BÈCêGQhŸµ+Óï7`éCãÈ‹:ŸÆ\ýq²$³‹{‰Q¡ˆ—3ìÆiÏ–ZM´ynËÂ}¹¡ úIß‚^Hݹõ’P·òà0À/L¤âXL—1 ËrÓÌ¥€JQF]3R¤EYƒ!uVåé®ñÐrŸL@P_» TÃÈ/,¬î×ÀFÚG ïÛÄ0²ŸÒu Ý‹dàY1H{I¥ßÆÚÒl±BŠhšÀn!íÜÙm&òJiÀU²ö¾­“ù‡dî_ÝŽf3(@|›¾.áo!øõl1ò¿.§£™÷q²¸·/véÏóûÛé2ûðé8¹ÄŒßüÔ½-Áï³Åü-6­ýÔ¬“[øãj=º½Je>Z~€’ƒ„4 BBç÷3?Ëõ; >nFïG‹«›éØ/þI²õ¬ÖË{àóh¹ù‰¹š-®üÒ‡>.§×Þ7c²e´æ£˜mü<*Šò˜:[V›va¦+7ÌŸB¹‡\†|öA $æ\ ÛK“&¶Ã{¿$šÈGÁŽeõª £óÎ’`¸äˆ`å…P3b~%Ìxòl4{?z;gÊûŸÉüm<1™ßݯn§ëw‹ÉÃjúövÚé¡)ªŽ^IÖ+ÉzÅbÅGã{¯Š!W ¢38zoy©Š¥#„©™ÜÄŒöœÖÏöÆWY/Á×åîkX9°^Lo Õj¶±Ûuõ€™éAʘزdµÁMÝóË‚¸z±|9gв<Êÿ9¿uX¬ø<ŸMW=±Bš×u±~xÍh¬âA÷—Wî‡È®’r|ÎëW¿ ã~Ξrí,{?+¶g°«l—}M £‹ “£×®Žg¤¤‘ ªù"BT[9WˆêRÄXã1Èm_z‹è0ÆÜ;6O»²ˆ—˜Eôúoã6Ö l\W LÎðŽ#ù/öb’Á2¯:Ý… )ÓFƒ#ãlÁÑ=FÆÅFÂøHƒ#?O$mÄÈø‹ËµŠ´mpX‘œm„äò}µ"Ý­ÚæŸ ÕúÚå@²¾H9Üß´( >;óÍEiwȧN¡E'T–ОÆòûès}”Í]è1¶£ÄWQ’dÄZ˜’gUJÃàIøö‹Nñz1vT#‡b)Bt`ÈÈ€†ÕP¥GMô²èÃ*ù8}Hæãå_xjÇþÌ1 õ®N©¯V @µñ)MIšû*NÖÄÀBªR½Zâ¹[¡bBCÓe……º@´¸øYD ò‰‰Z¨$²+ÓcV+ãWZлò†?‡Š4ªÛdü(’ØùK+ëïŒ,uÚÎxî‹ú —S_RÛí“à.ÌŽ.Ø5Í“ýa÷—G*ŒåŸé¯Ž×;jfÛƒÁ­q†ß°7"G£cȲûiSeÚ€ëBd!½¹,Moè09+êS%ÉWBÊã ?o>Ý£ÌèÆÏÙæËR0‡Dߙ夺„Ì~üш-pÀ õŸ„® ÏKÄ.+žÌóK0ê«×oÂjªw¿y¬†~É^ˆPKÝ2a†Œ:šØEDÍmàì…½Ú‘xÛþ6-4ÅרºΜ© ‚âv •Âcm„ØÈÉb>ÅC݃ò„µíPÚõæÇ4KÀ¢ÜíÊo¹òCGÀ¤Òýšæê^°zÑ8ž©/ý‘H®éö4iŽLXJÔ‚Ç òS2Pô,/²s“gɸXÊV¢²3!ñÜÔyr.–µZõ2¸ô(àñÿ,«í¹¹³d\&gy}Už¤ï<óš;€Ó+†D'Ò«‚!ÙU¶É¶ÁîÚ/! º©±ÐŠÅBªZ1ìPJ^1_J‘m)Ë 3~€(§wÅña›§›*?æ›\>åz]V{l¼d€f×Ðæ¹¬³²{òÍÿ©xbáJnºXãÅìa¼¸·ÞÜ* Ö‹» ŒêK÷MÔз´Ú2ªß㬠—3aÒUºùSKbEµL¿‰)á!ÖØ—îŽ U^û©#]ïÒ§šu_×_‰$9κ=€EŽèAHü kÜ-í`>‚ea4pWßÇA›íà™tD#ûÀ –öµ|°åƒ}*hïGùU/“ê9=Ÿç§ýgÕ¿Åg[¼×Ö©½Þ:Ò?pÔ*y;G§ÿº ÌÕšàn¡_lIæ×ɲ¸.!ë.ˆæ!(2×39riP•µ`Žp1³ÄÄKé©ñ '½ž¡õ+µ'z?‚N¦×£ûÙzy?›Â]L𙪃"f©6g¤M€î–Ém+Õ[MÇ‹ù ]O—ë L&b"’Œ»«¼vè|ñ0²oõ„d1AãÑ|1—"Øka¾0`m¯·ÙfC6éæèœ"DT%P—"`úÏ{$ïo—ÓѲ³”†ïôÛ ²`9}^X³¦­û7o#èU°\AÁ"¢ˆÇc„% ÙI2ɦNÁocúÚ“7Éd16sPµ«+ÀÆDgÞYôVDPΪé^XI¬x;£ i¡]\®+—)ÝæØéò€.tÀ÷Bí,¤6q— ]àÕl1þcõ.¹fÀÂÒ’ùdú¯°4c¦ív´úƒD}õZ]H^lå|–ÆÔÍ'%ë? Q^0êŠû´úB¦ò¿ËìI4:urC¹@LÄÿ¼Y‡Cü¼+7_ÖåIP¶þÅ3u¯ËÒBe’i[uts‘+ÉU§.ONø¶¡t<µÏ÷NcQ šº·èU­•'O8ªjœtoÕ\¨™Øè ü(ÛÅ•l!Í‹'ˆš’³¶šêÁ5ÕI5åÀÂÒH5åÀ˜iCÔTBÕTÁÕTA!†Ðd=ŠRSj̃ 5BBjjœˆÿÁš§'2ÔTŽQS‹RS=ÌTSc¥¦ ¡¦zT«¦ô®$Ž®BÐmAŠ­ÞèôÐê­Ç9 +P&:窷¤8²µ[‡ (·Gê6”Ej6ÅK¢×:ªÖ:®Õz¡±:ªù:¥Ò\g—ƒ(¡Ð@†Zê°1Z©'QJ©C™: êO=0J%õ4B#u ŽŠ1Á¶º “Mk‹ætÿ@ÝÙ蘫*”CkEyÅÜÏBiþõL,7€}$ŸG`¥ì÷îÁkïÒ¦Òq_u÷á–Jz›=ƤØrÁÞ4*L4Zé¦ú5ص°rvOyàèZ~kކƒËø3®††/I`.Ž!Ä\7}È@fÀСÌÀàƒ™BG*S1ä0Ñ|ÓÓŽÑùÈÁχ­˜81®‚XèÖ&ÐmÀñÀL V‰ø<¬LÆ l c†a“F ÄΊ9ŽŒM"10΀ìÀÀµ+\ŠÌã  GyèŒóÁjãƒpöXßgŽ¥\ xH»ÐÉôêþíêÝâÏÅûér6º›%· ‹³^ŽÆS–péU—lRÀ–ÉI*=z¸@NÑ㇠äH$G‡!ˆC TÖž=Š£FG>.¼÷Ž1å*Ðöµ(—Å׬ÚéÝwÝʧ±w¸Á#oRñ%?¾¼†U®‰ŒÑþ&TÿfÅú?´µO‘±‘áÄ*V›#†ÇYyrðáqÃS«O)¼þd£<ˆ?›£ÕØàá¢ïvi®¦ˆ!Y5IΈ6 ÿØè_'«ÁSÒÿw|Ü?8nÀäþ«<˜…ÈÑs2]Ž®“él‚„˜Ž–$àv1_¿#ÒŸ: x·¸_>,®&£¿r¿Ð‰Jæ÷HõÁ•€1¾2p"92UN§ppÁ"5å%ó‡p +$Gr ‹Ý>ÜÝ+#\]t=Iúsº¦¨/ìúÞ6±Œ é\«ãé$¹¿ÅÚÈ»ÅrU’>ª…„‚¶€Ùq9ƒ¤g9£¹)@žÊ¹àÕ,æîé@L¤€žpéP,Iè.=œ2Š=dÓÇV·|£µ žüžîa%Úb'gÒ/Pˆò—|ûä¼Y’aÙrd\ oÃódÞ&³ØfÁ?¯Dí’8“~r”?šT k?b<Ä,5y=ËŠ\Ý–ÄÔ+v™èo®ÖŠä‡.#ñ[ïŠFßu¢‡¢ÚPP~BÇIk-óæeÓá’âp:jã€Ô5ÒFÏÑ¢½L°¸HS; < €oÓïùþ´¿–Þ]Dñi[‹ËJŠcö”U\’qD¥Y‘Qõý6u:nÜèP{=7šïtÝÁüañŸ>?š[úüãÇ]Äݡ͞ÔÎè~ÿøé#¥5Ž¥g1D)µ€‹¸0 (Àµ¤è]ˆðŸ¬*UÉ‘ÝT±U+A†;m Yu›ïvœtÚN+cÍ~ ?™yñ(íß— pžâS’~›¤8Õ«ü ŸuvëûÍtZÿf¤ò¸ÇQöÂä<¦òU8nQdý´<ˆeÏ‚ì 3çæ`,Á):k "p¦_ô> .±‚Yˆž0ÄîÁ€Z!;Ú,JéR\£Å¹$†Òdgb5¤6­,Þ[Wó1yI£'†I¢_ •Yº»L)ß¶Ú†™…ÛF# ¬¡‡¦ôÎÑÊÌïôÂGo|—Üúc;Vr𜩿Ã2¬ëŸ=1Öøveb¼3fòTù2Á~‡fýÍ$v]zh¹P}z¨Ì¾S3söj&_v롉õú53ζcóáªg3á}׃›XíÜ6°;Ôíè_þÛ}ðäj&׌áÀÆj!¢7îã³Óßë裔Öà y6ûá6™?,§wâí¯¿ÀA˜Ôè`½èëM´ûìî2y  åZ.áQè‚b†W<½þèN;˜4,´qÛ‹¸…P2þv‡cê¿äµäËbW¾¹Ýu,'Û&¼+Ÿ~ýåõ‹¥’áà¥+=O¡îŠ‘|Câ’ŸËÓn»”‰»?¸×™{XÜ‹kê•¶»4§Qô(õö<Ýgp°çá¡zü¶…Ð}§$8Œ"²–QÈ|ÚÈGù †Þ#·ð+ç6ö;ãÄÄë±6‰zëÄC"ïœx8õ!}ØÕVÚȼ×FâH`\»oÖÈÆ@lÆì7Ùû8@%Ò¶~ˆþcö…ÌÍôX6/ã—<ÚíV£–Þ‰w”·VÈÊ´€˜÷ $ýÓg^çµ ÏùÓóŸ©|+Ý8 ?0î6­¾ ¨]ù#¬…‘²<ƒÇ õ¯£[Á_²÷>½½³_رB'ÓÙt= áÒÌ»Ÿß¯ˆôÜm{·‚óÉÆp auo‹ÁÔÔGL޶®Ÿ~  .xÑá£E¿& Æ¤™Êx^O÷¹ƒ§Z˜˜µ˜Êg®«»®«é³ê×î+Ý. ™êíh`•Éa†ªÝ*Û—_éLÖN±‘ØvëÚU@ò­ÑØmÎÕr:úþ,ZÑ!£ÞŸk"ûÎ[Žv øŒ£ ±_ptœg]¦÷n£ ø"^ï5âÈ {”‘€0øF„¾½hãä/üÅE }È;‹Òy]ÑF ÃŒÂ_«¸Íª§lÜúÀ'­Úl®Õ¤N¿ê¶ Œ|j0„‘îdj2¢cz<ÕÊýºJÖ£årôÁõ…ãÂ>¬§w‹?í7"L@ óøÃJ·ìÃln!íó#s{š`Â;Ô(Uš³¶_[f²’§¾£Ö¿= #¢ÿÌÏórúý˜µ¯]aѾÓI$‹V½(qòžQ÷QÉ1ÛŽÃ’ØïŒDVŸAŒ¬½~Ñil¾¶¨ëô‰ãHÅFªëˆÞè '–5(ÕcX ­žNòþ”>üE÷éwý²9¾2wòá)·ùcžU4j+ìÒ[Qóˆ«qX¤Ð~•S¼1gim*kãPÊÃ˨Ø^çßÿy*tí§õ%òAe fNœÆ)4ÕÙË·²Ú nÓ$¡–þ—-¡„"2Á[bþÂl]"öd@ôÀk¯†Ö¤‰ÍÇk³b0·¨› Oª&[žÏ)6 Y3u•ç—æOé9lHD?ÞÉåIÁòâÅ_Ü„GݶšÖ›‡Ùf¨¬ûæ´¶³iqÊ?òéܹdÉåêÕD½7Åò5޳ò£}G~>=ò€[ùzj™‡W/™:D ¯ê‘©)çÇhÅ‹‹]zÓ™z ½ÆÞS˜5öÓd1Ÿ"AÔc„Œñ¡¦$4€ïFó·÷³‡«Ñ K_ƒð¼Á›ÑíâaFÈP€÷!À:˜yË9^AÄ:ˆ˜Sˆúˆ´ñŸÊoEÛr„êTÂÞͨp¢Óiµ»]¡Iðߢ6)ÉÊ݃\õ÷ÞÓ6Qëéò6™»7 Ä=u ÒÑ@ü¥3N‹²È…â%%u(Rئ6DqÄ‚÷úÒÆÄÔ14´‹m#iÕ¼NŒEJ´ôM+ÏLg,Ý™IÕ÷CÆåþ³ø …!ó*ÁÜøÇ(*Ð'gwéI/æˆÊoÙ¿:VšxDüÆiÚ: l¿”Z¶Þ¸@ô”Àê æŒ|4T¼Õ<æß»nsà‰SYÛ‹]¨1×SwkŒŸð{ò,2~Ú­Ë›t_r]Q[&;\—ï”ø¢žA1¡îýy =oêÖÀ­6~"ÞÆ¬3Æ£ð(Qo(û?éá®ÅÁ sK®0ZÀö~¿çëÖBu×úiueÄÎïo¯¦ËÕúƒílÁ´n hT㉭Ɖ|Õû:Ó¸ö>×}m¿4dÄXn]žÄò ˜~·/qR"™Heñ5Ñ/ŠÝ ¹w”Š? ]… ‰f¢C÷ ,pðþŽvîdY@̲0Ak×b0—Z-N³7 ÇçÇ,4BQÝ HÞòœEõW­ÁÚ:i€çfW@{©ô±‹.~¥ \Tuåž—ª–_^2H ìÀ±Á`Ž}I?@½°81ÑèßçU™#ãB×\o9/i® ¥mµ‘†óÇ|s^ò9—H!²Caaòú­a¹K¡6òÎ1>(tÀg5æw„%ƒµŸÀ~ñ- +Š!—›åhÕÎGËrR‚HÇ!‡ã¢!EEäµ8ªÔ“7py/NG»ÀÝY–Ѝ;¯f¬âwßÌhtVUe埑pPÜ…3‡¦üívòÁã¬V %w l¤÷j¬¬²å­·ÚxçÆ‘Ã3lmR›mè‚‹‡ ƒUhƒj+N2Oíš6Š»ÝbŒz¥ÑÛI88Áò È¾ynÒÜ´=‰Â2ãÀÑ|·_ p‘QEÉ.ß–ÓÕt†ÞÏ©ÐZè–âéøŒ6Tqþ”… ±ëiôÜ$´0g‰L·Ûu©aèºÞǼ‚¶`uÕUE‚N Iª!ql'¤kµC±5šÁ‘3-ŽÇs—Ô'4’¸jZ¤§ò X^¯Ù&Ow2i¯ÇDòãTYÕø¯ ïÊ­kñŸ Ë6¯¶+q3~R¸C2Ô¡U½óç8G/ªQò²â"9‘r¢3#I—ÏÏÃýêRY’¢†äJòÎÊX¿JýêWRó#”@¢-lu*à>Nò¢÷“’*:åó*{Ú»Ø C3vOÒ‚Ð»ÑøÑÛi·œ^'ÿ Â>&w ócŒ¬¸ÂX6ÒyÈœ€‚ÏyÀ1l·cY'ôaá÷™¼ ÅδJˆ'[7ÄD«ÄËÖñãŠhŸo›qƒEôv5g½IÅ”´êç€×ù.»THáR(}H éŠö™“šÙÀê:úZ¸•5l¨ôeDeàì!Ò7lxÅÄædà°¸<í²«´&³ºâÒ(Uaí'3>žÚ5óÑãw£¥z††Mÿu7šO˜àñb¾–ÛÔLøýüvtw7 $TÞU-?,–“©:^No×û>åvô¯äí|±]Ù;Í>R¿â)~=]®“HŽ™ ÷ò](Ya¼•¢0¼IÌ$¹¾žÊ þéb>ûÀLÑ ’š­‡ÓÕU:ODŽgk‰^%Õ,ÄÓaœYK«wÉu RíjbD:Ö‹?¦óÙtêI³ÙH÷É^\_;«>>¯¯åÆ 0774°_ÖÒD¡a{ÿ€¢’‡3å²2Cž~àžñ¿*ewñ5«’§¢¬‚ù.ÊdQm³€öÀuV1€_²—€n&óbÄ9íŽ4Vú@áàêlÉ’cISc×øTÕ¡1å˜VzÛ9ˆd®F“SÚôúÐa³ÎÄ"è6«*zp¤B¦ªG`"†%LÉÔzH‚|šq0ªÏ§|-†x¬ƒ6žÙïs÷\!;¤¾ SÌUCŸØ,6%ŠFÙ‰ÍæÆ„l!âû±†IèÓEŽPK÷E^6î?2ÐY)‰€rÓ]’UZ„¾ êΟÆÊH†È0ïúÓSÒŒ\i5£Ò£V’¿} “nÓï†*aÄ"?WËAæ}‘oÊmÆì/ÈÖ ` ›JµMéæ(€­2aKP×hî¿Êäüní›Èç•ÇgÛæð!õ!Ýd4DôÁ}^¸³D—î?çO§²ÆÎ>®CV\‰ÖüÅÞ*÷B­×ù¿_h€t¿ûT¥‡gõ‰ÆîÊoY5UIÃN‡V¨ã 4æßr;* ¦”ªãöÈ€®|˜íþw<A<7H>èKûév‡f0ј{$%‡]%@Ô]PvÍÜm‘nÄ}ÁpÜ(ùHdYâî”Vùþ VN})ýGKºK V D‹˜V» üA—¼Ø…ýFÒ”*FéË=ŠJJH€×^ì7)½ÖDÊCìtñÄÁXº6Ô]ÅÿmžÑNÈóËï\ =û̬%~¤ÍöS-êQ=zë¿^[-Ìê[t¹ ©wHÍ&ãD>×G7‹øûƒ™•˜¾‹ùm†+Ð ìé{ÑʇûîÒíVõyï×7 |¶>Í™³¨ìWÈCÀ:”u!¿ [Ðz± ÂVyX\‹)Ô2™¿ `}¯ îØÄ-šÍÓv6¨Š-`ÔØg1óªfDðXîÄœ]êÝ$ˆ}jnj[K‚Þªd@9 YȼnÿtßýÀÒíkX¤ÜBÓîºÖ‡¦Y¨pÙIØ]Ç>?TÙ&Ûòª¥÷ÀE®ÒÇ,"1ÜKýA*ÒbÀ‰¯>WÛ,‡ý¨òã­ؘ¬ØEöÍ{)Á4 dìîÍ 0xÅR•£W$t~ާBœz …¥Ä¹Êq'V±t·ô£ù®Ó}LOÙcäVãY%ÏTû½Ñý¬¨¨sòvÁˆcƒ×ÊŸ•]À Ú®aß*ܸÒÄÅZÕU®mBjü¨—}ÅÌàèŸ4ñП›5\&¼9—ŽVb*ðÐØhëé¿Ö ô»Å2ù¸˜¯G³‡õèê^ÀaðfÉ|z=µÏ±!Ð÷ò Ö86¹°õÀŒa¬×ëwDå±Ð“éÛåtÊHÇrt•ŒÛÇÆO¦ãäVèð6†Gj|{Žß-VSùVælñgþ]òö‡ps?CO`G±ˆbÁŽâ:y{¿œ2Z¥Ù†Mâî~>^ßkå¦áúï»EÐ1&SÌú6iÿv9º{Çå z›ÌfŒ¶+¡kуÖï÷R2ò111YÜ_‰¸ÃÀõ2¹c›ž8žÎV‰½i…A¯Gï–Óù»i¯œd2]¨R}3¬¹1&O—›Œd=]2GÍw‰h£ùèa6•;b+¡?ftB]NZÇDqâÐ:†û(NZÇ@·0—‡Ö1,¢8qèÉB]Ç•S$ü6.:Iâš_$¼‰#.‘ð&ޏÌG—CŠöϸ²Š„¿§KI(Ì«d.Ó?FëÑ’ØIx¿HÆS1²(«Ž¯ã¤;:D¥6QEP»œFhc—‡æhc—‡æhc—‡æhc—‡æhc—‡hc8Aõê’"ám ') ^]R$œ¥½8†´¦€zõ∃´1œ¤€zuI‘ð€6†“ôÇêû#®ï½Ì³h;-}·”koùcB'bˆbîçÉx1™Ê™íÕJ¡˜Ã²rjˤ4ÓâÕ‡w-¡Á¹óøæ9ñ¹Y½JfÉúÃÃõÿüòK,eô†^Gkóûqº\<ü™LÖïäzÒCÄ‚’œbibÔeOãÍÑz<} =%à!ý3–ÕV|PËÝ¿³BšûÊ]D³+èlzy·KðÖ^»gÅ0Ÿ,.”—@‘^ïÑ{›¯43‡×!ôsZƒÞ!l ‡ MùÔRS@{ø÷O?9›ŒxÎûÓ ^éó]~¤²µ˜éj<º›â!òÅY(øÝô_Ârzk/É´È!Ý.˜ \Φzk]^½3õêèŒå*Àî-é+ˆ®]—M Yæ[=z³èêÓœþTÆ8Å6fC[µ”O“A¬dëÌ$/³'Ñmnå9ÍL¦<ÿKøø$ù”Äàý´%Ð7JâºìÚÌkQ§ô¡9œ¹b23Õ¶–'Ü!ÞU‚5­0w媆©Ï8_—ÕJ]°¦TªlÞ®‚ê˜~‡]ÌØe`àÁ»ìè¼Íg‡ûÆìð}¾DhÈü´Ç!‡*£ÃËš âEp€|uñ…(¨G<ì YÏyE„~I‹ÿÍñàmžn*ûQ4°¡*¯&òë\ѳÁëy6ľšç„9F¦Ëô¬P§LäOä*Ž  °«w”€Á×ízÕÎÆÉ_ø; }ÈÕ:é\©³ˆíá€ð«t¶õKQTN(\÷7Fßz ‚”ƒÑžF¶ñåàä%„Ùb CoÊ\Ú:¸½åŽHì)ó/k;æÊ‡:+ôšFÖÓBŸ)rÏózÀÛ´úb ªTFŸku¥_^Ï6”×n îZª.Ýn©Sxm´Û™w0úÀ0{³ËÒ*œ6éê'Í ò˜`ˆ{F*EuîGãØ:³0¯Ø¸ÇÅ1r•í˯Ù,jæ¬2YDg¨åª®K`¨c©ç2Ä‹Ñ!*ôšúiLÅ–éÁâUrD,Ãàãs^¿ú…„lLG0Džû\ftLÙw1?fÛÛr;&( ¶Ö{<Èïp—ìSüœm¾ˆá}\îË­|$ÕOÒ,ïefºpUjGjz3úXùŸ®AQh4-5P£-,P QX­D'‡‰¢¤ïº3½xi·pYâΡeÜލ"—ÌŽM¾dUÍäŠÅùÓ>Ðqè±T!dA«4ƒ«ó[‚ÔÔIŒªVDj°U€ðY|Ÿ£ì¦ˆ–x÷1깑Å#”‚=ø*šÔ¬Éøvª…qÎŒ"^“žÄó…Uöš³ÐìuB( Õë fW}ú¬]>yy#†X1-j±[ßWðЧá¸>Öá¸"áH×ÔÌh»SÓâ[¢æuVUS™îcÜxh„"’½ÌÁFYÞ>7Ú¤vDÄØÁ5~(pœaJ:’"J‡c5âM'~ò&9¦=¹‘Ky –ëQÜæÝa3í³ÖØëp²Ã!pÝ`תwÑ&ŽÔTa,{pÁ¼ŽgÁƒ•`¢ù=ÓeÅ‘ÀÛ¥¯Ä»p¶UØ7¢>UÙ8=¤›üø‚—7KÓthöTºgÀãk5aîX‘Ο<6O/9d¦Ûw¶aÓ\«³ºCnÈ^íöC¹{!U¾_—+•2$ÛŸ¿í¥Ô¯¢µŸIAuÂ`_Oš¡í‘4–þ1‰qÔd²ûŸIŠê†vY n¢–¤¥šºÁ žli>pÕ?¥úU1¨þüU#ý9/R9§I«ÍóëOWWPÐxÌM&,±_ŒÃ®¯Y –,èæ†bÍw.#Æ…å ÚRXøj‚Cî“<¾ôÔ.|üiL†O>MÈðëO×dxò)!Ão>Ýá~IA½€’°ú´"Ã¥“@(ü1Æ‘ì.Pl“„ ½ˆL*Xt."0I¨`Ñ™ˆÀ$¡‚A3 $ƒo’ä† ¦¡Ãœ¼á E_%ÉŠ ¦?&Æk2@0¸Ï¶¿©&«+<¦ƒ'tð5œÐÁ7t𠮞²UY|j.ŸX1ˆ…„WÆ” ‰¿VQÃý» #™pïnÂH&Ü·›0’ ÷ì&Œd’a$îÕMÉdvP );ª}`B¢EÀz£ #rð+ݼ~¥ÛЯtCù•n ¿ÒUþ+]¯¿Ò{C'í ‘´oé(ŠŠ E#V¡t¼h‰¨P´@T(¿í*8V|_³MWÄ8ˆ˜×Ajtˆ› b•xo÷(ÜUÞ¯r"3§2šL–ÓÕêá*Y¯¤?§‡ûyw[ÉÄ1¼c»&às~¬Ï'1q«“â¾Î€@jß@À™Ÿ–€i±5Wïô×ß1輄˜ȸ›p™„P¸ÐFDD£Û‡»[0äÝâŽ[Há"¸H“ù=’oýŒ.šÍ"üãb>}°Èur¼ZSÁê©ë:“²û9šŸ´¾Ÿ®°°?§“9º~w¿D¯— ´­ï—XàÍh~?Z"2§WK4ðv´#íãn™Ì’ˆû9\ù7÷3˜1º{¿Bªez·žJG¡`èb¼^`aóÅ{œ8™Žñ@Ѥ{F,xw¤=ʇ)j0(¯#1]H}L÷0ä˜ï3DØZaÓ*S/d 1 Àh·£1âŸ<+à°ÿˆAÉU'éËâñÏ,ûBöÂ:Ù§;ƒÖµÄ£PäÙ)·þ0%Ìå[R£ÙìÃÊ+¹½¿}¸_I7(ëÑ퓪Vh-ž9Mç¸5BEïÊšxeF(ïžT6=tPaôôزè™ü¢€/`¹ëï‹Wj?}p1HöËÞ ³Šb™}ͪ:ëOB±õÏ –‹OÙ¨?¡‰|L›ÊŠ©àãjÖb†…õ_ j ‹Ÿn6Y-=Þ˜ÅïV$ƒ¡%aXC´D°ãê¥ØB»±d×ô*ëå:”§:ÐyÍRéPÑ{V”]ãDœtÙ{ÎO£è:pL¢e׉+ªëÀGtس'„Ž®Y#øëψ´Øõa\Ìu=¬HsŒ6d}8 낹 ÛûqÐú0"lÀú0)é‚4|}°üÖõဨ‹¬»gᢴ'áÁõa½>ìIm‹úý¥.nT±ËÆ„AËÆž 3&OFì²±'€±dáq†,ûMlà²1ØV‡/Óââ—=y–=ç/û"‡.sÎZúÙGâ³ Ë—l_©0¦®ˆIüyŠ "&¡."'¿Ã#ÒkÄ?>ªH !¹n3q±®yÜSn±2¨Ä\ŸCì%KèÙÖ}Pò¹–'Áê嘠¢Ï5‚ƒ‚/nÇldºç æ¼Ë„„΢v ®°ÁÒ~:Â]ª‹X8÷K\ü¦<¼ b{Š?íå”UüÀ¦ßÆçiÆ´0LÎ,yõ£ÄÑ<íÓït^j€‚ÔP„èÊC70ÿƒÚ2óƒM¶O¿d«V-(÷œ®7j5WgPƒõS;ÄÙl£Ht=B©îª Õõ…¶†«CÛ*C‚UA}¼nêâË··kž[Õ¯}´FQ"Àç8däÊÜHg© ¬Žûð¬óùÅXY1xƒ6; >¼Qi¾d/щºÐf¤!qèÞ¡!u‚£}6ÓÍ—X{ bíEÔ—ÙlLíÎDF;„›~P9gÈŠ 2mA¼¤“oàj¡¡6ÊôàdRäx¢d†Fk“w|ëm•=•¼+:ß͆±Û|2còñWc:|4¡ÃoFó‡_Åÿ¿¹Ÿ%âOçÑ?½[ŒßE¢Ý–|ÜüþV [ѨÙtt÷Àƒª·˜fÓù[ûI&D(.HòP‚qþM0Î} F [‚Ü·ª€’IæïG³ûi¸°Wë‡ÛÑ¿Xh.î©ûr: -hÜ…œ¶ìä*ÊÛ(ž‹4h5ÉòÑÈdFÁ¼y…ŒÃrÁæä¶žCD|åGQãÓ½z ždÛ6™zWèµû,²Oø\ž„uÚ>?l‰>šzuEßœv⫝̸G}tæ (ðþïc™s<Ÿø¸+Ëj’ÍÅ”&\B6úSþ&* Ð;~dLåæYM}Ãé ¼ƒqšÏ¢â±€’Õ˜¯‚Pê5…åæ™EûÀ\ö•]þôÜLè­Ùx$fZ¥aéµ(ŽC3µ ˆþß¶ç®Ëþ”›P «{Œ$Њö ·.{U¦ÈI÷L?˜,{ DT ,›•˜€ß·Á`C°ÚïÞrW@„œc­ËFGßcü*,ùâJ«Ômâ›hóÓþsV1JòE4³ô¨- M ©å;Ñ}ä¹û_Ã.q{¨ïнóGç&Ì)àž)7B¹W8z ÿŠCÏa^qî èd½…¼J´ß‚„¾! öMtÁ¾! öM|Á¾P°oÂåô¿åýFôè]@¿‘ô[|ý6 €~‹my¿…K4|…ÒFÊ!ý’½àê¸:\82Ø¡¸G}ò|™%©[kÓĦ0­_›Ä»'éqXWýª¬4ü"¢-'nQªåÊÛ&Ïj„ïà6LîžQêæy¥nQò<î2;žª"Û†“÷r§.û~%’moËíX>$à .{ņß-¡œçK@"ñŠIƒ”½sÝ¢bU,ô2\X¢íTYý\î úùiW¦Ûk[YA¡{¼€û{mtW¯ óïåµ!LíeÈö»¿Ö†LçëeQ+P-\NráÔ…^“ÁîI yíèhH›µŒ_AÆ'tD D½‰Žü7~wk) lÒCºÉî^xŒ(Qƒ[Ô=L—ûséö òž` ´7Ø’áA»×²RÑ«†×»†Ú-4į)¶Ø!Ûö=Wš Hóº_Ù)ÿ^£­úð;Œ>ãœn)ƒõ¤K Üûãü|·œ®„¢…‚…û.˜ô3Яð-*ó &Há8gk±˜zÑaLõåg¡%à}7ÎGAËÚM4—=[™OÕøAç6ceò0§o&šÀ™áÀÎ 'q&šÆ™ágLä 1@õ˜‘°¤IŠ˜Î™4þ„Îa±§tnõ!“:v޴Δ?±3Øl]ëpà™‚§8 D7J¹°eåpã4“CŽP4“\òi±ú  cÒíèªéaÐŒÌC“nNº=5éö“LºýÔ5uN``vënP€žÉƒT™Ó{Pîœ$’§¶üÀš€Æÿ‘ÅꕆA5Ý2D§4TZ£´ x}Ò0‡h“†­KC“¨A¦·3£¶1` T%¹Ø!µåÊ «ÍCÇן+bHEº2Â5ï…ª^>kXؚƗÐt8¶ˆ¦CC+U/¶é0l¹M‡Â n: ZrÓ!ð¢›C–Ýt :鳂iŸLü,@p‘@£±Åµ¦ßÀv%ºÀÖ°Ü%6ÓV'zËl¬dxKmÍØȳ·Ü ‘Ê!r–1@wD/ÅÙ,þb\ÓgbNíû]-¸~ÖÀ#§YÃþ4=4c"ÖL5ÃÌû‚AO¹àŠa'µf¨ÑC—CZö3¼nØ_9l†x ¥„˜Wd\ÍÏ]oÔœs–jX»›}·¨½6ÎþÚÿ¦ÕÏ££(¦ÏòNÕ«yº§¯©Bø"µo§B˜¶ë…p·£yr=]­¤ÿœd1áWÉÛùh}¿œr ãÅ|-Fè‡õ‡»i;­Vw#û˜>œìdþ àÁOG³é$„JnïfÓ[‘ÎÑZäéa¬gÁÔ:fyx¬ùd± fân:N®“qDêl ·v'mȪ;åÝÜ…¨Ì¡‹ê Ž*ƒ y=ÚžÓ×ã°Ô¼žäOù‘}/OÆ@" rã– m :ÈݘqBAƒÆ$Ð 4=Æt9V!B噆™e蹜!]f˜ÉçËðrÙ6cÚZ aM?R*K! ¶©b¨ãB&§/5hwú¬’έ6i׺Uv›ùcV_]«'BzÓíә̡f¬#°eߨÔi  ´ømõqÿû{YvyVa-PÙÅyÆ[ö3y¢±^½ÈVŠv¡OWWapëÖGÈ2l!<5]]š–!´ÕG4Z1!®5Þ<%Ñäì˜&Å£ŠDZëµýò bN¶ò®‡µ]W£x|b±™TX˜åœ<€‡MB¸]_Ž$ÃýÔdoÔÅæ¶ žÙØMÁNßssv<‡?¨=:2äj¯ÎÚ‘Bº¾Ó³L9jºôé*o~6xsBà·l3ˆÌ"ߌ–·£·É8TM:-¤ÛÐÓŸ(:VÁa±¢z~ý/Y®þ´Ï…J2}Ê7 ZXüÕ·(ÌS·ÉK}Öê¼Wíf °{ÆÎ¡ ¤£00¬Ñ0´¨gÙ#¤F1lw뀠¦!Ì °ö°4 \¾“»UÀúAÛìÊÚuó (E Gµ´Î,°Ãn³Ï§' ðUÿ±#ë °ÎŸä@ÏÅÉÕ vÈŠ­®våæ )ONGÆéæšSôÒÒªn¥-ªÕ5+Í –/ëò=6)è`û¦MS˜ÏiIfQȘäd-µ±,ÓojL¦°ÄF£»(´Ügå){Ê O·Ú½¹>ý´R…·â€×Ú–Eög~|–ÈS3·­!+ˆ1ÍÅåñYHi¼vÑ·°ª”S¨¦t.S §ÃV¹ ½°8©s¢DBÊ [3î†?¡ŽYE ‚¨„ϧG6vãž–#Ñ¿O¢Ø8ó~`“ •Cdxé ãJP/°DàÒïÎß¼YŠGFIߎ‘œY^dÒ`ÄŠŠ­þ’´O ª—ÇïmtÍ’ Ž.F»ˆÈV8&¶Ùk˜[½})ð7O;޽ž^y!VXM™S`Ë}¹ÀåÈ¥ak»b—´ÃHÿ×ÿýf•>»ˆW§ÇGp¸èØÊ-¶\R“´ð’PG4öùÍKºþ&ý6ùq¶ò¼y¬ÛýDgþ¢ha\ôÀÍ¡OãÞéó‡*ûš—§š¡þqg8‰ †üOr¤gÜß@Øe#Jž IÜ«PŽºgÀ‡›È’:r;8DÛHG–×e5.÷Æ ¯ƒ<øì# ¼kÚ[Ì92IÕˆ£xè¡KKt,-•“q¢“ÄÕðé²·€×©þ}š!OwÇ©¶´}åò¼DÜð0`à8ï‡ÃÇ%P´ dt¿QJ‡ù+&©[ð„Á ©?Jæo¤L®TÒQ._u°üØpyÎ(Aj=@‹g]™/¯üàr»VïÍÆ•Ý,£@–ª̰SM<÷^‹ÁQG _'C Iž Lø©S¯Ä0Þðµ)3Æ‹ºCÝc^cXH¿M5 ¾aAÙþ±#Ÿ}¡@õb¥Ï'ƒ”ècʾ#Р#ÿiW–_N¢ÄÖ<<Û÷ Ñî]dË=Y1¨ë"ýÄPn>ÿîq€þœÊÞfGËbÃîÌð’$=wÌTùƒgõ[9tçÔéüí,Y½B®—Óù x;]ÞŽæ@@²ÉçÀ€›ÑÝh>]M ?Ë)È¿KÊJÞŒM®“éä­—£I"/§Žfêz9š¡ÉH.¡ï*X‘üAßï–c(;£äOPüýÐÇáh>š€)Qh…“Ë€"Ù)}Ê€ \·O6!_Sù²Ô*¥å»qî¤7AÍSÉúž×å¬IL ¦f/Ϻζ rÆ*åyX y##ºMÑÙIYã09[Ó†b§í¥s&Ÿ)‘·PÕDY›¯ÎÅðöó­(QKúñêßá¡Sâxî$M£ÅK˺M›çן€HX¥ÂJۣʜÊ9”g–X¹ÑÜÕПú3õ¡êvý_‡Ý9í‰Ã$¯»ô%>"›çG+©UÑIèˆç§Amp"÷{­‹££oyKžUâ\ ××õËg¿E7,IŠo ‚ÕÁ;+­‚"hñéëbQ[¾fŸ FÕUû˜Ö‚­céÐAËÝ­aÒi ýAŒæhÇ8…_Yge‡ëϨƒßgFy΂/ï¡èsbˉ('øHÎðr€2 •¸¼ûCü+ ì]uÜwH"^È23óí† >ËÀ}’áœW8¯%x/¯åm€vœ‹}¥«xæŽ0í¸”Gqœ! qHÓ³M|HËRB\µÔÑÝ*˜—«Óæ¹YG‹­„ ®|ÑX¸ÀÜÄ.>‹ ù×Þ,¢³ ØF=¹EBËÏ5fÁO·[ý+«ÌžÖ~û%*]ªŸíÜââÕÊA+¬vzšÛf»LCRbsÝ·š  Ð{]‚?"˜¢<æ/ a.0´£aPÅPgÜ8W´:PsÃ+1µªÊÛ¸«Êƒ¼Â’ŽÍX $µ¢dÀšµž *K ¢«ìªÍ X‹Î´‘Ú€ ?d‘¼Uú5E¾= £luH7$ê9û®Ü¿!ÁÈrމà…Ï ÀßQ–´Bò┩K€Þùˆð²fÝÛj4˜Coƒ'´qó‹¸ Žéx¶œs$ïúU'a\ß (<÷ )JKÝÕ7&¥äHw(ã²ý5´w@gðД[ãY±™aö‰ô+vÜ=4Ì;R.‘•úŒVs–ªèOž‘Ñcù.ûþ:ùÛÓ²™ì W^úD¶mÚÏhËà.«öÒ jM–î&ÝUZç›>HŒÉ]NG&6!.“õ4€ÍfÄ|1 Ù§õ—$U5¤wMÔàq@s~0å:¬NnÈž¥É¡Ë/0ûV¦c>@ `BTdR óýa—wwžº†Ú#Âe)+Ôõ ÀŠì[ÿ«Ÿ€µåD=†ø²‡¬YbÎYÖñÅ>ÈÒ)3DºžfpÒÝîAü_ùÍžsÊÌAbéŽ͈/(Ê¥>)‰×º±ªŒ:\ƒ’ü6(?dCRüƒ6xbœÃ6(ðÜ7°`¤D¼Aiчo`I¬8Õ?„ƒùWmÐ ¬ÔáÉ#’˜£6ˆˆÇmܪZ 1åžì‚ „šÌv[6Ÿ÷br›KQB½eÈrL£æóU²^=ÜM—Wl­ Ÿ5 ±EmÂec–'%ߦ'¡ªl·f äY˜ïó0 TåvØ ¨NX:·n «²ÜeiáôN œ…¹~C À¤<)ŸPÉðk1×::oÁmžq‰ÔXúe ž»Y)·”nÀÖs\‰¤ Ík§1ƒ¨Î«Ì[%qrê´TR‹«4¨u\å5›ÔâªSÁÓ«³ý©œö}S&Wg{™=Æê,­6ÏbõX­í9 á ±Næ„„0§DÜœ»'XÌݪ^×êèÑ`~Ú4‰! ÊÖõ.}"0Ú Åã^òu0óÅl1š?_¬¯÷ó EV9çw¡ìÂ:$y¼JÿÉ™›7."*þhš Ž-B$Aº—ÄRpy‰è ™Rbƒ£VBÔijyâ“+>ÀfÛv>U'ÜRWf†BdY¡ci>oè‰m_Rsd$zÑ“d“Š9Ãsé³éŽ<¹0«u‚ P¿Ý[±ˆÎ•᜛† Ž{ë {6êX1sè”PdxTO΂‡.â£x¶‡Æd5î.œõ¬­ý™{EÍľ¡¶’Ë9Ù:ßg…¥d´Ÿ¬mp}L«ã­hÏ!Ð$}a@fÙ—Pþ"0b>J’€Ð Ò€`r,•à¢ï˜*ý¶x|¬íbÌ©ÎD‚vùÓ3…Úç»]^ßeÕ;¡Š88ºö²gYñªßc¾¹ÀβôÀÃ?UÙS)OaŽOGÑ«@I6íql$b[WéW1,Ôh²¸}¸]L¦$äχd.Póõ;öíô)uÆBRK6tsªäx¶2\É‹Â÷5éà+ÜE5Ï …ll6-iþß™tšÏš`ºœr/gBëry[ÒG”PÍ2“—…¦ÅV‘È4i¨Ä¹Çs@àJv›°TîPîtáì8Y­›åvT+Â׌âpÁAô²U³t"„²J÷Máy  s‹Ù06*/Ze.?™±L¤‡\2†¼–êS*Â× ”ÎU.ƲµóÏ¡ú=¤›/M›±pÇ«û‚ž1ÝÁjéòqÛö”höcÜ7Ÿ Ü¾?1a#ÑÁD¯Zó#hîi×*)ú6ã.HãŒjódÓ=gËxUVÒ/aà¬{Һ؛BŒ»Ï¿Ã<õãJ@ÏêÄ¿ø1lH‘ÎI¢¢­OŸáXÏK‡˜ëìâr×TpRÜ¡†Ô”ä=r¼0õpYM+êâ€G¤ìNœz´¨#8Êó!ë(.+^E7~¿äÒ6Á‚´5\cÕA4·W!Ú×u 5²<0§ú9þ&D›K¹áøò‹®R®ì¿d…˜æÓg•]lcß•uîžcq¡ûô;V+*x›íò½\K©)T•ÕÄ|>Mû‚ÜñÓ­y4_gصç$}´A·’IlðôMU¿‚£:JŒ^ÉõšÝ—ü0éÚx˜¥76u{”ô§ËáÏöÏ tÛRGá¸`êѰÿ%+q¾Ôc8ž—l4ä©Gp}.ù Z.èm©æ»Zj8€¿_w°Eî ¥¿vÖ„¸NÛï”óêãÕ2÷»g©74èüP×Ô0a„ _AAPÍ€þ{YŒß¢‡t‰ü#†ÂñËh€ÙN …åK¼sœ¶Øˆ Œ¶Ä» l©•¼S5–Yñ&„-‚ç[І/¥Ø×XŸæðÏìİ.¢Ýþ¹Ú¦\Æ&å[$iå ö9{/&ΟVïË52[Ìß‚‹ùôá6™ßÛ'è¬àw‹û%8}ÃÔá­Þsvß%c­Jw ässUÎÝ•êÂßÞ®ªz˜Mço×ï@Äø~µ^Übüâ´ÿœUÚ;\(²v_É€W2àU€²Xî.X#¡:º€áæŸbˆ[Î6—UG­çdvï“&䀧[žEI|÷3 =Ü+ècè† N<+ É$&ëÄZzÜoÅü÷ÌøÿƒL«¾ãH+è.ÐÑÔùœë²’úÌFw— Ónþéó)ßm¯åGQÕN%4%ÔßÀË,ç–±—„óã³J,3wö»ÑsWVÝó§P›ÕÛ «¶½ÇS«`7“NÇl™mgÙ×lç: êaÑvsäK-k›m*uhw¥&ÿ`…h¯Üª8‰r©1V|³îW/Ä0[m¤Ý/ðßG¢5OdÆäé¸È\µü¤¨¥3µxçÌ8”ß,ß™õ1¼Ã?eÇ‹ º«²M¶Í‹§ËH¼À”JLŠÂÍûKF5k^0žÔh¡r*5¤‘ÇMÁÔž©£"×›L”wÑ™!ë}‘nF5àV¨Ém‡úäÃàÐ÷N:¾Ü¼\­Tå1=f3Ñrbšf.erb©ò 9ˆã…XI)ÔêÅÃ,Ìàx¨2°Ü‹-›Âè0æ&þºpϊجdß.nÁçÜ-neà Ëqþ°Zç¦r‹:ÈGøÞjáÈ0tñÛÒ­Ðø»Ò¾Œsôš¾Y¸Òü½ß.hã®Sw!~_×AN…uxúVk‹v®™Œ{ °q]ïÞ˜°CÇp¶Ú¤‡t“_’vÊ`¨Eï*w;,!ÉPΰÐ0X—ã l¨¿õPö5:›Çh 3mí9š  ÆŠ.ˆ1T´X®Îwð‘¹ß”Ñ %è«ÊCÓ²GáË„6ç}´åõ©ÊÆm9ÃÍÔ½Ëv‡Ìs)ÓBy´^›âÝoo(œË• 9…Ø„æòšs7ËÃðÁËU¬iW‡*@x|oÕ*GTqIF—Sšç–yoÔF3Iœ+N—Ô_Pik¡•pÙS£{â¢á»±$Æeh7Z ¹Oۓ㛤ô$%Í1$Ô·ÔÚê‚®‡æº=uàlϧ€ž×«^åûuÙ­xºVÍŸYúE¾(§Ë´g#¥’j tåžîµC}3 oO#:£Œ— à8­ŸˆÚ±ÄAZ/…ì2kNÀ€suÀ€çðµ´ð¢NäûDÞ©|Ç:™ï3‘qÑ?¡ïËŠ_ý ¶Ö:ÈòçO LTû#&;a¨ù°A,l%ÀPö’HgŽÕ =úl¢åßöû%Uö¨ËL>Yl2,¢–*K.„Aoäà5¤Îì4wéýç);¹·h!ÁÎÙ$lÕ ¢õæˆV‚R}fÄbšÝ¿œ{É¡‚l~èu³YvšèáS&˜hì?ý[f „Ž#šáàHˆkdz¥³Ýók´Â— ¬ðˆc"Pù’ûÕ&aÐyS@pï!ËbR]Èò…6ŽM‘C7aMèøñŸüðóh»ËªßÞf£‰Kå¿X ²·cAB€Þ »Á U¦` "š·ê“0™†×#/q'¦>H¿7—((RÊ£T¶5ö4 /¾ÎwêDOâFp7_êG½ö8ØBêï~nÁò(PC°ú²%‰!Gn—¼öë C¶EDK¯Š¯od+#jcaì88Õa!ÑYlªB, [# ÿeñˆ*±DŸS'– µIõ0Üv´´EÜA5Ô 5Ña0=ÑpEáBÈÄ/Ç ªQ›jª³ÐÁTy(Z*”( +êZ&R—R–&„¡*å&–ö"ÆöÖ‚ÑÐb%ÀþBÖ4&ÙãNd‰¾o…áê)‰.ðóé +ñ°]æ—Eö5ÛQÉÿ>½àõŒWº¯QÄ£(4ÛÖ‚í»ô`2½žÖö  0_<Œ·òÈÉ*YÌQØÕtµ~XÝM I ‘%Ò4ºŸñ°×Él=]±¾»¿¾¾ÍóÙ‡`Œ«õRÆ[H(’ÃE]Õƒ|$0[ý‡T žÞ@zqaí˽$6+¶Tîdð .Údºóåí6ŒÈ¶ÎÄÂÂH~ÒP sCƒÖå1Ý%E@T‹â£8Gš„QâdCy-Úð†& ¢|âÅYdÙ¶VU Ø0ç¨Ú—nÝrµu”V/¯oà ACã ÉÕ™ ‰lQ!ií¥´jôýkÔÚiÑ-c¾ÍбËÂãß‚Æ `°Þ ø¡²‰š³ç»²¦4—[òJ÷2áA¥Ç›$hÊÐ~û1¹ó¦Ç]hRh¡Ä4ÙXã.$+=ËÆ“" ܳ_\”üýp;z›ŒCÈëõô_ë è°™ƒ !h9 ¢æ£Ûi$L[çH/„£–ü†ÃÚX@ëô*UÄY2×÷8&V è»L¿>Ì’»®Ò|ÇFßKÛ)ZVÚî“âˆð½¡ä¯žË “L\pÑÖ^¿X·÷GR™@I±•$Üó- ÝcÏpâøHÃg)}ˆjpiëc˜lú>\6F¶lÝòØp³cAmª,‚óMÌ»@À0选yLÌ»0lbܤA,íI@L{ Ló:<ݲ‚ƒÛÌ)6ÝòJ°ý; 1™ò1À„Å-³}*¢”çšH>é‚PH‰I£Äå>õ@ÐðæÂ¨©·“=`ªgਫ਼ղkcªDÔ99+ìPجÐP”5+DÐÐ…†äâ³B…[Ó€½Ìßp‚È¢•p`„®4a„j ßRügó<]\s°qVl¬„Lÿ’‰&eŠNÛ×$ı·!,isC„Ç|·cB‘-BJ«0þ&áÇü0.‹ú˜Ç:hIXàÙb¼JÞ’1w AÆÓyPÊ|‚ˆ´¼›,Ci ADZ‚Ræ“D¤åý4¹ž…s´ø3Y'·!0Çö«Ñv\Èlêí¸1A€E·ŽBÉUMŠN®€„’+júý”N®‚ÛK¨e“ T£€„ªQ@Bå¢ú].Â(—P5 H¨erA)“Õ!ÈhŒh´þW²¸öLO¿Ü_… ëE íJ-h˜ó #-ªèU>o‹tŸ¡Çœº0×7¢M$C÷Ùñ¹ôL.8û~¬R\t¹wïmZábè{B¿êKh¸ÿz¤¼Z/€ýÏ.ÛàíÄ<¶Çh`Á»x÷>–ÃŽÈ ¦¢c]¸´Û²^—7"L½ûsãÏ»:¤<û£Aèª@;ˆ ’°³õ½:Žj@LeC}ý·OÖè@·ª±F â¼CærYÐO(á䊅‘Mà:ÏvÛšl“ød¸‡ˆ™p¥.OAaK¯­Ë‰h¡†P÷ !ª/Ô^K rV릀è¶MfMTÓ€YŒ‰â$©)÷ FKµO!ÉIÙ=…dáÑå7Å?w$Øb ŸY¯Dýžâ7Tÿzž×cpòÝ#²Ò›ê÷¨–”῟9qî£Áæ¨=¢›hR%>à×#é‚{c?°mÑ…‚çâMÀÏ„v6aÒ›¡e#F³ØtqAÑýG]ˆ`ü]\]e1ɧ«ìV6˜°”X!S .€„ð:Á .‡H·§ˆz]²wU(b«°£\ÇQsS…Ö¦ oÖº+¬Á¬Q q–èèÎi˜* tÿÇWŸš¼ d鬀î¯-&dŠ˜Ìß^ß$AÐß¡Ýó×77 Ù¨CÃAŽwZu?)ÏxÞALž4 M\çðôh hAnRWþ˜¦™C¥²m+Þ®‘äNYàÉqFõ(qÀt*VhcMÒõ1µè(rTÕÕG4çvÿŽŠŸœ(D)×Ñc‰Ò÷ÁÞQe»,­³® Ä«ò²™u~ËácV@àˆ—ƒ¨ÚÞî¸?[W{L1…·¶ 2vµX܆–C%œ!Ö8b+yc¹íîg*9öŽ”ƒ½ö×ÿ’öR°ò·7 õEÙ«Œ¡™Bî××ÿ¯™´ªÞÍRZ|[ÐEN‹mÜÒ–+àú´ÛaÝ|¶. ½º8ï\™+ÓH(Ï ûÒ‚Iû7‚ÕÛÂ=uô7Ó]Ø®Ü'•¼øÐed †.U/ü³h Š[x‡Û‚(TõZ(B÷.Î8Ñ&V+>ŽP„NáP¸ `£AÌ“™–v×i- â¯^‘E©KLüº¤KG¯8XrMÑë@ØAHkœ“âÆÓùå¦DLç“×ÈZþ×úÜøäáMntRƒŸqüóÿ[ãéDCasm-3.3.2/src/org/objectweb/asm/optimizer/shrink-frames.properties0000644000175000017500000000214210670531561025253 0ustar twernertwerner# class mappings org/objectweb/asm/Frame/remove=true # field mappings org/objectweb/asm/ClassWriter.typeCount=- org/objectweb/asm/ClassWriter.typeTable=- org/objectweb/asm/Label.frame=- org/objectweb/asm/MethodWriter.frameCount=- org/objectweb/asm/MethodWriter.stackMap=- org/objectweb/asm/MethodWriter.previousFrameOffset=- org/objectweb/asm/MethodWriter.previousFrame=- org/objectweb/asm/MethodWriter.frameIndex=- org/objectweb/asm/MethodWriter.frame=- # method mappings org/objectweb/asm/ClassReader.readFrameType([Ljava/lang/Object;II[C[Lorg/objectweb/asm/Label;)I=- org/objectweb/asm/ClassWriter.addType(Ljava/lang/String;)I=- org/objectweb/asm/ClassWriter.addUninitializedType(Ljava/lang/String;I)I=- org/objectweb/asm/ClassWriter.addType(Lorg/objectweb/asm/Item;)Lorg/objectweb/asm/Item;=- org/objectweb/asm/ClassWriter.getMergedType(II)I=- org/objectweb/asm/MethodWriter.startFrame(III)V=- org/objectweb/asm/MethodWriter.endFrame()V=- org/objectweb/asm/MethodWriter.writeFrame()V=- org/objectweb/asm/MethodWriter.writeFrameTypes(II)V=- org/objectweb/asm/MethodWriter.writeFrameType(Ljava/lang/Object;)V=- asm-3.3.2/src/org/objectweb/asm/optimizer/MethodOptimizer.java0000644000175000017500000000665210564776410024372 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.RemappingMethodAdapter; /** * A {@link MethodAdapter} that renames fields and methods, and removes debug * info. * * @author Eugene Kuleshov */ public class MethodOptimizer extends RemappingMethodAdapter { public MethodOptimizer( int access, String desc, MethodVisitor mv, Remapper remapper) { super(access, desc, mv, remapper); } // ------------------------------------------------------------------------ // Overridden methods // ------------------------------------------------------------------------ public AnnotationVisitor visitAnnotationDefault() { // remove annotations return null; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { // remove annotations return null; } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { // remove debug info } public void visitLineNumber(final int line, final Label start) { // remove debug info } public void visitFrame( int type, int local, Object[] local2, int stack, Object[] stack2) { // remove frame info } public void visitAttribute(Attribute attr) { // remove non standard attributes } } asm-3.3.2/src/org/objectweb/asm/optimizer/shrink-signatures.properties0000644000175000017500000000051710670531561026166 0ustar twernertwerner# class mappings org/objectweb/asm/signature/SignatureReader/remove=true org/objectweb/asm/signature/SignatureVisitor/remove=true org/objectweb/asm/signature/SignatureWriter/remove=true # field mappings org/objectweb/asm/ClassWriter.signature=- org/objectweb/asm/FieldWriter.signature=- org/objectweb/asm/MethodWriter.signature=- asm-3.3.2/src/org/objectweb/asm/optimizer/shrink-resize.properties0000644000175000017500000000015510670531561025301 0ustar twernertwerner# class mappings # field mappings # method mappings org/objectweb/asm/MethodWriter.resizeInstructions()V=-asm-3.3.2/src/org/objectweb/asm/optimizer/AnnotationConstantsCollector.java0000644000175000017500000001233110701747173027111 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Type; /** * An {@link AnnotationVisitor} that collects the {@link Constant}s of the * annotations it visits. * * @author Eric Bruneton */ public class AnnotationConstantsCollector implements AnnotationVisitor { private final AnnotationVisitor av; private final ConstantPool cp; public AnnotationConstantsCollector( final AnnotationVisitor av, final ConstantPool cp) { this.av = av; this.cp = cp; } public void visit(final String name, final Object value) { if (name != null) { cp.newUTF8(name); } if (value instanceof Byte) { cp.newInteger(((Byte) value).byteValue()); } else if (value instanceof Boolean) { cp.newInteger(((Boolean) value).booleanValue() ? 1 : 0); } else if (value instanceof Character) { cp.newInteger(((Character) value).charValue()); } else if (value instanceof Short) { cp.newInteger(((Short) value).shortValue()); } else if (value instanceof Type) { cp.newUTF8(((Type) value).getDescriptor()); } else if (value instanceof byte[]) { byte[] v = (byte[]) value; for (int i = 0; i < v.length; i++) { cp.newInteger(v[i]); } } else if (value instanceof boolean[]) { boolean[] v = (boolean[]) value; for (int i = 0; i < v.length; i++) { cp.newInteger(v[i] ? 1 : 0); } } else if (value instanceof short[]) { short[] v = (short[]) value; for (int i = 0; i < v.length; i++) { cp.newInteger(v[i]); } } else if (value instanceof char[]) { char[] v = (char[]) value; for (int i = 0; i < v.length; i++) { cp.newInteger(v[i]); } } else if (value instanceof int[]) { int[] v = (int[]) value; for (int i = 0; i < v.length; i++) { cp.newInteger(v[i]); } } else if (value instanceof long[]) { long[] v = (long[]) value; for (int i = 0; i < v.length; i++) { cp.newLong(v[i]); } } else if (value instanceof float[]) { float[] v = (float[]) value; for (int i = 0; i < v.length; i++) { cp.newFloat(v[i]); } } else if (value instanceof double[]) { double[] v = (double[]) value; for (int i = 0; i < v.length; i++) { cp.newDouble(v[i]); } } else { cp.newConst(value); } av.visit(name, value); } public void visitEnum( final String name, final String desc, final String value) { if (name != null) { cp.newUTF8(name); } cp.newUTF8(desc); cp.newUTF8(value); av.visitEnum(name, desc, value); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { if (name != null) { cp.newUTF8(name); } cp.newUTF8(desc); return new AnnotationConstantsCollector(av.visitAnnotation(name, desc), cp); } public AnnotationVisitor visitArray(final String name) { if (name != null) { cp.newUTF8(name); } return new AnnotationConstantsCollector(av.visitArray(name), cp); } public void visitEnd() { av.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/optimizer/shrink-annotations.properties0000644000175000017500000000136510670531561026341 0ustar twernertwerner# class mappings org/objectweb/asm/AnnotationWriter/remove=true # field mappings org/objectweb/asm/ClassWriter.anns=- org/objectweb/asm/ClassWriter.ianns=- org/objectweb/asm/FieldWriter.anns=- org/objectweb/asm/FieldWriter.ianns=- org/objectweb/asm/MethodWriter.annd=- org/objectweb/asm/MethodWriter.anns=- org/objectweb/asm/MethodWriter.ianns=- org/objectweb/asm/MethodWriter.panns=- org/objectweb/asm/MethodWriter.ipanns=- # method mappings org/objectweb/asm/ClassReader.readAnnotationValue(I[CLjava/lang/String;Lorg/objectweb/asm/AnnotationVisitor;)I=- org/objectweb/asm/ClassReader.readAnnotationValues(I[CZLorg/objectweb/asm/AnnotationVisitor;)I=- org/objectweb/asm/ClassReader.readParameterAnnotations(I[CZLorg/objectweb/asm/MethodVisitor;)V=- asm-3.3.2/src/org/objectweb/asm/optimizer/shrink.properties0000644000175000017500000003056211534435172024010 0ustar twernertwerner# class mappings #org/objectweb/asm/Edge=org/objectweb/asm/a #org/objectweb/asm/Item=org/objectweb/asm/b #org/objectweb/asm/FieldWriter=org/objectweb/asm/c #org/objectweb/asm/MethodWriter=org/objectweb/asm/d #org/objectweb/asm/AnnotationWriter=org/objectweb/asm/e # field mappings org/objectweb/asm/AnnotationWriter.cw=a org/objectweb/asm/AnnotationWriter.size=b org/objectweb/asm/AnnotationWriter.named=c org/objectweb/asm/AnnotationWriter.bv=d org/objectweb/asm/AnnotationWriter.parent=e org/objectweb/asm/AnnotationWriter.offset=f org/objectweb/asm/AnnotationWriter.next=g org/objectweb/asm/AnnotationWriter.prev=h org/objectweb/asm/Attribute.next=a org/objectweb/asm/Attribute.value=b org/objectweb/asm/ByteVector.data=a org/objectweb/asm/ByteVector.length=b org/objectweb/asm/ClassReader.items=a org/objectweb/asm/ClassReader.strings=c org/objectweb/asm/ClassReader.maxStringLength=d #org/objectweb/asm/ClassReader.header=e org/objectweb/asm/ClassWriter.TYPE=a org/objectweb/asm/ClassWriter.version=b org/objectweb/asm/ClassWriter.index=c org/objectweb/asm/ClassWriter.pool=d org/objectweb/asm/ClassWriter.items=e org/objectweb/asm/ClassWriter.threshold=f org/objectweb/asm/ClassWriter.key=g org/objectweb/asm/ClassWriter.key2=h org/objectweb/asm/ClassWriter.key3=i org/objectweb/asm/ClassWriter.access=j org/objectweb/asm/ClassWriter.name=k org/objectweb/asm/ClassWriter.signature=l org/objectweb/asm/ClassWriter.superName=m org/objectweb/asm/ClassWriter.interfaceCount=n org/objectweb/asm/ClassWriter.interfaces=o org/objectweb/asm/ClassWriter.sourceFile=p org/objectweb/asm/ClassWriter.sourceDebug=q org/objectweb/asm/ClassWriter.enclosingMethodOwner=r org/objectweb/asm/ClassWriter.enclosingMethod=s org/objectweb/asm/ClassWriter.anns=t org/objectweb/asm/ClassWriter.ianns=u org/objectweb/asm/ClassWriter.attrs=v org/objectweb/asm/ClassWriter.innerClassesCount=w org/objectweb/asm/ClassWriter.innerClasses=x org/objectweb/asm/ClassWriter.firstField=y org/objectweb/asm/ClassWriter.lastField=z org/objectweb/asm/ClassWriter.firstMethod=A org/objectweb/asm/ClassWriter.lastMethod=B org/objectweb/asm/ClassWriter.computeMaxs=C org/objectweb/asm/ClassWriter.typeCount=D org/objectweb/asm/ClassWriter.typeTable=E org/objectweb/asm/ClassWriter.thisName=F org/objectweb/asm/ClassWriter.computeFrames=G org/objectweb/asm/ClassWriter.computeMaxs=H org/objectweb/asm/ClassWriter.invalidFrames=I org/objectweb/asm/ClassWriter.cr=J org/objectweb/asm/Edge.info=a org/objectweb/asm/Edge.successor=b org/objectweb/asm/Edge.next=c org/objectweb/asm/Handler.start=a org/objectweb/asm/Handler.end=b org/objectweb/asm/Handler.handler=c org/objectweb/asm/Handler.desc=d org/objectweb/asm/Handler.type=e org/objectweb/asm/Handler.next=f org/objectweb/asm/FieldWriter.next=a org/objectweb/asm/FieldWriter.cw=b org/objectweb/asm/FieldWriter.access=c org/objectweb/asm/FieldWriter.name=d org/objectweb/asm/FieldWriter.desc=e org/objectweb/asm/FieldWriter.signature=f org/objectweb/asm/FieldWriter.value=g org/objectweb/asm/FieldWriter.anns=h org/objectweb/asm/FieldWriter.ianns=i org/objectweb/asm/FieldWriter.attrs=j org/objectweb/asm/Item.index=a org/objectweb/asm/Item.type=b org/objectweb/asm/Item.intVal=c org/objectweb/asm/Item.longVal=d org/objectweb/asm/Item.strVal1=g org/objectweb/asm/Item.strVal2=h org/objectweb/asm/Item.strVal3=i org/objectweb/asm/Item.hashCode=j org/objectweb/asm/Item.next=k org/objectweb/asm/Label.status=a org/objectweb/asm/Label.line=b org/objectweb/asm/Label.position=c org/objectweb/asm/Label.referenceCount=d org/objectweb/asm/Label.srcAndRefPositions=e org/objectweb/asm/Label.inputStackTop=f org/objectweb/asm/Label.outputStackMax=g org/objectweb/asm/Label.frame=h org/objectweb/asm/Label.successor=i org/objectweb/asm/Label.successors=j org/objectweb/asm/Label.next=k org/objectweb/asm/Frame.SIZE=a org/objectweb/asm/Frame.owner=b org/objectweb/asm/Frame.inputLocals=c org/objectweb/asm/Frame.inputStack=d org/objectweb/asm/Frame.outputLocals=e org/objectweb/asm/Frame.outputStack=f org/objectweb/asm/Frame.outputStackTop=g org/objectweb/asm/Frame.initializationCount=h org/objectweb/asm/Frame.initializations=i org/objectweb/asm/MethodWriter.next=a org/objectweb/asm/MethodWriter.cw=b org/objectweb/asm/MethodWriter.access=c org/objectweb/asm/MethodWriter.name=d org/objectweb/asm/MethodWriter.desc=e org/objectweb/asm/MethodWriter.descriptor=f org/objectweb/asm/MethodWriter.signature=g org/objectweb/asm/MethodWriter.classReaderOffset=h org/objectweb/asm/MethodWriter.classReaderLength=i org/objectweb/asm/MethodWriter.exceptionCount=j org/objectweb/asm/MethodWriter.exceptions=k org/objectweb/asm/MethodWriter.annd=l org/objectweb/asm/MethodWriter.anns=m org/objectweb/asm/MethodWriter.ianns=n org/objectweb/asm/MethodWriter.panns=o org/objectweb/asm/MethodWriter.ipanns=p org/objectweb/asm/MethodWriter.attrs=q org/objectweb/asm/MethodWriter.code=r org/objectweb/asm/MethodWriter.maxStack=s org/objectweb/asm/MethodWriter.maxLocals=t org/objectweb/asm/MethodWriter.currentLocals=T org/objectweb/asm/MethodWriter.frameCount=u org/objectweb/asm/MethodWriter.stackMap=v org/objectweb/asm/MethodWriter.previousFrameOffset=w org/objectweb/asm/MethodWriter.previousFrame=x org/objectweb/asm/MethodWriter.frameIndex=y org/objectweb/asm/MethodWriter.frame=z org/objectweb/asm/MethodWriter.handlerCount=A org/objectweb/asm/MethodWriter.firstHandler=B org/objectweb/asm/MethodWriter.lastHandler=C org/objectweb/asm/MethodWriter.localVarCount=D org/objectweb/asm/MethodWriter.localVar=E org/objectweb/asm/MethodWriter.localVarTypeCount=F org/objectweb/asm/MethodWriter.localVarType=G org/objectweb/asm/MethodWriter.lineNumberCount=H org/objectweb/asm/MethodWriter.lineNumber=I org/objectweb/asm/MethodWriter.cattrs=J org/objectweb/asm/MethodWriter.resize=K org/objectweb/asm/MethodWriter.subroutines=L org/objectweb/asm/MethodWriter.compute=M org/objectweb/asm/MethodWriter.labels=N org/objectweb/asm/MethodWriter.previousBlock=O org/objectweb/asm/MethodWriter.currentBlock=P org/objectweb/asm/MethodWriter.stackSize=Q org/objectweb/asm/MethodWriter.maxStackSize=R org/objectweb/asm/MethodWriter.synthetics=S org/objectweb/asm/Type.sort=a org/objectweb/asm/Type.buf=b org/objectweb/asm/Type.off=c org/objectweb/asm/Type.len=d org/objectweb/asm/signature/SignatureReader.signature=a org/objectweb/asm/signature/SignatureWriter.buf=a org/objectweb/asm/signature/SignatureWriter.hasFormals=b org/objectweb/asm/signature/SignatureWriter.hasParameters=c org/objectweb/asm/signature/SignatureWriter.argumentStack=d # method mappings org/objectweb/asm/AnnotationWriter.getSize()I=a org/objectweb/asm/AnnotationWriter.put([Lorg/objectweb/asm/AnnotationWriter;ILorg/objectweb/asm/ByteVector;)V=a org/objectweb/asm/AnnotationWriter.put(Lorg/objectweb/asm/ByteVector;)V=a org/objectweb/asm/Attribute.getCount()I=a org/objectweb/asm/Attribute.getSize(Lorg/objectweb/asm/ClassWriter;[BIII)I=a org/objectweb/asm/Attribute.put(Lorg/objectweb/asm/ClassWriter;[BIIILorg/objectweb/asm/ByteVector;)V=a org/objectweb/asm/ByteVector.enlarge(I)V=a org/objectweb/asm/ByteVector.put11(II)Lorg/objectweb/asm/ByteVector;=a org/objectweb/asm/ByteVector.put12(II)Lorg/objectweb/asm/ByteVector;=b org/objectweb/asm/ClassReader.copyPool(Lorg/objectweb/asm/ClassWriter;)V=a org/objectweb/asm/ClassReader.readAnnotationValue(I[CLjava/lang/String;Lorg/objectweb/asm/AnnotationVisitor;)I=a org/objectweb/asm/ClassReader.readAnnotationValues(I[CZLorg/objectweb/asm/AnnotationVisitor;)I=a org/objectweb/asm/ClassReader.readAttribute([Lorg/objectweb/asm/Attribute;Ljava/lang/String;II[CI[Lorg/objectweb/asm/Label;)Lorg/objectweb/asm/Attribute;=a org/objectweb/asm/ClassReader.readClass(Ljava/io/InputStream;)[B=a org/objectweb/asm/ClassReader.readParameterAnnotations(ILjava/lang/String;[CZLorg/objectweb/asm/MethodVisitor;)V=a org/objectweb/asm/ClassReader.readUTF(II[C)Ljava/lang/String;=a org/objectweb/asm/ClassReader.readFrameType([Ljava/lang/Object;II[C[Lorg/objectweb/asm/Label;)I=a org/objectweb/asm/ClassWriter.get(Lorg/objectweb/asm/Item;)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newClassItem(Ljava/lang/String;)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newConstItem(Ljava/lang/Object;)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newDouble(D)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newFloat(F)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newInteger(I)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newLong(J)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newMethodItem(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.newString(Ljava/lang/String;)Lorg/objectweb/asm/Item;=b org/objectweb/asm/ClassWriter.put122(III)V=a org/objectweb/asm/ClassWriter.put(Lorg/objectweb/asm/Item;)V=b org/objectweb/asm/ClassWriter.newFieldItem(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/objectweb/asm/Item;=a org/objectweb/asm/ClassWriter.addType(Ljava/lang/String;)I=c org/objectweb/asm/ClassWriter.addUninitializedType(Ljava/lang/String;I)I=a org/objectweb/asm/ClassWriter.addType(Lorg/objectweb/asm/Item;)Lorg/objectweb/asm/Item;=c org/objectweb/asm/ClassWriter.getMergedType(II)I=a org/objectweb/asm/ClassWriter.newNameTypeItem(Ljava/lang/String;Ljava/lang/String;)Lorg/objectweb/asm/Item;=a org/objectweb/asm/FieldWriter.getSize()I=a org/objectweb/asm/FieldWriter.put(Lorg/objectweb/asm/ByteVector;)V=a org/objectweb/asm/Item.isEqualTo(Lorg/objectweb/asm/Item;)Z=a org/objectweb/asm/Item.set(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V=a org/objectweb/asm/Item.set(D)V=a org/objectweb/asm/Item.set(F)V=a org/objectweb/asm/Item.set(I)V=a org/objectweb/asm/Item.set(J)V=a org/objectweb/asm/Label.addReference(II)V=a org/objectweb/asm/Label.put(Lorg/objectweb/asm/MethodWriter;Lorg/objectweb/asm/ByteVector;IZ)V=a org/objectweb/asm/Label.resolve(Lorg/objectweb/asm/MethodWriter;I[B)Z=a org/objectweb/asm/Label.getFirst()Lorg/objectweb/asm/Label;=a org/objectweb/asm/Label.inSubroutine(J)Z=a org/objectweb/asm/Label.inSameSubroutine(Lorg/objectweb/asm/Label;)Z=a org/objectweb/asm/Label.addToSubroutine(JI)V=a org/objectweb/asm/Label.visitSubroutine(Lorg/objectweb/asm/Label;JI)V=b org/objectweb/asm/Frame.get(I)I=a org/objectweb/asm/Frame.set(II)V=a org/objectweb/asm/Frame.push(I)V=b org/objectweb/asm/Frame.push(Lorg/objectweb/asm/ClassWriter;Ljava/lang/String;)V=a org/objectweb/asm/Frame.type(Lorg/objectweb/asm/ClassWriter;Ljava/lang/String;)I=b org/objectweb/asm/Frame.pop()I=a org/objectweb/asm/Frame.pop(Ljava/lang/String;)V=a org/objectweb/asm/Frame.pop(I)V=c org/objectweb/asm/Frame.init(I)V=d org/objectweb/asm/Frame.init(Lorg/objectweb/asm/ClassWriter;I)I=a org/objectweb/asm/Frame.initInputFrame(Lorg/objectweb/asm/ClassWriter;I[Lorg/objectweb/asm/Type;I)V=a org/objectweb/asm/Frame.execute(IILorg/objectweb/asm/ClassWriter;Lorg/objectweb/asm/Item;)V=a org/objectweb/asm/Frame.merge(Lorg/objectweb/asm/ClassWriter;Lorg/objectweb/asm/Frame;I)Z=a org/objectweb/asm/Frame.merge(Lorg/objectweb/asm/ClassWriter;I[II)Z=a org/objectweb/asm/MethodWriter.visitSwitchInsn(Lorg/objectweb/asm/Label;[Lorg/objectweb/asm/Label;)V=a org/objectweb/asm/MethodWriter.addSuccessor(ILorg/objectweb/asm/Label;)V=a org/objectweb/asm/MethodWriter.getNewOffset([I[III)I=a org/objectweb/asm/MethodWriter.getSize()I=a org/objectweb/asm/MethodWriter.put(Lorg/objectweb/asm/ByteVector;)V=a org/objectweb/asm/MethodWriter.readInt([BI)I=a org/objectweb/asm/MethodWriter.readShort([BI)S=b org/objectweb/asm/MethodWriter.readUnsignedShort([BI)I=c org/objectweb/asm/MethodWriter.writeShort([BII)V=a org/objectweb/asm/MethodWriter.visitFrame(Lorg/objectweb/asm/Frame;)V=b org/objectweb/asm/MethodWriter.startFrame(III)V=a org/objectweb/asm/MethodWriter.endFrame()V=b org/objectweb/asm/MethodWriter.writeFrame()V=c org/objectweb/asm/MethodWriter.resizeInstructions()V=d org/objectweb/asm/MethodWriter.noSuccessor()V=e org/objectweb/asm/MethodWriter.writeFrameTypes(II)V=a org/objectweb/asm/MethodWriter.writeFrameType(Ljava/lang/Object;)V=a org/objectweb/asm/MethodWriter.getNewOffset([I[ILorg/objectweb/asm/Label;)V=a org/objectweb/asm/Type.getType([CI)Lorg/objectweb/asm/Type;=a org/objectweb/asm/Type.getDescriptor(Ljava/lang/StringBuffer;)V=a org/objectweb/asm/Type.getDescriptor(Ljava/lang/StringBuffer;Ljava/lang/Class;)V=a org/objectweb/asm/signature/SignatureReader.parseType(Ljava/lang/String;ILorg/objectweb/asm/signature/SignatureVisitor;)I=a org/objectweb/asm/signature/SignatureWriter.endFormals()V=a org/objectweb/asm/signature/SignatureWriter.endArguments()V=b asm-3.3.2/src/org/objectweb/asm/optimizer/jdk1.3.1_19.txt.gz0000644000175000017500000037210310532002111023172 0ustar twernertwerner‹3`Ejdk1.3.1_19.txtÔ½[s9’ú~"Îðƒä'·Ý;³»áA‘”Tm^4$å냢D–¤Z“,NUQ¶æ×\ê‚K&¨¢ºg'vÛbáËDâ–H$ÀzÅ«ÿŸâ·ñá°MÊ·ñÏëÁzEz·Mä‡ ó³|{ï“­šþy%>ý¿ÿ…Mù˜¯£aÿ'ݧåÿw6±±Þ|¢±xHÊöÛ"Û&go»_oãêsºMËç·:èCæË2.“eRz3¨,“5RûFeCÒ¼*Êãœäi¼ý”äEšío¢Šq†Ù¾L~• ªj¸²YFå’ µÿŽ´Ñ«´¬Ëô‰µÄ70Õê([wɾ<‹ºÁÞîâf1›†Ó ³M‚¿Žóx—”I^É¿÷o—ežî>¼±?alä_U%Öyk¨* æ'Eú¯ä,ŠÊªÒ'M‡¥¬bxËbÕ[“˜Z—Ïã’ë29Whõ„@ê‹Bj×TY9•*ÖøDHê 虦ÃôXÓ…L‘5Í ¦ÉšU¿©Rp‘_ê¤ Ô|=L|ßà„ò²z@“¼Í 5Ó$7ZH… 3Ù–ã'ÖR¨$l“‡¸\?‚ì6ÿ{dÚ©!'·u5_Dßæ³Õ`§/VÑKe 6ÏS&”¡go"ÆŒÀ)Óß»ãîL±a,V5ÆÅ&þågSalnØdí×y"†½‹™Žt°<ßfë4žÔÁôS*—»ìèá©#],ãí1q³ŒE¼ÙÈ_\öIZ”ɾ÷šð>úÖ†|Àrdµ=%Ýyš#`{xŒ‡Ùîié:r8xòr1t&ÞÎÙPÁ£åʃà<¢™›ƒ+]Èp³òˆà ·Iœ;2È×ÎÄùSâ ¥À8D{'½+™çt´.ÏÞ•>f·‹›ÉØ|ñ ج”ÇâŽÉÛO­ÖÒÆè„1.·ïöl€í×|¬OØ"ƒ‹.˜z‹ËÆjn¤Ü°|;̶Y>e¶Æö)i‘ì7 ·®Ò}Y¨†j“£i€…_ÎÞ\8A‹ãÖT€:æ1.¹¡ä%ÿ<Æ[Í”*èCk¸­»Þ¶þ§jó­"P‚"_§^Ô¦( (Æk–$ö“mÖŒiÜ9XjaÔÕPÝWØ®Îa-K¶ˆ‹R›Á$7ù™Öá­¤7fÚç<3hÅÕ_ùÌn̸aO)ÆN@‰@>B=ºd+‚»c™›ÃÙ•uäÿ/ž¼gË‘OÞÜ=à‰BÄ×<õ5K}­§âdµZ¼&z…ëdˆ&ÑAe&9¹ü?XA €²˜ Î'ãоfméÏüÓ|8 TÊU4^ Ã+_«¶¸óùÍläë&‹ñr¼øÄ ñr| ž‘(Ç_õŽ cª¨S­iT|þ@«VPã¹á92´aFÕƒ5þÀýRa$Õ¸GJžÃJ/œéFœBÎçÿU6ßnÎÞ˜5QðÅïuž>1[yÄ4T´/3¥fkR¹ëìðÜ‹˜S]¤ÉvFzŸ'É,æ.)Ω¬ûto¹éž™…ƒ¦Çm™®…ùà48¤ëÕô;OºÖoÛù¥q=  `iUÎÒás~ƒ¦x «mÏ>JßçÆò  k€£mA†S&ð Ù-³ŸûÓ±»J7›ä„üŒTÚ}§¬BÙ-D{÷gxŸ­Å%§°y]ð´>“¬({qù‘<¯ž€(“g:‹ë<)оLÉ6‰ûqÙeÇ"nÓõ€Í”'†0ÂJÌ-Y0§1[Øå'aô‹­OÀg”ǧ`ë¦6?Óý&û9?$ÐÈú,ƒ8 ·l1ÍLޱ:P3MÒûô4ÌFIzJvbw+†ºU'ÙâÓ°ãl²ýu’ßgù`6éDflÐìDP×ð‘™0·ˆ¨‚5!bŽql÷Kˆ|¹ëÇÉqÅÔòîÇrš”Ù†S¡¥naÔi5Γòš{«X城ícšäq¾~|ÆX^Õj#í×IQr礞ºrÃ,»`~‡9gظ.Ä?¤“$•eäÄD’˜’‹•BOµ$Г;äÎì4o5ÍÊYM쯘<ÑœõT+o=¹kîÓŒo· –ÄuGN¨(F²%…‘ÞA9Ñ É–FzøÜ„f¯%Z™k©]ÊnoúSâ˜Âð™ CK´ÐR»4A;£á-`ì@äi&TaÉbCúHrž÷\Yc8\*âÖù«gUT˜¿bbE„ùóæVD€?czE²þófX—Ñ$‹ˆô§Î³ˆ êT‹Èð'ͶX üU."ÏŸ4çbmñN»ˆHÍÌëæ/ž|™aqç>ÞvÙ²éºã"kå¯È¹ˆ­|Ó¬Ú›KÖÙ–ežÄ;ç)ï@žx}™ñ£Jx(b—qVО°ÊêŽÛ¸l¦ÆAžÇÏgßÃ[%òf¥H]øš]‰³yƒ îþZ'>£¨6õ7CÂêÙßopÑ6×I¾K‹¢¦HÖÇœŸ|:‹tݦêÙ)Tn¹ S°PRñDXrö#y}‘n·ƒM|ðl9c$ká°'qùH€éG¡@+(Cê5‡q`}zù5nA|ø@ ¾KÒý5+Ó)/_ïx-œ]\hâÃ!Ù³ÙsŸ„Qüãoø²5# "ï*""™lüºX$– ½ÖÄÖböëùlR÷o7ë·<Ÿ·L%q,is\›:×ÑÚCNU´ägoþp âXxõÇ<šÝN£•vÒÁ,x,“ p>þ4ž €áàúöüfµr$»øóôå?n‹1ø™n°¡ùê³t$­ã’²KY…oSöØÄ–!Oº=<ÆE‚dpmú/6}ƇÂÊr>g!¸J‰\DÑÅw¼Ï«0Æ ñÐtyÄ@þØHÝeª.¢.“ú>ùÌÛ^?` ÆL/Ä=@ `ôë(NДwŠ ïÎìF¬ý¥óæ»vý(Žmb(8ÒXEÐ,h äˆá:Ïò +aüœ‡4Üãƒ>ŠÔ´'GÚ>Ëõ1«&þL 4Ã$ÆÓ ö”é:áÖ7–zŸæ…è€Õ•3]0àËyWúl¾X]a‰Ëù ž8,WXÚç1ž6Ï µ¯¦ž/æ‹ñíE´X®n'ÑlŒŒËídàUü8„Í—ÑléaÈãÙ…9ìS *%`*>ÂFìÕƒ¥Eti$ÂÍä“—É'¶p–5.fE…6ß>:!œ¥m—ë™à,å:›"(Îc'OË_Ký”ƥ­Îí-*ËCžÜ'yžlNÉt'/Ÿ’%Ÿ“Ä_ƒmú°çN¹/0Ó :‡¯ÒýS¼M7|y.>Àähëm«¶¯ÔÜØ}L· #~3Šn„1rG ›3à±,³½~ –üöÊÎR‡5ŸUApvö*ÇÚ Eñݨ=œ^»eïOh=••ô{¯W‘°.TçÚ=üª»üCûü}ƒQR¬óT¸hš“»á5»É¬Št+Î)ÔðÈ´Ú©;)Î츻ÓÝ”–ÊÒæ fuaÄÉÄl/8%Ënw˺ЖLUÞµ×ÁµŸãªîvñ~ƒ%×îH;ýÎX‚ʯü ¥èò‰Ë¢ª˜Š–ÇãÚøi’ oƒƒ™b¿àõÀ#6x’IׄŽ$²,Ûe~\·¦ Y-rci–•éý3(†˜vYkÒx5š&vÁ»¦Ò'ˆd&µœzSù¶^¡¬««Bzó¼÷T'½ÉJä9ÞócÎjhJ{~ÊÖfÌlÌø`ï™+F‰9¦Ç#×,ȧá*‚ŸyZ&ÒÜwnÁMo`R±ê ìyé¬5BOA×jÀáßÆÌ¢- ³M|ëdÝ9ØYÖkYwò»^ÓúSÍWhMXb˜3KõžYªDÇÌ¢×Pl»Š.óøð˜®ùÙÎûôáX]7‘vÒô-¢é«Ô[”€L ‡¬(‹ùvÓr)ôó¨PcöJuÅ9GC¾ñûúTßÁ † PIyBSàÖ6“ Œý1J:ìÑؾà‰Q§ñÃPya†}0 ‡S¹K–§qê¨ Oâ}Ñ{F¸ïÅIOð¼(ôá~…8Øë¢Ð®“õy ÏwÅ^¿`ÊOÀ:âSš5÷tRë"P,~(Hà±³U%ânò ¿Ë~ózõµ›Qâfi&n¼mœT)F¸¹t=Jça{gTH&RáåœRáLSæ^ç”_¸N*ÛÎN*¿¸U¶]œU!-þB`}DP²ó¬5j”ék›Ÿç%<äÙñ%¤J´5”n.lêïÈÒ¦í‡øâ¦Æ¬«?|®³–ržEžˆÇX­4¦ß@… ›ß ÒÇ'=/Ü7€·§™KÞ’¡ùblyº-kjl‘¨ ŠCPmA’KPÍ@4ù¨ášõNžlÙº$©¼?laªÞˆW-ZR­‚Õ0D½æÁtê°ÖçñãÊ`pŸÉ€YT±à=¹œÂ5Ù0 rN6TAîI“ª±½B­²÷dCÒÉA©4X°‹²Uýж<Åõñ»èÚ;Ô‰Ùê6—ãFNß,ªQ^u½³™º&‰P”K) ¨ •…FWS1 ‡:ç0ÂN+Ài²?òá[`ujKã므lÄ Ðõ!‘]/Ö¸æˆÜO»àë’iÏ`÷r:„Ý™vX 3#/éÂ÷Z@³é½ ¤§×3 ›> Î.=«Ï”WÝ9dDWƒ À³økpÈ"°Iw/•¾äFìÚø@]$¶ :,M¥íÔÌ‹B?¼i ÔgQÖpñ,ÎÔìXC©êÁµ–ÒØu[S©’÷\˜4¬N²ÌQËv²åNôӲ§¡î´ü1©;/ƒ”9ÿ)yx² ^85¤½PJ—è¼jÕ©kAÏ 'XX¯ë«ÕOÎ…V–®sòãß:nÍ ì³Å&6ÿn¶J*#š–AGtˆô iÂ È Fc&/Ø©|®o9ðZØßë•|´ß$¿ìdÔΩ–u#¾b6M•ŸÃ’ˆµøÇoµHp­¢öy ‹w5-jÔ=…K…v/–5Km&Wô´.U££ÝaK¤h¯Ör˜c5RH„žeQˆ@¤L÷¬«@Q+„Ö.(ñ±®ÀFš¼Ü`»Åš»6ÚDeQ[-ØÒ³rãÃìAr Ã…©Ò‚š´“ý§T]?§±«@{QjÓ0+Q¥é`Jò;Ot´îª&ê`ÓÙSb/MÑïá–™Ôô{lÍŸÖz;œN¡[VL§»ºl  ¹J¥"çÿ]âµób [>Wúþ¸k&®Â,—çÿËúòõ›sýu8ô‚.ƒ¯^? ;XÜR[}½ß2鼘‰dŠ`ŽO^Ì×áÝ0÷£~={1¬x^ ¯./èjùÉ™,½˜áôëG È‹y?œ,¼ ß) ÿ €þFýúO è¿( ÿ¦€Ð94¤€FИºð€†ËÛÂÓ½¤æà0{†8qõãøFnÁ°UMà“´¨*Iw Úz>ã˜ïúì>Ïv$`™ÉÚ¤±¤bY•ð'`tcBÍÔi‰çK.Ϫ®ÚJrGëkh‰‰†Ã[sV†8X2„Üùrg÷é–}_äöe9æ=G“8þzþ—Ç $~–w¨EUeüŒƒ kÑ |f•“·pŽAa@ÝÃâëìðkv§ª`¯ßùm<n9ð P÷¶iyÔ/¥àö±ŠVŽ÷ü•Ö×ÜäÑ6ƒ Êü¸×–BÍÙ[–ßÃÊò»( ÿsæ+ÏïËó{÷ò•æ•æt³“7â˜N¼ö÷™xÿVÏ÷d¶…¬‚ù´wp(ÆÇFÆg~ ŽOÿ\k—PÐÃÉ`¹¼ï‡p£hy=¬9¿YYŽ?EÃ1Ú6Þmðp>™/–׃áx8Ÿ}/–Ñ|F œ/W‹Á"Îl0D6Npº^¦¬Gú[¼­ÞˆÀã (ÖqDè¯gpñ@”ò2‰,¯ by®¶ 8Ü=ÿ #i@1‚‹> .ý`(¸„¡à2†‚‹A . a(¸0„¡àò†‚‹D .a(¸`„¡à²†‚‹G .!-¨ð0 —ž;J‹Ã6~&¢¥Û“ž¤ûDèà®(sfLá­9I$àFÇFPQ®“œ{&ñÖ\$[ñˆ¯àœîf¥¬}ÂÄeu@ÞdU’meo¦Ð’xC¨îUvþÛ*~ !ß‘‘ïIÈsþBOŠ÷%™`µÒ°«l@+GÒŠÆ‘´¢ ãmz'›—MÉŠµî1ÎWqÎ$xvxÎÓ‡G":ßpK”„%Oé:™Þ?ð]øŠl“li–IY2«¾ ‘\Æ»#­¸ÜL ö–ËæÙŽ_ôŸ–„B\mr~¿‡5Üí"ŸQÂ`v„”³Åã™7¦¢{½&0éqíj?xÍ5ž#³ùëÈ~äÅ6~ H7÷Ç{fH³yÄíM’h>kûaƒ’ŸwÌ%`Œz?A´ÝÊY’€òûê=n²”´Ïo¡Ø•äO‰¯où“ Ç£ ‹ÿ/_¿ÉS_<Àu3³¸CùlÚö.d›%c²‰óºVñ›žR¾,ß4{«Å#õa]7?ë¢l"‘,‘|¾Û»×·Qu×U+0¡³u¿ÞÈ©s­[Õß-§ñÿfõÜmÍšðt¯þ“ÞÎvØÆ²›à‚DÃ%‘wô1avÁ»=®C#òàîÅzé¥r\DþáE5K¦ÅÜB2¤1™žA!†&‰¿™¼ÁfÖ—gØž¯BÂ&<6ÝòjôBÙ:Ç+Ü dv?ghhSèpYf —g‘§d¬(\k§cf4Ç{6ÍHVYKq O›>f9»‚HÍhéÏ(;${ïÌÄFͨŠÙÉô§Oì߇d3 öÂm!Ó'8òf²6¼¡ìœKxTîëß~û-°n|›ÔܳåHv %HiÆ ímà fáJ£&“ÚÀ­ j,WBøªqqyÞ±9å‚ïÓN¯ç³ñ̹±Ë±—‹ñxFFŸOnÆd0­-dï¦ä¼Â[²¦ŠY÷ÿÅÀ$4i¨°í<¶»b”vŠSéCâÕ……å¼F~òµ¾n¹“Ÿwp+åúÈÖ#?@ô÷[_smé+¿Ò½ ä¹[ºçd»Í~¢%ÉÞúº‹˜[ß×ϱ ¾ÛíìÆÒZ~}Š!ì}þp‡¤ Ÿãíá®°>¹Îß ÀÅ`¸Òâ8äçò±>¥a%Á‡w%URH#]ܱàípEæMÌ(ÔzzSB›˜]ˆO›èJu$}ÃӜ⸅u¥šo-Vý[Ãã(W"öq´sq'˜4à½IaÉvÊØ©ã„Nô””_~‹P¦Ñ^!¬ºŒóv$Sºdͳt:$yë•æ©‰MÚ^Ì"?õÕò\FÑòžjW=K)3†ácÇ †m²géR΃"/ãª,ÐP¾Æþ¦`i˜pfÎ1J̧3±C¤z[½‹PëCv-eÊg+‰>r¥£-ØPbf›(ß’l×&¼™IƒûûtŸ¬Ø,Zpo¿Æ­Z®_1[ªPûï5Ð:ÖW—Y°;Äy²_?CzÀy—G¨9x  ,*ÖØ9“‹ø)Ù¬tk`âL­gG«Ù“‚Æa“‡¬H€iWƒÕýKðTû—•Ÿ|FXά&™\Ãä¹Òù|ï7[÷ì=9‹ ûw§ãgߤá!4›·WîëæCºÙ0ËÀÌodØúé=/P†W±«Cwf¤VFûŽ"ޥ“__qg‡$/Ÿå Æ%w 3LÞÂÀ¬äEVn¡/³†1Tï5:%ßnw:eÑ啎Y]ÇÊõÂxFÝ3÷»Dû:Ÿ¨3#ñ rÎÃGí‰ÂÕѧ+ò$[Çí‘Qq‘‹üÔ½îÚg«ü÷‘/AS2;×?øƒí»˜ÈâØÃªÐXY~‚P½p‘åɉÄRXõkxÌ‹Lw‰/¡2U|,6êI¿œÿ¯ íjÁ¢“ Sqh¢°xé¿+T”iQ_wd8Õü¥« M'©7ÇO©øžcMœ#_ç`PŽkùN—Zíb§Èô?Ò4Ÿ.ç{Š«v,ɲ#Ã~Œ …‘UÆÐ~zÎA¡ Ô:˜Bõdq K¼Üç}¥ ”ñ`˧‡i6(íz?åä™Â*_åñS’qø ËùI€¢\Lï’߸dèÅnZj'súåø[‘´•+´$q-ø>¯VL°1øƒ¸’WþÇá­ñ3q¨/ÚOøÆÍEú‹ê1èÄ®´5 *Í^|ºbkb*…c1 Ã‚“.œ@Î}œR.¾}Ül.¾½<‡.ÆÆªˆê=ÌÎ|Bœ³Ô/ SÂBÎaFS¯ ìy%v>`šøppøw^ý¿>ƒ_¦›òLyLx¹Á¤ûÆÂ“ïšu B‹WÅ–¸;˜´«>0éA{¹„*³ËV–Ë!Úqøó8—£ –¬žS+:M–m¤ZeTŸ|$â} *YZ|âkÄ—Æ’«»¨7¯œ _ ±¥éöÙ‹u{¸½nþ +ùþÕB ëU*F¼I 5«×ìÈÒÏ÷|]Ž–E梨¼ÍÑ¿©À­ýÄ$iácºA‹Òa#®ÓŽ[—ÈN;ŽA[f5U¹8eЮZøæq½%ÒœT ðLºDU2Òwsºo(A”¬ LMëa² “VÝd²Îa´‹3þ–¾O¾óóª„W BçÂì,Tà–RÍ2€¢Ã¾Ü«»P‚vÇ8i£ÈþÀ#?6úΟ8”Ĭ𴯎´ÏÜ%êH¿ŽQÀ%-¹ö\ý€Ü\C„4NÓb~ˆÿytØÂ?þ³ª$.z¨nž‡Žtí›Ç„»NTíÛÇᄃmú°ç¸/úI`ôm²IüœÍ×@[íLmÞ2쬽¡¬ å‚sÊïÉå_ôêÀ;œEC28”×ì("þbdÛŽ¾ë@ñDnWIüô,é›”"€IžÈZñ$ÿáIwN æ=ïUÑ]rë[ÑÂl¼1{TÄ¿~ˆDÕÀºW8ë˜øzg›ã:ÑJ¶^~Ú1Í·an !)@¡æwâê2óÝ{ÇÈ:3Eâ)Üd„M?¯„Ç:ô mm–È×—xo ^ÓŽ?J½Á›Ç‚ "1rsX,FlY•>Uûû ×~¿8-—ëGâ“0ð“ÐiEù nèa¶ïõŠÃãÀ {ºR7ƒ¹TY®Ý5£·nùI02ø³¢D)áfÓü@ø,>AñUä ž$‚íd¡j\k¯Ãâd!Üb¡*ž¾Ÿ‚óÔqDQOË|¬öž¹÷ôL‹©°á,cÔ»­–‚ö ÜlÅ© ‹7fG±jVv¬Ò+iîêìÉ„‰¡ícY<´T·('`T‹£ïÁ¼t A´Ó1åï%Û;qöë¿6Æ-扙žäEe•›’÷BFº£ô-€psÓßÖØ€w è›Õ(ÃYµáA­³x›ëLºÐ< |C ßw¥M²æü¾´žìáÕž_ ?G[ó`*æP'xèÅ ƒ9´Ir væÄLœb¾Ý´È3ȪL•Ž<õm<…Ð' |ö â%§Ê>ÅÁß ëOdôfI€.j$I?’Ü xÄv Éx_jZ—Dó+µ« %ù‘<ÃÕ…ã¡‚cÆøÚp«*Ìqû’2·ÍØØºÆ=D|ªrc²ê¬Ig1Øâª/ ò©Êñ˜W¥¸,‡<;@{6_9u,1ºXܨ«¾k\Xæ>£BÓ⊡ÿÅ:S§Ã'É}¹ÊŽvϺ=Vµ€¥ã–¿Qü˜¯“ó#7û{g„\Å !}ݺ`JÔÛ—¨Ã•‰ÎÛ±û›[­ƒ NºÃÐÀ"wÿ¨µø`o V—õ?sÆÛÃU2ØÕC]ñÖ]Š–ð{ŒE¸Á7ˆ4†Ì#×öçæén´îlËѺ3N0»™™Sn÷¬×Íþ[‡C¹'È6àÌn`§ ß­P&ãZ¦.ÀwÞEÂ%àΧ`F¡w>…dÐíŽ ¬Ë}’ìվ駘¾vRˬéØ5š}d¸ç¼ÚÅ¿¬“¸uš0á9>rs­Æ r§6aù뱺›¸QÒ}èÄ:OÔ5sçÚÞ­!1O²U p}’RSÈêļHªºNr DVǽL„ÀT~g„h ˆŽ1ÿÞЈæâíÙ TÛ’_`‚4­»Æ'YÀ–ve{ž:8 Ù0^C8Ó2W80]¸‡Õ•ûãgy7QϦNÁã€3L ­ ~Â~b*Oþ˜RðÓÆèliqÊ ¬£ŠÛ¬ä—i¼gÆw¢¡ÃÈ ±(f}ÅRñ(åAMç§_ü¹¸P´3IJE‡†È·3{7ºàùÆéD"¯Ú}hˆ<²B䛚"FH×xr·fd…àåúÍ$K§ì÷­eÚ5Y+ioÉC««O µ29YF¾ÜÄÜÿúqB†§‰²©¹Æ¶ebékõn>„Naµ í*[&Ûûj®¨š@Žê}}£[`¬~=]EJV2töÌL«±^¨ûËæLHT4dËÀ›NGrƒWøF÷¬»ÊmÓ~ h|“º{ÐÐ ]÷¸1i1à7Õ•Y>¿‡û ¢6õÕ•?m[ÝAì’kVë÷󟺖õvþƒØ¦ítÖ°ÈŠ²/=î#D~ŒY³*iÂFøÇ‡Ãö¹û&oͦãvuÛ¥;lWŸÐAèãJqžÎÚy»·q4¹öÅÄIÇ×ïœ;"5†-x^ówBgÆ%„Zú/4åM—7rׄ@ß!­ÏOáNšE~Ô_£h®Škã=¡6ÞÃþ»:1,G~¯Fã‹ÁÍdu;¼Y,õw7eúp1_.¯ÑE¬Æ_pòσO\~¾]Œ—Ñ·1Žû3/™Ÿ‡W À+„W†«Ál„&NçŸpJ6÷lþDžÝË«‹M«¢4)lDù|°ÇÜ«áÍ’_|‡eY<³eÁnxd3ÿN~8Û Qšs7DjeÜ }aºKv§»˜Í ½Š·<ÞõcÐhhOžÎ´@*ª£¢JþyŒ·àŠï[(µslsÓJB¡~Œ‹G3Ð;¾ß*ÁÓ¢Ic^„®%€Ù¼tøLÈÔ\n‘è[Ïà)UÎrPôšsø5úOeÍB+4ÈE]„ô`#W#Tò³é¤® á .]éÿP–Ûtj±e<þÅ”ê¾éÍÆ¦1M÷ñÍcŒh[›õ6Û'°ÇÆK»ÏòhˤY vf+Ó“MNÝöŸQË–êb–øi| û¾ZŠæ…‚\òs`í G9ブGË©âÏrªò¬sêJáì*{݆ä¢7T§_CphM*?si9ùyÖýu5ÐÕòz<Œ“¥é]Û›ÈãÉOûÒÜ‚¼„¬ –Sƒí`/ªm]„ª iwƒ^eÑÁœ×$hú*ºÒ„Û ˆy?e¬Œn'ËN­P]’â’ÔϤ‹ÿ@­¨ó¸^´6ôN³Ÿ`ƒŒh†~CÚÏ~Q£»õÒ0 ¶]Ê´Xe?’ýð1Îφ„RW¯] "¤Þ(Óœ6°‚ç<š>÷ètä‰H'#ÏJ Y—±æ`$¬‹+¦øËf4„WÀ”¡ö˜?¬Æë8™è|äƒ=¥H‹ñîP>;Ö+0]û@_Oõn”dÛ¿n´}U1…^2Þw‰ý ]Ÿ)DçÔYÿ™ý!H­÷#=|~dsÂò¯¡ÚŽB»ç?YÙsQ3>îƒX:¿Á²ºÅ^ÑèÐSա˃MŠ%‚LÑMÇíºÔ³9O`6L ÷AU‡5ÑÊÑ."”ßZŒ¼¦AÇÈovF#¬6¤P½v"y‘5/Ÿãç‘9èCæ]î¹+߬hKùîµê]%í²M¼µ?—i ¡$Éá|›­è1çUê]\4ü$“8®TªCkÐ î–Úƒ~ Àzâ¡Ä´¬ñ.Šb;ʉRƒ‚®ylz~\·7+ZäJŽ*5-¦¼ßé^ä¦K”2”‰Ïg¼oÒ¤(j4­¾Öí­ÊËG~Õ $žH€ÊÄ{x~<”õQé&ì7#yétu.ŠÀ «õ4q \ñ‹Z`•ßÀ G17õÕ…¢8„×íñºÓAvh=º€ÒºÌÈæªµöÓC’íÚïïueU£¦›òLy7qIN5XƒŠ¬“¡5¯•:±“Ì‘`P/I·éâF&VÖ³7°¸<®¹zë°¾&î·ðHàÙ,ŠY“ å¤íÛ)Í n¶éÄ-¥!\‹ýæíàXfÅ:϶Îã $yÍ/Êí±}Üüi_‹9ÚêÃN…OP ;®¢ùìv6Ÿ °áüú+Æo¡ r»/¨ðI4ûH€-ÆãÅx6t²üg£óGÜ.“¢<æòŠ#™Ú^vW«I$nb*|¨ û°ÏUøÐ­Þ 0ËÓ‡tïCÉ'Õ|({m§£É:{س1žˆÌ¾ª¸!€˜1(7®”D] 0Í‹‰ BÈ¥½‰ÚwÆaÔ´$”L¡ò™‹SùÈ ô‘ó+Êâ²=¡$ª:ª>z©ËlçñsãmÁv{\´ivU= ä+ú¾4‚_±:{¨oTjNy·Òz¿äÅ4B^Ï6V—ˆP6§°¶‡/Øì.AÄß8ù±HèÖ‚5Ô;µ$`Œnp…‚>¬Ž÷¡"ŠÞUàåk07êD'ß-’ÃÀ1s(¾IF¢ª¼RV"ŒÐv"õï¾¹¿ ï±&²É“^_͵»ÆB'<î;“öŸ¤tfçLµƒ«lz4Kk(ȱâœ3ôüu:j;ÍŒ£õáh-šñf B\†S›÷¢Yð§*¡”Í™eAR+åpHö®¬½“Šì”™¤BÖ÷e‡çQž¼À©¨Up’î€<ëYFΜåÙû #¶À¼ß:êðÞÏÀxü†¥¾žÖÏl[ýgÃïN ½kÎ`ÑÆTtUª£T,m„9×nIêŽ:o¡C ´«þÓzòÒeû¿,û þÿ¦ÕîM^îÓ~¨}Û:ÓCÂ7ŸMÐu¢·é¿Qc`À%o릮^XÍÚ®E}ª7½„¯:ºpt[UŒIú§ Öí²¡ë=îh«WÐM–š ºÇÙ‹ÏVã…5ÿD ¯³ËñÈ‹s®Éu(Ý^P)-v/N^~ì‡9|:2FWðVÆüénnn 0w¬N!žºõ¢²û{¶º ÔO« ¼à-îÈÐ̪m¶¶U™è'OÁDÙ±ì _º‡–~>ªG~´ˆÈÛ:ÝGjièµit—ÈÇ]ZJ‹äAèЮôün~㑺αó¡‹$ÒÕpä÷Y¾Ó”…Üÿ’ª„8éCÎynHGz·‹Zdóg5 àPÿÐn!ׯ¨É#¶n æÏÑO¶¥MWšÌQþi0ø¦Yq Ë Z5KÑo]6—ÚE[F½^{«e#|×Cuö!tȾ\ªJÔ¦O{•eUTo¾ KÕŽ¡zXÞˆqä¥}I£=wÁÏXr•8pÖ@+c›Ä¹BëµÍªú}­º¯ù;ìt£ gáÜ ò“§…x¦ªKÆÖe6DBÄ;aöFŠ_Õ5Má<œæîr Ÿâ&ƒnE;Õ½PîÁWY$@•ýC/UÈXðuC— Ðöë¸~õöš>¡²9fMDYmÇÕI)¡6Ãð…é%wY§ê–ŠÏµu^;Û¤t[«íÆ>¿ô‚ÛL$™ò„wi`Îì¤æn¿¾g*¢ N¬­`Öƒ‚ÛÍÚÉ$ëÒjÛËiºíº9ǯ22Ì¡ìCÞ<¤édij¬ZŒéVL§ºF7ø´ZŽ–|[ùÌPŸ×…´ hƒƒ-iÌ;|6w¾`¬Ý‚þ} ý©Ç©‡yðHmù½ÀXÕ„õÆ•€T£\Û#ô3’Ro µî8È)uàÔäÿJòŒ#Œ¯ê_„íV\-V¿Ø—‹½¹»L–}ס®ÐŸ~¨;™wêm«¾ÀPW„ êøN8…ä„€:”H¦[K@3ÞôH²TíqXÅågU†Œ7YÓ[ÄÀfíÙÜ ¼ŽªÐzI°ËYxzøEq"O±?ü +»“zŽýád²&"Ñ“ 4b´â/†Œö£ù¡z'ºS1Ún“‡x+î‡ïWô±ÚÜ—·»â!„Ûã¢çÂØx>~ìŽpDßÄÁëÏ:¤~j^:ƒSòáE8}î &^wÐïxÒp›®‘ ‚Ñ>žü™ÛâÄ<É6‰OÍŢæÉÔð‰Yò¤‡óä§–½M…ñÍÖJ×qH=p1øü‰U11è'\… 8}á`ã;’€· à#¶ DIp;¨ý~c7qß½GœÓl+Ñ2é¼ r°O •ðOS±± NŸŒƒÎåq'd®ßÙAË8™½šó•ƒDM ¡ ب‚x™±3nvF™¬xÄ6iðyeºÁlôò*ºXÝNËNØpµ˜øQÓñjàG &„ «{/¢ÅrEN4Üõxq1_Lµs³6X:ñXgÚÅû¹޽Ø(G\§ ¶×ÕæoäYŽôcyx5ʼªÏm  ä¤õÞÙë7ˆïõ[6ÿ{,Êû“< ŠÁè›åj:ž­°îÀÃÇLnÆ·öQr˜ðf­n£Ùp1æÄ4øhL…ŸOæÃÁxº8«Å`(‹ßF˜ åøQqóÛxd†ûU…A`-LM ¬t0>²ÕlQ8Q˜|âõŽl,úV(DUBÃ%@-Ø4m#ŠBÚ^Ñ(>z0È¡›l˜ÐõMrÊal3í=Žm–½²Í²÷HÞ—qÊ8è]ƒÂ¥w èºUH°n+¼£"0Ž ±f%ñtW„¡Ò êÄŪ‡ül5ˆfãªÞ8¢Þ t­OL@ê3£чÁú1ÝÚ+LDPRžv¶ Ù9V®ñEW\ÕGHqYxYÉjO£îªö*&!jÏ$9Ý(‚4i¿at‘­Y—hh\h°{þã’ËbK)€h±m6“¬°¯’5˜àÅì¢)‹ùðf‰h j uÉÕˆ=mns7·2a…ÈãüÙòêëÿß°¦êdß(”i±ªË¡;¥-d·Á,вïÙu>ûñUš°êY?>ŸgÇý†>p:|#ñ~e–öVC„Ö…‡-fŒ)ÕCokŒðÄåµøž¬À†nCvÁU4^ 믈^Cá˜ÃÏ ̆ãåªzLˆŽÆVv¨8 º5Ð׃7«ˆ’¢åõdðupM¢¹¼|…Í.©ðµôa×qNhR ¾ØÆöŽ‚ µò «ÍÕéO—Ëþl:¬Œõ>y?zÙRD3ã"šðìÍ>‚n“a䃒lHë/˜;“ªÇÚçí3…б© ð}H„oC* tÒÀ\.×W^äùÍj5Ÿ½#âÞq¿{q?“½+ßžT@^ÓRÁ‚O:Z(—Òø²#ÕŠåcz_ޏï°#5$—y¶%a§I“€ƒ--s†»ÌãÃ#Ì´ÂgÖR:ÐQÎ RºÎöÅq—xšATÇm<ò¹âT0«ÂÇlC5V,’hv}ÃÝxu5!‹›f5þ‚[éY «Ûëù2’#Ré´,AÓÄ"1"ï[öïÒ²L6Lßæñš™Îâ•i!›°§T¼6{©Wøçv^°·ƒ’ÍEwGUðæ=<ŸgƒñíŠ\1±¿Ï>8’°~&ÝKäÊ£¸”Ã Þ qÂ-r“œ·¿jX%#±ù¤÷ž }*HÅ‘ ïf)lèVD”¶ßx•`Ö‘)¶§{µÞ?Þšu#1GŠýT—£+f"š}šŽx+ýð—Q©:>?î÷`† Üó Rí4 \ó}òæhdéø8Ÿ#Ñ(+åË¢*ÜIzð³Q‡œEtº<6Ul¬!t,?ªT×·6䛯FÒytÔe²#œ­ÆSl°è ¸·ë˜åj°Â£°Zðr<WNÈhL¥ì/GrÁgIÅäByW ÔšÉyÒ2Ù²ž$Ô€~uš†!ë.: í%p¹ŸÖ[ìÇuªe[CàÞ`»÷É€)LEó¦U¤&–Z6|Fù˜<“]Ó wG+ É3ø²åbtÕé±cFtè¡"V7†¶0SPÞ’äãsÔjPchˆÕ×k`|këÅx¹ôLU œ¨OoÍ'‹lÄù`øñvy=Ð^‡·a«Á¹3}ÈÈ7„Éë–E¸‘Ü<æ³ÕbîÎgX4júõàfé.ìppÍ7þ€€S­n— çfä¯×ëÁåøöæÚAñSzS»»ÂÕ|êe2öT¾GÌEtyåfà-Ãp>œˆi4»Yºkk¼ˆæîªX²QzåDüæL}çL}ïLýÝ™úÎÔ¿9SÿîLýOgê9SÿÛ]›ãi4œOæžîù›ÁÄÝrî–÷èwÇs‹æL½p¦^ºÇœ3Õ¶=ÔTÛÛ¨¦ºU“[AN©îfœ»Çž3õnõáîdîÙÉ­·œ© ½Ñ¤~v¦~q¦~u¦Ú®­ž¯Ç³Ûs~èaì.œœ¿½ m8™/Ç$†³›éõ`äV€ãVƒãV†ãV‰ãVŒãVãV’ãV•ãV˜ãV›Ó›É*ºž¸;É`ä™ÉÆ×ƒÅÀgã-oÎùùÏä<FÓ[sŒ¢OÑÈ­.GÌ,]¹!¬vüÖÕrÈ켉wáî…îxáî{înwáîqîÎváîgî.váî]ïÜ#øâ§ÞÞy*î§æÞyªî§îÞy*ï§öÞyªï§þÞ{êッßyêï½§þÞ»ëïzÍVlŒŒSš1[Žî5ž¸çm¾%þq3÷Œ{?âãµo‘ÁÞUÃx×2 CX¯Œ#Cðɧòl0¼ñNÀ†Ñbx3½˜ŒÝ¦ƒÀ®¢‰WÙ2ØtÀT¥»Fî|1&äœÇ‹Í 53Šc.æ¶ÍZ¦¬ËºÍeÉu~s>S«s@*úp<Š&w'Àùå|6vO8Í=CB >Í#–óír~ãY› 4_G‘)S¶Î]|¨%3 " Å–£s÷Ì?/ÝÍ|¹{ín~޽CS üƒsàóùV¤Ô¡ÈÌßj|³˜ß.£KÏ øËp2˜Êm´é`án”hÆÆ k–0*^··2ØòÊ;0™v>^øå¾žx<.¢­ÈÙ²žÍzîp¾ð,»£™ÇÎE¹Ë8ŸQ`ƒáp|í†LçÌ@›<îye0s+øÃ½ðL®Y>7S6Ü^ƒÕÀ›ßU´\ú@7ÌÔþVîEäÕ`rA€-æÓÙákÖÖžÒN¸óx˜úðxöØÍo–-ÞÓ?Fã[äö³ ®³1[“ª³A“êµA‹*ñvÿjG oba~ávO =…Î¯Ý Ðk>…øÆ³Û)4àGm|cÝ=]/æ×î¾±\Í݆£8Üçñû7!£^vjP¼ïSp?’ça¶±7j5ÀclÇG4ïFnƒt6wèg4ìAë"-êËŽ˜ÝCR~”5mäªìk˜OŒ²¾Ïœ%-ÔPO'LJ–ã‡.—0¹Q.æ1a:poÎe{öŠîjpÞ½p´[x£S”¾_®‚tÜŽVtÜVYôØW7’·ë54¾a¯Á:ÝŠñ ½#ã|/(Æhx(ʇtÿ'Þ„²«)ލ…hÊ š1Y`ÁÀè 5œDÃÀ´c±8 ˆÆXHø°™q $à— ‡²p#fAñW ð—+Ñ>¾«$®ùøÃ½Ô!;«<}xœwÊV°ŽI[Ay¦^óõ‹žM#_ T‡|õCÄõ­Î—,*q³æ6.I  z&æ5<¥ÅµÒ$Ðô¦¶^à§V¿wŠ`ú$§ÃûªpQ®3ê£ÄuN=´¸Á¨§ŸfÜ ›uϬ¬ƒ;ÝíæÖå†h‹c`G5ˆNS*]÷bÍÄ[æ“ôn’ÅJ‘L¼EMä–ýÃ~åqž&® ®ãÔº L¦xÎ[*„×lE]fÁ@£ÁD¹7× ¯EAÈw_P}*(ïħ`iç‡xެ-áÈ|…›5nÕù©eà\%Ͼ[ 1_Íý no±â˜Ü3 Ø/ ŒûŠÑìmÚŠŸ^*±%ë^‡tu¦¡ùá1ç}‘l¸öùœî7ÙOò„¢ÃqÍ£ã~Š_óCÝ"¡¨Æ…8 ·Y¡?üÜ‹Õi„ŠÖÙž;9NÂl”¤§dÇ=(O1dyt’-&³sô¹.ŒJù9šæŸEAeàx\ I$Xƒ6Œ(i4œÏ¢‹ˆƒàü’òOhµ ò¦Á½ŠU[“¦L5«JÇO¸‹ŸêÔXÑ: »)eÉ®– |}g°ê¥ð^'«§Ê3¸õÖy¿žJÏ’®³ÖS4܉$€¿âa}ï-‘IÐe%2º¡D¦×’Èãì…ü¨بlñK-þ©þ8šYœ%?áò£]!¿j¡”Õ§÷ö§ßíOÿaú›ýéïö§ÿ´?ý—ýé¿Q¾ò¿³ Bçn­Ø¹ªG€a§U—ŽÉ ¢µÊË8k$¿ZAyu‡ÐhäWð€Ve¢k‡²*&橤ªo˜a¹Úl4þ¤ßÁoLUËÕbþ¥ýbì«.J\O±(Àô'ËD~þ –¹9>¦T~l0M¾1âHB©+O5(Oå†F¦LÆqëIDz;Jë0ǤX .±K_†h ª&ƒE¬ö!7;ÙE?8_Î'7@÷­ÒÏÇ—J ©ÙI´\!EIò6œVÒ¶+9Z¦UBrœø: xƒOc8årÎùü~R€ÛK*ÅCDÖgã*ù1ÝXŸ~Y_ž­/?ût•L÷UdÕú–<¸z÷šoï9T7—X »ºªhç0³U†ØkÎÇó¡ eØì³˜[,U}À×v5µßÔU50x9—ÖP5b÷Ê4k’ùV^ŸÂcð½õ"­“íÐ âÂŬ½,ìÚˆúáÕcžÄ›×ï¼Ö«EP>¦Åk˲`Ö‚€Åâ“ð×rxßá E(Ñxw(ŸÜãߥ‡”THšÒ* µKPüÅVšQ~pçôjsgé8Q>&ÿ8&Ú;E £¬þà>ÆûÍ6ɯóì0‹w>¶zÈ N€Ïæ·WƒÙhb›&PÔäkyÍ ¯¯í×ìsöÓ¸p¢C†6ºŒ¨soOyU”Ù¡þ$tƒ ?îý Ãq'Ÿë.´ÝýF\9oýrµ.²¼¹áæ}RËa¾—{oh 7K¹ƒý¬½Bh¢#Ù²~.i¡¶Ü¢>õ£ë®:Ã&¤¾ =>®|CÊÇÉ;y^¿{Í4k{Ò$[ÿðÎ'8åÿ²¤±‡Ô›L(Eù"–Ñ츻ӂeÔ„­þØR}¾ˆVÖêP"fóÅÔ¹Š.¯|\n&ÑØ2š%æŸü¿–u)ÓöɯTÒ2ù'Oiv,S÷U˜äîˆT'¤N¹qyeN¬öÏlóI¢ Í'µTY!G ör™“è:®¾N´`ÐVeÍ*Mj| `~VoãiçÕ¬i’äGwšˆNTwðº>ˆDkø€6w«[eÏqÕ§‰t›cH—[®µ/^gð…†+ÔòM^Q®Í¤â”éÃÉ„uÏ\¥‚¯´èûÍç8-ƒ({ÌÕX%Müî0šæÈ²ÕÛdÛ?Цíõ uTûÉKÇ‹‡é6±…zöÐ~“¿• ÷¥À)Ký¯’²ÓO`()›4‡îÓ-BÂRÊ¡º‹ „jϬkáÁHî ú,”t«ê/Ø*Øè˜~8ÐQû2ˆ0Ü}PæÇuû¾_ˆxVá }¼ÙÌø£ÏhÈ{»$ZÍËtTD¡òr6–2þvU°B¥¢×(ËŒÿ ÊGgÁ»ä…èÌufiöVOpg©0Àè1øÌ õSK*‹˜zV€$Þ¡ÔtߎJÄì‹b¾Ý´1…†Ñ vk‡¾½Øf?'ñsvtnI*(cNIšn~%ÍÜÀÓFzÜ„’¸Z ¢ šoÓ‡=œ´O~ðÔLJø§<¡).•Ö¢ÖÇœ¿ç±TÁ~ó½ì$02níäÈ—¡þF2¯­]b©k+ «+V‡.."ÝÅà“‡Á''¦Cå_í/. âFPJû æIãÀU÷ ë•`Ëô_‰îÞ¨_Èi?ŽRVÏ…q±ÂrÇuwÜ!+cS’ä&\ýÆá …öª¡úéFP ´ŽÃUhKívw›*›çÓx?¸ƒy4œx‹m‘enÀüç^·ˆT„K¨8 ”®=•¨G‘kÇ'»FRBVi4Zß»GvíÌÄSßü¯WΦ»®Ü>þ .,Ö˜æSv§¢üæø"ËÆùînÒóxýÃIk ñ.ÃEÆ_ Ýoø«{Sì"Eù˹‹ŠÁ¾LÙŒÂåð7ER\ärÿ4ÞN6º×…Ÿš;Ýж¶’l÷vpÏ*lÅ·#ï³|÷áÛ7 /þ²GM¢¥Ÿ]ªV–ÞÇŠ#T]Ð~˜ ¿Ü>ÿ8üyé]åsx›!«˜·Ë«h4%û|­Æf‰2â&(¿Í ”p6ŸQ3û™¤ÔªxȳŸ×yšåiù@2¸+²ü.€`’Ü—“t—†Èµàå!*ÙŒú#°8’(¨@’$´H’*¸PÕ¨¿ø]ˆÿ·G7Bx¨ê!*>±…Ȇ¤®ÁU@ÚªÁñæ‰?ÿéÄ܉çBþƒ_=àD-WƒÙh°9A“èr°ºYÀc¥ çÓóh¦/Û@”|¾Ü‰òè‚V·¢¡i›OïGΑ–mj‰­od}Ÿ½¹ð!å#­ïG–nWsô1™,Ï Y-H(Þ¼úšÉ†¥Å’ɶá&=…ÈIú—Ç<ñ#™-sÇjŸ[ßhýê¦úù1-“â¯Á Ž–â“ðIцU…EM$Œ]}Äÿ†ÛT§Ñ&bëá+ ádyHrn"Œ’ûø¸-årÇ/ùì¸_ ¬G´Pñ³ºk†Œ-΢è{ôæ»`’=0¹•ƒ%|¨´Œ>¥Åñ|æÇrËL/•Åò1>$T:6=RŠŸ5yÔ‰ºyC-2K.î 𔺰¸ L¼½Jül­ZKŸY I¥°óp£‰W—RôЋ7ßa½iéÝ´[#i=´‹ÚHL•¡¦’8YÆ ÂÓÂ9¹'ÿd%TW±&]TЧKÓuó´¡_]›÷ëÑ ]ͯoÌN™M!ÛÂDŸÏW«ù4€@Þx>XŽy¹.½âtsp+”\x&èCI: 3˜WØXƒy<ÆÅ£}û¡ƒ@›q´hkù@`àÆ¢“ׄ™!çyÿ˜&qÁVDþņMqÇEz¸-Ê8'pWì]ùØç4Y Øy]ç§“…G Íïï™ñzva÷a7>úF¥¨VyæÔ²jÒ¬1ëfIJîÃê¡}A¹@Vð€¶ Ò}‘äòì ±™Il7É6oS†±ÅtÕƒ§bQWƒ ’ v. ´^7èDcàðéÅN’x#œ7> œïý¸ó¸Høj7b£ë—¿@5\ŽVöšÍ à»?’ò1ÏŽÕðòJ¥­˜âÿ±OŠÂOwÃuD+_ž Ô«¦Çm™¶É4.<÷í@pÙmX;3vð+úŽMQÃÓbÁCVÁêvQUލ`:ljœñMV™éS2 gÜ÷ Ÿ;ÎMÍÿgs€š†_×Á]ªÞFi€«Áåíp:¸v®ÆË¿®fƒ©µäÓ—“¯VÅk€éà‹[†ëÅØ#äteêàãx1ssMÝ&ó¡µ+¨ 9_ZKq 0_¾w7Å'7ýå`é®…O¾2|òUÓ'ÖÚîjòV_¯ß9çˉ»%.—7çNÀhYÛ4àâúrê|²·[u|€á…§KO—îQø»)Îõ{Gc· —¬G:,Wnãó‘»KŽÏ'C`éLVÚ³ŠÀ°NÜ2 †¶ Løó|4ps8gƒß3t=Y\Œ=Y\Œ<uá»ÜxôÏdèr:_x4Øõ¹»WóW$Üêa1øˆø®‰Œ5 ÅgÁ•x×>zóWϦ’ò0ÔîÙЉEL$°§…ƒBE°u |ú=ýv0{ñ™Š-óìÌïÄùhé@{M&!➃!0…åm“û#U3p­P |5„g‚:Û`’0šm‡ÌËálƒ œmn,êl㎠cDùVí¯Ñ!¦3K÷EÉ[tªEø@G .€¾L£‰åªÖ1ŸÇÆùs;þ´ú턌§#Gc&(½_ÞLì)Äò—ÏçOEUàéxÝX%*1™/ÈŒîO¤ö’mAæ{3¡¡÷È0/n4žé…¢`Þa´n™³Ê3ö$Þ4,_ã¡d ˆ&n žŸO¢Üx8/£okÏÙòb¾ðôÖå Ûr¸ˆ®=CKÞŠ¿Cà–Õc¨¡¹m¸ëñÈ[ûOÃ1´Ómòc5¾0Þõpüº? N<£mh#°Û¹µ°5jgµˆ>ŽWW,ïKÏxÒ ^Æ‹›Ùí(ZŒÍûõ|P¶úò4¨_¬,#˨ÚhĆÝô|<±”:–¯W¢‹h8ð ­AÅSŠ!x(PZÇkoþñ -“ŽFÜUøÕL¬ÛëèËØShõyN4š¯V>Õ¦S\.ž ÇÈa°¼òå°ü<¸Æ.,· ôv}ãjŽx­!Üäè}E¶ý«òÓ_‹¤È¶OúQáÊ¥z$¾ãœl¿JKÒÑ»f&«Ø qÒ¢Ú‰oìÀ Xü+&Æ_ªóÖhÖ@h®Á6Ûu"²ÅÏÛ± Qa‹” Bxè‰÷äYtÛjÓÌ «S³vfœÇ鶇»ä>Ëë]©Î\â{¶Šê˄ȖIÎ~[ñP!<„œ‰GllVaW„­42¶n”¡CÀX 2Ÿß€óx ™¾@÷?ÈJ |§ÅŸEÀ޹Qeâ¯ç3(hÖÈ™¢'etÁëaœóh€mº~&5 @†î¡#x¹Ù›íÄG—nKªâ%ºuMÿ &t]û9Ì gM`Z|âêxoùN´xWí´ Õf¼ɽ2žü¶íƸõ”éÝ6ÀG`=“ ãõ£ ·æéÕ¡,¬êï >F°Ád1Œ¾ÞVV0l–UØ 8Á׉Ö9%qÏÏÚÔáã®ö€…§çð~_DûúO1È“Áv›ý´ÏÙ*T£ñÅàf²ºãÕíõ| A ¤_*áºYá‚‘t‰»¢çr,ÓíÛi|è™ Mc›p¢³ïÃúB䆷/ä×mtªÑlÜ}8ÿ¹z~íÌwËò‹ ÏÎ >JP‹Y×N®÷qQ †mE]áTmVd™+üû°_žÉž– ý㜎^ÝÓ톀ã!<êÈrû«#~›íÉ+§f~IÖ?ªÉËi@{ PÛ›a‹švç—ªþÑ!ž\먱³7 _Ì:ÂËt|ßGÇ}Òæ-/ݳÒaøF•ŽÃ£öŒâ÷êW|ax_®²…Œü—R–âÆUËÒÖ²A† œOgò“£àa/ŒÉð³²8Mn.)«n¯áê¬21ý¯2Â:ÊÍB;×îTaì—è!>MÒM3‡Õ/ê2àd¹õãÃÇÏ‹VKÁŸR+MfÝÙÈs’»àEêE8.ãÛ›ï.cþÀèW™Ø½>û>úfjÐKþX¼å¹P¤‘|:êßaÒ.ù2•+jO‹½LcÖ³Å$yJ¶¬ëy&ü¶ø…³ù‰ãå{×ÊwçÞ‹o±X22S¡îÉßG»²˜Î5n‘³ˆÝ²Ù2cöÞSñιV)æí}2´þ"Ë¥²[&Ûd­¼9²9߯ëçÙ¯úÖ€ úÊÌ·7ŒRÚ$Ž88—ܾL yÖêÂu[NG…­óïÊĽgT¯ÆÃ¶Œ *hê¤Ý/ª}A±z'©=:LðšU2× ¸ÓÇå/‰wI½¾9¬Ô%ŠpÎpo%VÓ_äÙ®*ƒu„èç™®ë«QŒ®hÝþ02âõ:)Š×¿ýö›£™ÿT3†¶c \¿­e'\÷bs‘”î‰Yg»k–šê>d9´Ö0{ßYÔ÷QߟRÔß;‹ú;AÔßO)ê`ññ(_ƒ@Ån¨P:Ÿ{èì¹ »Ä6<‚0¯·£"u¶Â˵`«8D/$‹ã^Üþ…þcTµÎnÉ1ÕµÙŸ?¡eéå8gºþ¢—¸–ºP˜4îwO?4;¡oÓÒ ñšÐ–îÐ̧nã> |‚Ö=YÓVj* ak B³ÖÐ0HÌaòúô‹©ÿ ãG cá¡'Ã7I¾ -¢‹ãØ8‡ðõM™ÒôtÕ¹Ž^Ý·7Çã˜sBpάræ|òbh~q‚'Ù9UðÒXC–§Z RÜ«å?*ä»+üÁ;8¾Xâ\ðPíT¡ƒA¾Ô÷v¸@_ý &6©8îíäöòóï|Ùñ=ú~Ž3 nb§rÈl‡AþP8t2ã˜LÄam­b;VÉßÛ©/ÏÆ´1ÄP Îc]XÿYeU÷pM^¯¶³Êd§sb+7©ÛC*Ë-p¬ÈØ®ŽÂN\)ëÊVr[ŠKZ]ü$N¹Ñ•ù€û!Îsƒ°ÚJ‡fvR›ÔùÉ}WO†YoѺ ñá°}®'¯A)eÁ-u–ûàϼÞn&ÈùE¹„Ç þæ“ðÂG5¨;}û‰JÀ5š´mëšG­a–ü™p§ˆ\3U&]·Ö+ò“:>8OŸ×Œc‚ýWBåÇE9Ì“¸LêO¦Æ-S=Ž ÿ'q¥ÛЍˆÉ¯C¼ß ò<~.üÓÎ/Ø›x†Iþ˜møš¡ö%šÒ+Ö8¡£ÂIÝêÿPO–€ôñ]²½ˆÅól}Š·Í<©||ü³È…Êæ‘éÛw8.ÈÙªÕ¢‘[˜S«º™Ú(âyºIçûë:ŽAöFÏóÁ P©…޲4]jõ>͋ʲ>÷?Îx—B¿UGm£¼Rq v†¸3nƒ«Î“òg’ìýMéZÖ~ÞwˆŸ—ËÒg¤KîïÜñ:«Èw»ÊFò“/¤ÔÀ÷ùÚ @WK-]tµ>4Ü|í£dä\X¶8ÿ:I‘Ìo£ËÕü‡'šüÏ»ASËg6Ønûùf•‹ ùFxi?×—1[ç¬y·÷7žEÀÝš¼><5Ü´k ÑgÏ05Ö^uÿPÄŸïÅV='ë¤(4¶5‰Â4DEª×m6uQ-|bkVLqj¹È€]DNª£~³)NΠ|L‹×¿ùPö£Û™ý %@‡Þš‹¡¡| †ác`0C·èbXÇMº>ø¸Få½Q—DˆÜª‹Ñ:oÖõ…dF‹ èúOx÷‰§¸Ÿ—eé÷ &[R°™­Qéæ°z5ž^¯¾Þê7ËŠ„ëÉ š™ ˆÄ·h5˜DCó+ú‰HÅß-ÉŽgJDújq3^}½ß÷ÒˆDþ¤ºù­(Ÿ·öÇô_Ö·x[B ‰ñö.ÿ6ŠËØú8cVú“8ïgIV?œe&ìÒ‚Ÿ‰fÚ:Þ/²2.-‰v1kSs~p¿ÌûDV¿Î ¹áÞŒžYÇÙùÁ)3ßÙžè¯ôòú‰<áBp;ˆ۔©>éI¤RóQ"æ?UØU\<–üŠE[¥ã§;Í—ÊÝà >¹X—ÚØsäS¶¸ðçÊÊ7–foµ‡ª= Í6[èx—nŸ=^\ ¶,‰R­IÆÖjÉùõ’_ûMÌ+ÊÿíïZŽ%×Möü+’øÅ¡h Òœ^¥Åõ6N÷æKÕ"å<ÛnÀ„¨d£k $é=¸þ탛dÍ{B8!ž¥iÄyÁ;"‰>eS÷4ögž– üÎüüXbÍsÊ.Ô×=~±Nž*S R%æ’3ýÌRØæfùÙPÛþ­­yqæØŸhÐOqºåJ[%ûN[‘¿©ª—Wó.wix»g ¦ï‘ùX…d{º\]1^p®ô©(ÞÒâ°ŸYË[c£MUb¾ÍŽ$V\8ÎWô ÀCÐó[¤„F“Ûü¶’dªáfŸòzV¬q@ýmª‡Qßgj˜ï†Í ›?¬öü9 D¯Ü¬í¸“æl÷½@yЮrê¬eU[õýZε»OÌ.¬|Á†¶]Ǥñ(yOã_J4ÈI¹K ^y»”º)‹J‚F} õòÍæÍÀÙœ/]8øEZ$ƒûû¨ò_¤7íÒÓÍá{ñF®"R_œ \ú"¹C¾ŒŽFFÐ¥H9ðù?+ ‰U¢pI|2X§\"W`КliR¹6Ã9€™½»¸ÿZ'#®½ùf°4)œ7—9‚ÈUïßH’Çè%W<¥Â˜ôXÛ´ÕºÒ8ΘÚî€0ÍOÈŒ¡(ù ÕÜåƒÁø¶•x'÷̶imÌÅ¢sIÁ&WY’ 4Ë›§g¶`«pfdQjâ‹; C4ÄÕžD´•ëPË“ŽœjŒœ0#ÝÂ:y –UÏ<Éö0”Ϫ¢çã+QלüíÓ¯ ( SÌæíÃv÷|±zx!fÂ1ÀçV“ ¦D3Źfù<Þ%¯"¦Nܺöy%>µˆÏé~“ýÔ!ò›šÆÆÞªÆöDÌ?31FÌçÐæë"ÛÖì_oãêsºMËç·:èC0ë%ßZ&¥—} BC ê5i/ ½Y,ç +y¸˜/—WƒhVã/(ñçA„¦-?ß.Æü0öf>3/ŸžtŸ¾ü¯³–6Âåž/¦ƒ‰õ9Îgæ·ÕàHK}ƒQ|M׺U->î’ýñ<έïyR¤ÿâ+ ›ânïã‡dgÄðˆÄÂÜU_³Ÿûd#;da%þLâ+6š­†c}ä;Ñâ°XbËì²Ìàžÿ×»S+ ÆÃ ⣂×"J§ÖàLMß§Ç<–LJ<”è“ l‡|‘5 ¬ŒlÏ àãº=ý@Ṳ̀ñf3ËÄ ¡_¾©Ê»*‰SQƒIUÃýÕLìh?h»ââȼ…›h˜ýTŽ•yõ d_Ãm4À>-õø3,÷š]›þ  /¸-ÄF¢ñš{#»LÔ—Õ°ßeO‰!¤rÇæ&)ð6>dEyg|þú˜<ŸmŸ&á¿ßÖ ~ëñŽf»ÔEó"˱²ËTqT¨¾ϵ§¯[“êÜ«Lü9I‹*½¬î=qºírV9„osÊ>šw¶iR–^Ë2@UúÜK¥á&&ätùw@¼yŠFãÙJ¿‹7Æ&æ³M8þ†MÒl¿]“1‰âr</“Šé`ù1~1‰®IÀÜ F¬¸«ÛÅ|E/q-‘(B§l Gß@ªÁõõä+¹±%ºnmoÅJ8© *èÕX{„^E ]¬8j¹”\(ž=¥DBLBqv¿ýæ…¼óC~{ççâ‡üöÞÏÅ 1 ^”gåÿÆÌ‹'ËØá•Y7ÿÓg1ž ô…IPù\\Ôw’àßéPYt:g´àÛ²öŠª‡eY>¡|[JÚò|–'‘sÉ7kN[ôåcÂ,;%KÛ0ã„-wlÙÂ÷ F>‚ãaÃ='Òðõö1¬ÇyÎÌHRת‚½ˆQ´Ä‚Ð5ö+Ë›ƒÊ—c‰|›CäÝà)üË|Fñ¹gH ×Bìl’¼ÚhH~Ùk´aËf'SºÇ×5Çïé g"´… & 籤׀USXÝ{fÒ¸Qg63¯YWÙóîÒ[‚CÎWB§ã'#5"a;$!‘çø`ƒªZÜJ¬]²®}6ó­¿ÓóûŽpˆÐ‚声¿ˆ¾_’Œ"öÁ¹„’Œˆ‚¥²‰ÑÁðB-deK®–M²-ã?[\#S²°r5¿“y½¹¼«ÇuyÈ÷–â[Lùú§:Ú&ÜNE;—|ó––ð¼HøƒPZÀ?HÚÉÝOòáÞ/x!áõ3åë÷£×£ìx·M $+ÿË™úìLýÉã=œë´ 1_CµɯRßϱ!ø2@AC€ák\ìØG÷ó`f)h½Ðb502Pǫæ¼@S/ïà ‚Ç¢¹|è´ï°ÂÐzcš¯‰mQhâBÖ„®äõÁù­U ÅXôê‘ø0½ØfqI¥Ž R™ˆŒQ™è¢à¡á àŸážmd %ý;4¬£¥¼,œC³à#³¸fóŒËG–:Ö3*%Ø7(«A“-–0$u°oDJôiä+ê¸sad¼š_í}‘2¼š/à*~uÙ¾j‘P>cùx†­#»€€åkÌÇUCDVÂ"¶|¨\ÓŽ÷›.”¤þV£h¦þ(Ý%{îïvÎÏOÚ䎋4ÈêShΟ‡ "9£”øüyÅoˆ²zV9ÈglÐG2u ì°•˜‡¸ù^TàúÏYßÕEÆ8Fì;kî{åGºi˜ uÞƒìùyO3Jò„W"¦ÖÙ¾ŒÓ}!VŽi¡q§Iy.˜h•Ð~N£ä¤ :Ð?È· ë`Ý€c½²‹)´ø¬T#ü ²›DÈFlº!ã±Id’-ËE¼ñ`˜.`]Í õæB¤ÆíX6‹|½L „Ÿj÷a}H¡µÃ¦ caŠçGó»´ÅHxI ^Ø€ö"ôÅ™éëÐÈðn0ëcžóÛ­“6É·B¢™ð‡Ã9‰ =˜„Ñ9<æO Ð4,}íHâï¢o¤:Ž¥G›j¹Ú`t¼ÙØ#‰1xq¼+ylM£'Cˆ’_ëí±HŸ’¹­dy"nÊBq,Dòu¶}~ÈöæÝ*D1¦qÐ2õ öOü¦w~ÍruG:,0ŸS:CàÄ*tœ•Ub•´¡‚ièžPÑÈæ[ƒJûÂ5‡n¨P—ÏôKó¯¡3žfï¶Tf¨yÈ0#ÂÁÚg¨CÔ™‚ Ïâ´VFÿ ,#ÓŸÁkĆŽnúµ…O>›BAòäI0r ô˜~”}Xu>½Óè ±+Ô"ㆅ‚B- ½~ýfƒÚ Ãã]ºÖ¶«¡"Ì‘ô®4ðùx2ÿìD°ôñèÒÚvÓ0ÑlÜ«èòÊËgp>ÿäFô I[ôD AÖ d­ÐS5Yôý¤qOñ=Æzè(oñß¡]Ez’]EòN".‡Û±*È'?u»Kþ:ÀòŸmE{Û´&ê@Âòá DÏ"͸°ö@‹ãÝ&}J7î*îQýý38Iæ2˜—0l²íS"¾T*Ö‹¾O-²¬,$– ÅøŸ{.¶¯ßݧûÍ·$ÏX?ýîÃ:]¶0’ìº5„Ún¥üµ–<ÅÛº£oß$‘§:ùQ øáÌL÷?㜿E¡½Ža ä Æ¤s“d¸ËaMs/åÓî“Q˜o[¯Qê\‰ÝÍe²ß\G¯ù/7Þˆ×1 Û\‡À»è.µì÷zë9xÝކ̘ß[‡!Žo³½žo7êúVÂÒ¼M«bÑ•… r¡04UÅÕ{v†pŽ<7Ç(ƒêp¼Ý¦‡Ý;h’Í,-:«‹[+ªÆB€á× ŽÁ¶`h+cHxê´ÐHŒ3„ƒ!ÖÑ ,ÚÛ,0“`A=qx=”rËrãºæoÎîo‚|ÝÍãE€°»È{ûš3¦€ù{š?¶ÞÄRúYã0“ÝŒVzr¯<…c­áâÞÒù»€{Eм¦1ÈÑ |ùPÌ*/²µeâ±ñŒ‡eš+4Ó`ƒÝcЙ(Ф³Xñîæùw>€e¡Z€'/¢Ì·‡Ò þ0a°•Úô°pÕÌÀk¤Z퀙©&1T­Šð›ª>`}lÕ£/Ö‡{“ÊdÏêAuÞñ„].æŸoùe¦D|‘[] CþóçÉ=K$lÓ]JÅ>f[+P²6°F#µ´ÝeOT® JåÊ‹µN09àã=µ"8Ú|ÙÙÉS²µÆ½ Â}“ÙšªE›s 3À1‰ps{wq"f7ÅaÞée†“º• B‡êBÏŒÇ<¹b=fâ5¿€^)ˆ>u¡¿‘á-L¤D=—Éž‘l9±W­ªØÏÑlt;þ4žÝÎGV_°€³ùìöÛx1w—ãË[~côÊ‹âOýúQüžG?jxs °É|iM*H<ÌÕ™¥D,Ô0ËrûÐ Ûw^V ãgô³?.X4‹VàĨ‚Æ_®ù]ßÓÁ 5ý0Ê FÃùlhµœ$›E–í{`تH~'î*;ƒVs*L¼î‡1{b#`>àš{E+¤»ÍŠ„ÿåižøpHö«¦<`QÙ“‡ƒWá«àB{_Þ‘ÌUbØAb•vìEÅô8:¡µ”ïfßJ¾èǨ‘-4ðÀ‹VB×ú’7‘lºfäÞæR9x¸s†/¹5Ö#Ÿ°1CC…¸ìRòÚ¢á)DËš‡ b§bcÛ§ á`W „Ú¾HÿEÃÖ¿‚t+¡>}tÝ܇ˆP[#¶:RÑ>Ë›Bø@ÀöùA¢í6yDâ¶Wè•ÁÅq_¦»zlÐõټ$ö•oX øÃ`ØÖšL33×)ì¨r=Ý&7è­€nƒÞ“ŽÖƒÝô ´oà›Î µP`ॅ ˆº´å€m9H¨€8G¶Ü‘¤ß®IÅ ÚÇsöo솖ŒönìHƒNíNöumÂn„4 úÓ`h€o f nc g'®dB_Óƒ;zƒ<}H½Ñ¡B€q_µ ôXª !;€8 ±Ý ãÎÊeP4˜s0c»&€T i$·@Q(ãØ½ù";Žbýr%jf”1¬_¬Ôm»7ià##;Ž_ðR%JÃ7*ûÊi¼×¢T±àeJ*¹KI…ÀW)©ì&%^¤¤(•2â(c­û(#Ž/âÈê7¦(£‰2Žº  ±ã¹§D¾Ð}D°Tôëˆ(²*Ð]DÞ3.""ã±[ˆ0ö!`ð"Œ±‰^¤VkçïËý;®Òø?üCÎÖäðíCN¸À¹ÇÉ]*µ~ó»ÈüÞµõÝ?nþQq΋t gƒm¡!Mѵ1è™nÚ™³ÅKíÜõÈ'lûN«Mª“¬ÀÎöy£Eó³'N¼‘§AÀ< oä9T 7OãïÝÑåÅöE4²/¢aû"N<º/¢49ìcSfŽ­Õ:ÆZDðæ_Q+ÇÂÀ#n YÖ0»KF£×‰püF\ˆ³¶%½:j—ާðÉŽåš{”¡™®ƒNç‡Vò T ì)h…9Ef7û—Í%|#HeùꈊÙ»³!Nµà¸OȆù•‚ÇņBa§‰ 'hç!¤èÿíB6𦠒ÛÔŠ +ßYwH6TÕêâòqús‡š×‹é®ûÇ À›žTÊùÍêv2¾Xù0«ùµ²ˆ.¯¼|Îç«Õ|êBQ”½»÷îè´d5 YeAV Ž„mÔŒëV2z‚ëv$ÀõG¨lÏšXƒþ:ÉQeÐ-ÉÝF/«¦^}Œ_¢LüåM_ß^çÄýºBºd/éãè‘O˜CÍÈW¢Â‚cKÌÉÈḛ̈|B‹t[ƒÎa j8-¨a}¦ ž¦{ª¬ Jwÿ"sQ¹Êg驌%šÊ[NA´RËÅkW·PÚœàiJîÛÉÜIjÈfs‘g»QË×y ¨ÑöÝ=sæ"»Gù*Ê“K¾sawÁŽî}²,l½÷ý‹O;J¡©þõ¾rö“dk‚‚HA±‘Fî´ÃÀä ú˜ðËmµTëf[-ô9y6.4¸q¡!à ‡µêß¸Ðø{7.ty± …l\hÂÆ…o\ð.8:Ý(+o„‹ÝXÐîVö]"`㉠ã|ÄáÃ2ÀM]7\ƒ‘a†2Í9ŽšÍ8 n=ã4ƒ|Ý!'Fœ™ÃÆD(¸ã©N n ØÔU ¤‘ðÂ÷™1L®ànE¨"Àö-`œ_ ¸v0`,qŒJ0Y4ð öt @ IF¨¨ãß½w‚¢Éc’°‹‚’„Œ}•(4«€‘ßn­4c7°aº) €ö:ãaÉ&ÓÐ “œ<<{HhßèÖP§n"¯;ÃĻך7hzÿ|×YxÿzÇ! Úåž³ÃÒ—F>—9IÄ^)Y|j×L61…¼ö²pðÌfÇ”óC¬wElˆõ ±Þ„¡€'Hl` ÝnÃ媩+Â׬VNþ…«ÝØèêÕ‚bKX» ëX/‘K[‘®í¼ÌãMʯ›fÚ©t©xx‡'½G“ÖÙ6ËqJ‘ì ~fåX£ÉØv‘!gøÁþ¢5ÈÅëz•Œˆ0~©¿ýÙb»2ä'#²HTæèÍŽt6Îî}@vi1MñFwÛÐC6±óß²NwñC"3˜f›d«Tkë—îî•S¹±)ˆÇÍ\1q ÕV’9+F°=ÄL¥¬ŸÏ¿˜FP1$+‰ÿ+¸ÛñšðQÕP#ž½íÆkñìC¸MFàÁ‡*â§dã‘j§Óu¥äÎd*¯hª3-Y‘œù‘õ@£BŒÖˆ!pZÄß"‹øá““LóráÍœ\¤ÛmÅë;g™ë ˜t›ºQzæâÃcº.<#Lb b“(u“ZÇuÒܨL'‰x@b+©`êæö©]‰.j´oîlà¢Z§"ƒ|™/¦zÔ˜‹'ߣÏô77øoL\5 NÆÓ¤ÌÙO“õÌÆ 4s b4d}–¸UÚv F#–ð‘ùlÖp å@Ty«¹ZÏ~XìL,ÒϳÃó€u^‘;–ÿ&ŠEÂåyÊɹx LÄ9…Mãq‰-d"!9ÏßG ÌRÚ-??Šóš?Å[Oey œË _{ËçÃp>×Ùö™ßÙÈ´ìwî!ÛSaе$¿ ]Œ‹I`­Â¨¬¹8U0´ í*ƒFħ•·ƒ’}º;–ÉføçñšÍJÿÇʼn£‹³ïCwœ?— C»QŸ|•‹ß,wszßçwE’?±YÚ´°ýüNÏ7ƒN/ñKåðõbrí!;b%ÖƒgoÓaÉî#è„#Tyª{L•y ,ƒ>‡B|‘Ì3OÝ$¨¿ù"›J2IÿWGÏ)8Î6W`¸ÿ×än„d'éÏ÷÷IžlÌÌÔùSŠUri]¡­œ´Ô $˜M|·MàŒò&ý­í“kè”ã#3vý\d]çªN¼Ür]nŸŸØXÐÖ÷ÌŽ~«$9˜ðÑD%L»€äÿ†õ{¦|FÉSºæ§ûôá˜Ë‹)嚀T]uSK¶c9-õÕQõ -G½îRmþÛEÀZ-û¡f#?¸H4×–VqªËëõÇäù ð}âëÒtˆ[O Ç2ݾÆTžx³éFhÄXÐi^A˜ƒwõ®al¿FɳR|é8‡bo]9lMåHïö¥Þ|«¾<T¦ƒÚd‚²Ëtãâøv¿†0ZÜóxýã!çV Í1R‹k©(IT ý7ÖØ‡)Öä•uƒÓÖ²¿×nø7†*·¸96Œ·Û;VÈ×¢ÚÛmý‡‚á\Ò½¼:7ˆÈeùáTùqojõ}ºàÛ äÌ*=ªÊÎ=!ÔàŽRœ¤:õ Ú*¼¡:´Ò 5Q·ö¡7N–¹Jâ§çŸ"ܨ)eq‚æró%·¡› ½aÝ|NÛÚº€“•¿_xj/¨³$I~Š¡l±!u‹ŠÖòÙéÚbMnW“ÒÝŒvɃ[-?M«åZ-ïÖjù˵ZÞ¹Õò VË»·Z~ ÇäBj3“ˆÖd&ÕéZÌäLn0ƒÐÝ^V©ƒ›ëmÞPZé…š¨[ûЧG˼„…ãçKnÃSX8~>§míY8^Vþ~q: çUqÜËeíqÐÔÂr¿U²;pw %zÄ XŒÿq-Æ#?òz1¾/HЛÙl</—ƒÅW?ØÙ u(÷E$E©ûA¿Ý@óƒvq”§…ž°<Y^&ªÉܾ2Ò›®&ð×[lÈБ)xÔLê˜ÇÝ!/íÉm KߌéÌ·7ã®1g^V¶d¼FÉ}|ÜöóZLg ÈwRÓýÃi»‡¾-{¥SWÈÕ×ëñíb°\·Ëáb<žy°×‹hÆÀT4\ŽoÏo..\P×Pª ÜÏû|0Ž Ø˜hT„ìW·„Zµ³Úöj5'·ª‡õß0jYÚŠcWkMŠâEºÏxÿ”æÙžt ô!¾ÍÖñ–}ðÀ\M®âäSp[ ªP%ªNƒó’)¿d/ëns\;¬ªW9†i{•ŸÔÉuŠg»ÈŊɇ$fk"î¢×ËE]š´Oqºå;âïÒíó,Þ)uèwTvÊ®œè¬´`V7N7çñëìLp‹'®×B/Æ“Á*ÒžŠQÓA4šÍ‚Íæ3£óùêʸš/¢oóÙj0qã>«hèC Ç–ê¤^ø„1›3Ü0?b9¿¡00äóØÇÉeóÃا_~ȳbøG`ÖA'×L±$È#[ç=f¹Ã1ܶ^Nʃ9ľŠä¼%›ú¾ø!_ýÏþæà°+BsìÒ=CQ˜IžÆÛOIÎo€»‰Fn4<Ëb0y’B:ŒDËÙ¡AÇíZ°nžÄÏÙÑc\¨ÀéàËå"-£o€.­1ü‘0Gz³‚v¢Öl)TòÉElë®.? ÝŠ¢ý}æÈo{ÜÉ‚óɳŸ²wàŠÅù ŽNS!D SSx¯óÉì-¦JeýàgýÆÉoŠ,ûq<¼ó<ÙeO‰—¹³Üò¯yž>¤ÚbA(ón(›‹!¹ö=òT£=ÒT[õ³æðÈo6ò¯¦ì@ðb` ¡<¡ŽçJ³›ÂÖÁä'Ìgö¸ü½äÑÔ* qý«m?6M…W!›ÒÝqwZžñ¯“ólzÓ`›>‹þ Ìõ"€Å×Péþ)Þ¦¶j’`z¼ ·U¨ ¡ää0y•è².6ŸÀ#[µ8ãÁæEy‘ål¹õ”–ÏgNFÓãE½w£Ç%pXÇä9&áÑæpÙ9œnÎï?9¿ÀÌ|òi¹ÏÌCšvŒQm·ÉC¼mjmÉãÃÇ¿ÖÉÁØÿª€zº"€‡‘c…ê¡„†+Ä.> ¦Ò[ÏŽ”Ë4L($™‰A¶Æ ؇"Ùò»ƒø§iR>fÈÿùÍ-‚„Õ¨”ÎŒËæ ÏòxÇ×ügªŸµI|-S?8+B9ášh¼çkéÍÙ7'MZ$βæÉ:Û?%yén~ú1.×ã']y >¯Ä'wQ¤ še%¿¡Î«yLêd¿QJå—Ó:¥ v±¦wð¯y¶•—ä{©ùIú+6çoù¼O &Ébðùv5þ²"@‡ówKGT‚›Ùr<9EÍ-Ý}b<þ„Ñ÷£Vr×%ï&CRhwØ P® ¸§˜)gCŸã<Ÿ·ž•rü}E‡Â]'´0ê´XVu+/Î͈ë["úS]ŸdŠ%¯UM?óÒPjÂð¤Ó,’“½é…Pðmv¦i&µÓÇ8ÓÃÓ®Rk5ïÆs¨¹ÏïïÙ\¡;–¬lH¹Ÿ:/¯+M[ñu´ˆJËTô.-Yá¹2aª‰ÏwÆõu“Vׄ÷Tl¸8“dÿÀï–%”dÍ í„uÞÂ(Ò_\ z¾¸,Ș&‹2Lk(EEÃ7gžäÛQt­–8jµŒ¢U4Ÿ &·WƒÙ7¨-+è2š^O¢‹ˆMäÇÁìG2£þcàJž\|ŽF««ÛƒÕ€ñr`/n&‰õÔF ôÕˆÓhG‰Üê¯8¤jô¨>]X†•y± IR›ó¦ÈçÊ$÷Ûò&m€9dÛÏ¢‡Œz“Œd×›D¸io"ƒ­{“Á^˜öÃ-¿,ŽßL›ñkyöÚ}ˆW`Æ*4}ÖƒOì¤zkð1Ý$R²ÂËW[®øÀžÕ TÕÐè´&ðø Çæ¢OI’=$"N&‘à q™Dîºi®0¬ mdû ñ›bI{Ü·+O>ÒÔn-:EjYu6 yñ¤·}FI±ÎÓƒçòr'ø%•Z?FÖt ¿Ç¸=ïã]º–„“´(}ºFGM`]h‹04@sºÜ¹ñq´nà/\bfüµ“»ÕÙ ç”Ùü@Ûó˜C#ry~p7;Lò‹ÿKÀ=1N„ÏÆƒÅx¹bÿ²eõù|A¥;&§¥ã‡7ìÿ ðT\O›mÅ`ãQËøŠYú ÄŸN–‡¹.‡y‰NkÓ\§À”÷éVa1ø©oÜÉÝ…¨®¯5?ÎST%[Ùé´êk^<È–l²xàGðwÛc·fÑñâÚôçP<[zÐIàw_>I);dÕ.þ‘ ÖëãNªk å$f®Ì0ó˜ØÐúæ¹]§¿’mqÝ j=O ®Œ‚«„–¿?öe›¡¾–wzq„ªÅºôŽé%Š‘©Ãw13½y@{#”ÄA%¶RuLÕÓ¿¿1Ýtâu^.¨yáÿ¹†%èIm ûŸ0¥[ÅyáéÜʯïÔË&›e¼;l1@M@GÑb@±t.X Ï/î&Ñ˜í«¤AÇœ•d¸b!îÒÙ©rþ~"Σ¸ŒåcunÓ(üøaBF0Þ&<–k`{špäà¾<Ó‘©Pø|ÿËÒ÷*w`&ĹU8Cùó ˜ŽTnAÌÄã“>ްÂE8Ê'p},G!,ež¢‹ž‹2ˆ j? aFéFD~m/:-·‹“rŒ©÷е³ÜYç‘ÙÏÌ 'õºÚÿ¸I×iR¨¤ð ¦®ô•àEþÓÎM‹o »MÇ­óÕÌ…™àeE äg‡$/S`Õf” ðÅÚ5[L·eÊ–ÇFðM"\“Ûåj>¥ £ÙêvqyN…±·×‹1~i»^èïç_Wc*ø?xŒ¦Ê}³¼š/V·ûûߨµXSüL!„º\ ¾°§Âe]F3ýb 7œŸpÿ2æ, ?NoãÑít°üH€^òF¨àóÉ͘ŠL®¯T°hGºÐ~¹ ‹ÍáLt2üoaÂü-L˜¿ ÃÇD€0 ‡…á ‰hºmt`»ä€š³bÄ_VÑDV^ºý¦lõ]ÅÅ£Hóç ^‡ƒÃoaBU«íðeµÉHÌr'ãÆô*_ jB"¹9ÁÖ‹FP4Þæ( Þ„æ«^'H]?O€J¦V¯æÿmŸw¡gÙŸÑ2;ææyˆ†ÓužmŽkR_KꈑðIYäÎï~{,ýú‹eÛ\øãy 4jõ+ƒ¼—aíu¼)ðëžžm8¿1k†cåÈÖaøêÄ ²ÁÄc·Î¾YhÁuÕÓ3ô.Bºöá1M÷_HÚ¿’€ªg+Яe²šw_V©ˆÉ!dÌÐ_éhV&žƒiÀ‘tÍÊÑÚ•Ãùé»/p€¹“æk äò$ψbøô$ »±äO…<Á©¾§)PX’kBzµI¼Ù𚯧‹šèç&c1OÈ0-D箪äÌx*3*8'>ãž;ëˆÏcÜd-vPó…ºrXËæÉ6‰‹Ädê5Îý›*ŽRP’ÜÙÕ»óúkw$8BšWàH몇ÈÏe"­$8ë1hd…d> èkÌ:V") J[Ï™¬IŒ¹òhïÏñw®–LY^¹BšhüªÀ÷UÆ—tzEôãIXîÔý†ÿÍ÷÷¶ ýŒZ#r{m8Í©ëEÿH'AØ¢)  šÙüô%é­x;ÇÞ›ñL­NÄ¥c+Þ?Íd%É–Æ Ý0»Æ ªÝZß¿ŸCc CSÀÜ(VÇÆÜ‹–7­É}@±ý¹Z\4çL(žX­¢[ ¥ž¤ dÈ36”Åát¸¤ ÊGf™Õ”°TTA$Ë|}-妠ù€%Âá&ôÕì¼Pk¶÷;ù8ˆí:‰Zâu߃ù äûÝä ‡·UÕöaσñ[Nº…ogäãöÌt†LÚóè"L GsöþÏÀ³{ÂK˜¹t ô3Øÿ //ÑËuÀ?!PÒî/lžÙ6J’CÒÿÚpº9¼ë òÚgûÿã ìï2Â{ßkøö-lAlöcù×yTfÃhüåë·~S=¿û<Ûý¹9–ÙyôÂyÉ^)4Ò3ÿœ)Êï•k{ Ѻ—ØÃZ%©¾º¸½K1‹W¢öç€x÷üçÉ~m“Qp…|¤Jnƒ¹€¤°/UÂã®}Í •OA¯ BC¡v rÿòUeZÜPX”YÛ¬§ûrÛfñÆ]m,£êæv'ŸÿZeÅ9Û•!¶NÄöÝßILÞýÝy’LcÛ‡¬fõÀóÊ|¸)‘Û»¿û€¬¶'é]çi稌‡ð¨ŠŠªÂU.µWÃWãûˆ³è7ûŠ2ƒÍc,.´#âÞ’æT§ì÷Ю¡ŽŽq©Úáp(nÆ…‡|9€à•zôK3Su®i4?Í‚U·¿˜—ü&w¾=RjMv ?N„ ‘Š`žËÔP²j3òjè@¦Ÿg¢uÞ^põº.Q;3‡›ý¾z;0Ù(ܾ_ИÄQÄèßÇÑ ä4aþ:AXåÉ?ñª:·‚dª÷qÈþ¢¨»Z£«“Š¥íÝ&O“䋿ì:oÉ{²äzݳVwÖ‹¹ö×åë²ï`Þç„Rv•¥‹Ÿ»îÓ½~“CD}‘uOeĆª#N}¬´2<ã4-&é>‰s¦T Ññ]¾é"9ñó=YñËìj©¸aËÿ™Ü¬ÎÞJ:Y!)ZjYƒ–o÷ìÞý]Ò-½“mü¬ rH©µE,gËK0/ñã4Ìk¶/.®¬>/wgíR\ÕÔgú ~@V65[š6] Œ€—šJÁê /›Æ"Á¹«&€–¢n pi “8úi_¢ó˜øwö¾GèŠÎfW$åñÀòFV­6sÂ] À±òñ®%\t-‚ÁÁ§>ê«Lˆœ’_%¿}ÑÉ*D*úRÉÑ,}8„,ž ׇ_H.ß#ໃÊZI‹lavª>E9ÍdMZëù(}¾ò¡+0ÅôXŠÙÌ_n½ͽ>€ð/°òçÒo)ä®–^k"\Á¼ØªPñ®E¾ÛžsÜeãºÂ¤¿‹÷y Ú”€ ~TQó4‚ýqÇo@Bÿ ¢‹u¼gfp—h+ ;^!N_=€W.úïù!PÑéšèoéŠþƒF•å›$ÍræSÍ/u‘#ƒþW9˜w½•«ýöÅb%ª4!Dò§cÇÁK’Ûy;΃²;oJ˜˜ÚP†}˜0åu; CÈfÇf.¾ô]TÎ’v¹ŽÊɰãTîþ~)•›_Ç{©ÜL»^MåæÚõv*x†;ùUX6]ï¨ròëvMƲóMU~†—UùÞWåfØñÊ*ØÐ 8÷OÙö‰t$HÁþHò=hv6ˆdóðxA‹¾oãÑåøöÛx1¿½ˆ&/r6¿_»PÈa¼¢4ê«”t"W7-Ó$ã ?Ʀ_è5.ÙÚöL•‹ú/‰l÷åþbQwMÆÿñÔNiNž¬v˜— ˆ'åÐ-^eýâqÕjf}O¼ óì *3ü(µIºf¿¿PöMfê3 uåE¹oÂ5ÑEsQ““Õé¿ê àâ;› eÜçLpw~UÅ€ý£Áý“­‚mî¢ó‚äux^ Íü˜‹É|àGæ7ç‚ô³Ñø"šwí)H~Œ…U0w WIdbÑêBl íçà̤–téaU-2k(¸rWà®Ç G‚+¸@9£#± M…ßá`o„ŽœUÎG?O¾ó5JóàŠç¬Âç¯k¬–ÌÀªÅzÀ…¾ ‰[sö +9ê9°èÆÁt¡£G$±Þx™Eûêò_À•ïîqþ•X ægÃñTG.‚<+o`¸‚¤àáä’e3o6Ä™=úLÀ›[¥€8 Ѱ\ U¬Ix‚:Ò¡,Q-XŠ¡ÃFL§®Ìé<=”C™ÃHýX’‘߃ tlßïÞ)™£Ûìê*Ü+² jÿ%À ÝWCú¡ÄΫC)}wù˜åÝz¯¤ôtL "ô` $õa€ý¾ ‡ Ãx3´§7K|ÛŸíØI ÁjŸ&zµ¥€‰=ÛSúöM÷Î}CêÝ7äî}пoB:øMP·ÐAð@îþN~ÒËo‚ºùMp?¿ éè&˜„&vu íèëiž¬ñÐ×ñúôC£¢-y²¹ÝÅÅ?Rñà¡ç7Ih6ôÀŸ&÷ ‡RTóö..ßž§ânéd¤\ä ÜÓE¯ á÷Û~âݪžjÍœ½¡B.óøîŽŽª¡U¥µ)JûIaß i"ìÛ#M„¾¬!Ä'D›©8îT¿†}ˆ:¿*Èc‚1eçÅ,!Ï¢zàÿB~? u¿<].ççã-­ù1?ÊR“b5ùA^ ëF'¹²$m"å;3ke­pá\V• y)4t|— yÛÕî@Q Ð?¼Xfž•qy×!&Ýt7øÖ»‰ÔãBœæ˜Iª2 : «7™ÿtŒ‰Ç¥˜ÈiLOÒhŒšH"’G¼ÏqšŽÌc3•N&Çs8ÖŸ·xR¾Mâ'§# º—Îáç}bÇE|R»Ê›O‡e&X½Ò"ò®pÔlÙà;Uˆ]º·-…6Ͷª4x«±JDöm¹Å˪•£B¡ïPµéêZƒÉPc,ÕÜU!d¯PºLá©h°nòЖ¦§È†Wê –Âbÿýä%fz›ÅKóù†v8^¼ ¸ó~áÖóeþ—e}ÚŒ‘,ÕiÄ!ŽW’ F„:M–S¾SÆá•@” Y.9‹NAÌüEzñ|šðE+o,‰¯^ÄÔj/?<-ð ™W­Õ-˜Ü$_$žýºô)Ï}ÐCmøbeè[Ц6ÃÇt»j…&bE]-Âû™ ïÕCCëÚsM™íî áê|.oA Áý-fVYÁ^”oWµû¶âZd×=`pÔÚ,œ+5] çŽÅ}‚²ëϰÝC‚|ÊBÖ”’{õÐîl4wó $ðd…‰mßy^Š0ÁÍ[{î*ÐÁžJÐÁ®jðŸt‘À þ.}Ù麘Aø’åÈMƒüs~4Ùžú`FÃøO8 ¡â…C¨Yõ}ö,(^0þžZ™ü*ñV’VgLäò³¿÷ÐYíâƒü^áÎ"³¶^Òê{ ™¥ñ.a5s¾ÍÖ?\ÈEó§Ënl4û…–}Ðêo'(©m ©ù÷‘Ù5 IòøÇh0ÕÖÂs€0€¢$Ìò¤š±|yäeþi1zÞÇ»t}†ÞŒ„>h̤…~µÝ«8Å¡þB„ßç¥Q6—>%¼² Uk.=ùñv›ý’ÏÎâ¬èçoqñf#ã˜¡Ø ú0 È‘ÛQ2GÒeŽšlÙlìUá©d¯G¡Q†.ÚcÎQöŽy*,/¶8”™€ëBBû5æ„:º´_Ñw¬Ês'T!¤²"šáu¡’ö­…×IjD•-„š)…?Mð¼Î_ŽõðåX/_Žõ ©/Îú—c}ñr¬G/Ú­ÿi“Ïìüy_÷òynà“ñþãy_¼ ïÑË0²“7ßûZa| È#;~öS—Nòácœ«äÃ@c„_ˆ ÒÛq•Núh¯QNÿ“lÿ ’ÿF.ÜŸ*½í~tÒK—¨ÊÀvIúÍ—!_6škSñ‘à2¬Ð E¥I{ÍVËÛùùr¼øÜ/ï ìn•œ ?By7w€ÉP_ÿ RmE9{@VoO…ÒÉݳT_©ª€=~ÀeÓx9µËÌû™º/áà¼ë§¬šÌOžCËšì0ôÊ8Ð);NjáŠ(Œn÷<\D!=‚ßèÃÝ”¬ºÎ3ûæd'!bAvÐ…øiK4[´“©Ý˘Éû,ß)#}ù®›í™õé9þ‰Â›õ’C¯ëDQ®…Åõ$ÕQ¿¢ÀK}Ê=ä|t¯™a°¯ƒx_(‹ä³X¿pÖ/,ÿƒÚºfÉ8¨Ó ˜Ñ7¿§˜Ò?ë9^ noLv5øN›Å¨G„ÈÀ¢…Ƙ…. àHMD×ÔàÞ‹¸çBå°r·xt=ìn×L÷xt“ào"qþ&=yá&pvÜ}Y¥[8øB¥£™L–˜ƒiRs$½‚9: ’9ü2O7_ðÛÌPš¯4Ag_Lâe†žäªjBÑX®³Ã3åivÌ4¢õÛt];^Ôj%Èü69H_äëÏðév}…w‡à6ñpçðöLš<û œlGÀë ¸KgÇòþº;Ú×ê€p×Õë°0nÿÀXù®(éØŸë#?ƒ6ðù~Lð>·ôdêº8–-Ê9OÒùê¼ý­…eÈmr-b›ìÀ~^à…¶"I¾žÝAïN¶MQú UOü~ñý"d)e1¸èH.ïâlªy6GÃW7õQ lö­ƒóK ­Nñó*Ž¥¨ `–1°ðò“Nà ­)\ãýMQeO=>T϶C®åû¼‚ãÍü¥NC©=ã%ÞÁ¡eÐ鼕ѳþÒ—pÜœúô—Z§/}üKÍ+À{Ï.—çŠmdvé”Yž>À/À}ò“„cªDþe÷Œ™¬ŽwE™–GÞË({evÕŠí´×Óí.mhÙ²Úùcز*ºŸqÕ•Iº¦\õfpœX·¤¹ì0 ß±¥"‹¶Tz'–y%>?Ûï9.¾¢ßto\ .Ø ¾T·/‹G/?¿W¸?»!ðòòS]ý'ßðíÎî…3<ýUßnî§å¯]çàleÛäÇøŒœ|ì YˆO­Žûu<íºˆ”®¾N¢_»Þϲi®£pñò–μ®ÂÅŒX¾æ:‹~Mh\wѯë0z4cÈ•ûD6βÑÙ8KEcC|AœNP4ÊÐórêü„ʧ_ÉZ>§(iÄò:EùHãÍÍë”Wç¾Ä‹,§{v(ì‘ °G4ƒØ{ßé&s<ºjçdÒ‚“[¨ÚJÿþ} uNB?4W3ö~8øJjÑ’ÉÅs‚k7åN§þï§9ùT¯ Ë,ö*‹Žw½@ª]üë<…ßKsÒyž=sÒº.ºv ^þM¤í@L\zXH#•‰}ìÏI}RìϨ³öôÔ€OÒÉAýê!w½ºæm»fPv’üÐNtD~q#Џ%*Ga…Q[ÊÍèÞ~'7,~–gSŸ°Ëá`2¾/7“’z1XbIËé|¾ºBãëI4¬ÆHú`1Ü>ƒËhvi Øš¶ÝD€fÂÿÛö좬ºV×hÚÑ-ü¿Í3˜åeÓµ3U d<’;ËmQĽѾ`¦ÝZÞ‚?ÑQ6ÙýöXa¼ŒZø#»”¬îŽeR¼®nG‘Y°.Ã#³ZlüoªŽ"0‰n“I(Éb0»‡-Ç“ñpÍga„³Át¼ # .Q‡òt,M=¬µÞC¡s “¼(Ó}Ü£—èôÑíE4qUŽ ¿^D³ÕxA¦ð5°Ž&TRë$ô†a?{èÖ&-it;œO§®n§bgƒUôÉQ_v>#!=íÕé‚ÒŤ IiIMnÄ)™©ˆ[¹'ê*Þom·fu2ã óz°`k–ÛÑ|x3óD‡óÉ„}±?®#G+„s¾™„·»s8I_ª¸/WXB'sÓ“»Ý2Ý$E§>ÖRF·lìÜ.£‘v-Ž^}žKôíd>»¼S$L·¼š/VTBwÏiq!…èV„Ž ôLmz—ý«×Ù!Õ¢jôäaV8€Í ‡c„îD“ïÓmÂï¿Ày¶»Ö×Ó:`ÿr§§{w:2îP‚ã¶`µì¨ÁC~‘æÞ‡|;“Ó½¾á§§¼s ©eæ,/ä¡8ùƒŸ2BHAƒõÖì'×ÌÎÀSV*‹Kß~øþ=rù°±êªÊrØhå¤ìÒâR>¾õ5¼Å»9”P‹ZeU˹º ˜1ÚWõz‚K‹ugŸØMOsI¬wG·°-C*?ˆ¢“;¤kS0ɆÀÅ-ÎE¥¶=® +ÿ†Î&ódXMžNÝÀ\Ýš{.å¤ááV£|Ìä ãcV¡|̵„7½S‘9%²ꔓ[ ¤DÍrÝLº<ÚÚYÑ ôûwOm_Ë™6´×d¡½XÌxK¶‰+sɤ×dTs¡Öþ*#tð äªqš/Z§]Ò¦ÉãòLFó$¾K¶¯ëuR<òxðy%>µ•Ìfë}©£šÏŠ(³ò1-^ÿFAZæ–ø¬7J̯l¾42Ñ"ÛÖŒ~½«Ïé6-Ÿßê ¤vª4ex5_¬¬Ã±á…“ŸÑå• æW$Zãmú°ßAÞÅEb}ܳ*fGÃÜ–iŽ­­åì–r¿AMÅFxí‹2?®Ë¦b©Î÷,fY™Þ?Cóæ¯kNiu](é`\KðÛ±)’–T=â ÒÆ“ă›I@¯¯óöusàaãªÝ óIüœ™ý°gÑXªYÉMë:·Ò”Yo*O¹Ã³%39äÉ}’çI%ž8° ²Ø—qº×¯…iî&û€reKótwÜ”ç¶*hE sô4Ø{r‹½Ç›L¯[O¢Átÿ:użOu‰/Í@þ³½áñ5˜GºbJšïÃËrñ òŸ"6b”µ¿~çl+„Äžœ =7C@£-^â‚whýO*§»O"$Är¾?a9ß÷+gp)³4H0ù<ºÎo–ãÛÑbpy9ÝÎ?é6HÆ—êâaÙC½ø{¶Ò)h¨ek/@ÁÐ]v,’1 XÅ9ˆ^‚RÀ¸§q,î¢Þx)ÒbÊ3‰ö³À¦Åp›®ÌóÃc¼'d´Éã‡ÝÉê¬õc^d~)D¼?•æE^/æ_¾ÞŽ?1sóv:X~ôÈC‚ZcI×j¾šafErF€&{B"zDqö€;Hx[ÈÇ-`#àIDþ§ÈYaÂÖâ…Ç!ϸõ1y6¹È —:!€—(Ì­M à7mƛůM¢ðãîN ‡­Ã<€3ð·kÉ#ÿ$ èã_éKä"òD ¹Y>/ÙçQÎCïHäÙ¡;µ¸ù½{ŸKžH6m[OQ¿Š’+‰×¿ýö›B…´„k¦¼NÈs¤€Ê6÷ ºT§U?±™UÞr€ôtg}üS*ÖKgßœŒ‹Çì'Úàñ(Ž;y$lFã2m<™I éfÆ´™t`-£ö•& ÚI•'’î+6ÓâŸwá_Ô·“ÚÁŸ¶({Â\gñ6)ÖÉ5—Ö~m’[¼Gî㵆™[m:½]Ð §nµX•Çò}«$›ÁT®K»’¯²lû#ÕŽVŸ<„á9L¨QûR¦ŠîÓ‡cníˆÓ ¦×¦I™s‘ZNü«ªý”‹ŸÏ:ª‡›_’‡œ Mõ±*ô(6—v$å…°Êè¡‘¦­š•øàS,€*Ú]ò览r‡O4'@\G)\\݇0lEÇtbn T‡á{މ¸”›O×?:òÜ÷Ð&»~ªd’­Å›ï—¬Îm0Ö§¼,c¡0ö-à/âp·= âŒtgò”_Âí¯ûqŽwÉ÷þ L~P–'óUwÏ5dèùñsAÉ2ñ³öÊ—­¦|ò ùéD¥‰ÔŽkl©ôè üã(ö¬NËõ,òÕ{¯šQæÕ7æÄÚ™oÐ|(°bCœT`ºm(peJ¼±l‰>Òí“àºÕ¯Í¦R¿Jõš^Dìa·ÍqE½œ5,œÀJÀÅa²Ôëø~²`Þ€0Y–ÙO±ñÛ]–µô«¨X]FÓ'Ñ2ëÏý„\ …«U½FJåƒÐ^Ö¨oßé¥Ù%_ˆm?‰Öx ¸Æ>mËôTVà ´îÅfl¿0„›kÁÂ'Þlô°¬–Ú§æeØDhf¤µØ ]Ð/ˆW0”úy‹(êë$çÏêjžwY ‘zæ@~)?Í øá#Ò´òóÎtv/½‚x±%ÑŸ0¶{.^h`4™qVÀÑf5²sKÞŠxŠÒ§…Q§õMgAÁr KF+R§u&_o“8[Ž@\ô`»íÊ@V¹µ«úaÞzTÌž ÕZWæGãåQñ­>DÆôfZQµ¯ùý)mýfšTºõÔ‰…¥™Q®üä*…sDϰôê’¥ÛOÑ2:ç×#Í?/MÌ–ýg)ø0 hÃ/…ªø™@ѯù·×ìÛk¡î_œEI"GùÁ˜\%ÁîéMнTén[S0Ú¶‡h2S>¼„ˆ¶b2±ïP‰m­©œ"VØhw؆à½O•×å÷Æ÷V8!0ë“v3ÀyrØÆë$„@¨Ñíh;¡#Ñ&'•²‚o’mÕ¸PŸ©ç¡P஡Aóîn Åó¢õ •„Ö?¯àQ”)\9xZZˆ;fZîkp¤òw$™Új5-¦Šî·×H¯âí–QÖ fÎ+¨rNJ0’QXÀ‡Æƒõ‡]ü#©½4pÒ7Ò#ÊŠÙØ.£Ñtس·r¢f¤îíÓ¤ÛS‡¹º_A¥h™>„%ªÎÝÈÒÐ+D_.Ü_V¥jgˆÜvøPk±Ã#Ö• +“‘ȯv¢úãE¡‚ÔP•–¢Yä†,kbeɶ9L£L8Öëò"ñ'¿1TªéJŠ4«ÔöüXŽ%cšÄ;°Ùã Lí]t§Ü­,KhF¶ºe0:Nþ˜·FÂaz ª”×6‰šA®|ßëGßôkK-î\I[ók3·[m)¢’âk5™FúͧJâà|¾XÊñb1_`‰Ãùôz2Ö®]52]®8ï‘~Ûù²L½_‡_o©^0¹gXš‰´àÇ7àWTœh¤Oâþ»2­¦G“Ñ[9µîQc"¬ßWµêíù5®42h©LM`i¾¾ZãÞZ'#ýµNFzlŒõÙ:ê”u50W#âs>áÔ…&rP‰h*±Äùæ…|£` ´çy–öÏŽÜX?¨BÀÜ+ðgœò-wk¹†þÀeºUÙ$È’Ñj#c­C|õ+0þúuçÖÔ¯€…ׯ óÕ/yëWÙS¿U™QTeÞ‚ÓEå(“Ì5Êø,âZ HŸîºg“ÑÓ¹mfcøW-C‘µq„à€és4«¤<Õp¹ü-W­,dçóû{ [\%ÛÿÓL1¼§âì=IÎYˆ¥³µÛÑçUkÙªVâEnè7Ûɯ)(¿¦HÃýšUµ¯d{˜j^vÄçYÉ û¾‚;ž…¶ÿœŒÁ¹Eƒ3(K°eqÊ©¯[1™³*ÿþÏŸ< ˜Bùg|婞‰´…ýK™N•Z‡ê¸ûìlj OvÏUcÖæÇ™¡q ü î³Â*ù,œ?T+‰dM^•R¢À ]¶Âq/0Àœnr€'veMÕP!+,8µƒUªë«LN8߈ÁÖuîãÄgNÚy’}¦ÓÄIÑyÅR…=§¡'<³ eÞxEÊÝȜĜiH”à¬ã³$¦§ŒÜê–)QQ‡3%Å:OjÐõIùwŠìØ0}¢ »e©=„J ë–‘ãTU7†Ž¨È Ã"C2"[ë(ysƒ™_ŸÖz¤c¦ÄÃ`d–çÀBÄ$ “zú+DLÊÁ¯Ig¾ÂêÑ}Ü+¬='½Bë|È‹œr¾+¤ÔðÑ® ÀS]!Àº$Ïr‘éiǸB5)ùWƧaH>·¤iG¶‚ô/ñ´Vˆ˜¤h¨!ig´ºMŸ=pŒ$÷É,2#üP™EŸóXrv9ŠuªÕÍÉ ÃŽÇHúí`IHãúÏŠ¶â ÒŽ£hÏ—sÀñ¢‰åUÍ[NŒ9<¾„W÷™ƒ~¯?´d'޶é:-·ÏËÄÁ&ù)/œï·Ï¸°ZØæG§fÁQ±R…yúÄVµ—dDÏ êDÖÌ’n®dMIÓ aóPËH[§+öêAíí,nSö‡|“¡£$Ñ+|Hè(Žp²ZPÔ¨ènêà5‡g@é«Ya]±‡¸r["ÿí«x†­pƒ‡ÑH›ã2 RÚÒŠÛ’Šó”ö^µÕWVl5ÀLîÞÐO½Í;ù»=ˆy½QoM/ßwOÿÚKy þøJÅø§ÜHÖ5Aè~WKéÑ@qð®ÞÛ×Öà¶‚n&È(³.\º8ò©ì:»×© h[pŸƒš‰x Õ›‡@õ+²¨ c¢n™xÎz˜o2«¢í5‹[¸á1ç* ®K)Ö츻³í Ûeks ·:vRqÄ‹ud¶ˆ6¢‡¤¼^y%mù9PB\õ¿Ý.Þƒ”Ð%þ5pö»m³jKJBSÄw<6¥êε‡Àìª?(á)‚ ì,¼©‰Aµ,ê†SƒdAº®€dƒâÑ4uŸ¯-Qù5žZ ß|Í÷½+£‘¿JDHÁ»ÇÕ²7qo6ADŽ÷âè±"$PXÿSH0¢s¬‹Ycõ·±7J‚l˜ÍèñÔTÝGî¡&!}hõ8YÛ°é}FWË}Ïé6̂דíä²€Uóêtì¶e´Š$°ª†ë´"•Z[ŒÚ¶`Ïu¨2†žÅm'2Ïš±ô¾%cƒûay›¤c‘ËÇô¥õX ¼DØ“Ga-ÁT¢mÈÛâN³MzŸrÇ›ÙŬö:«­0itè«® ü¨« ðÞ44Þ1ftþ`­òv®Ãào綈&UÒJ¾(it;œOæ t:ŸÍ‡W‹ùtLÁÏÓñ’$K–?Øeq´cTDòP\§ŠoI£Ûh9¿ýÁotðûpö]ö}ö÷ì`ÿ€ý{ö?°ÿ€ýï¶h¸ól@#Ÿ4òy@#Ÿ4òy@#Ÿ4òy@#Ÿ4òy@#ŸSùhInd%6²ÀY`‰,°ÄFXb# ,±‘–ØÈKld%6²l‹€Ñ9 ÁŒäaÀHŒäaÀHŒäaÀHŒäaÀHŒäaH#ÆËèr6XG·“¹v͇ƒpüe<¼YEŸ6 ¿˜O¢9Q¤Ù§y4$òŒG—c‡•¦bg_­‚à—ƒ ý›ÁbE,á€;§Á†4؈خäÊy÷Û—w»Ï>'óë0²ÿèFö{8Ùy÷¾Õ»pªÿüòßáDïB4»™ž·Ý)ßýÖ´CÍÔ¤š¢& í2L‹D«q(Ñj0ùHÃVƒÅð*êz¼X2ÂI™géªðXìàèë7úê¾v£¯Üèë6úª¾f£¯Øèë5új-`­F_©Ñ×iôU}F_¡Ñ×gôÕ}mF_™Ñ×eôU}MF_‘Ñ×côÕ}-F_‰Ñ×aôU} F_…¬¿è«/úÚ‹¾ò¢¯»è«.úš‹¾â¢¯·è«-úZ+`¥Õm´Ê¢¯±è+,úú*hu²¶¢¯¬Hë*ÒªŠ´¦"­¨ˆ†]‡ÕT§µT§•T—uT—UT‡5T‡T×õSçÕSçµSç•S÷uS‡USðš©ËŠ©Óz‰¶X¡-Th‹Ú…¶8¡-Lh‹Ú‚„¶¡-Dˆ‹šÅJ³Vi–*ÍJ Xp„°€õIØt@³i¶/Íî¥Ù¼D{7ÀÖ Ó¾¦q˜v°¤Ã´w€á6Øéa:À¬ëÔ«€¿‡1¦/þ3Œ1}ñ_aŒéK’0»&`3 õÛ«ž úåŠÑMdz¼œOæÉ(X¨ÌWÄuq5Ê/mý0iÜÖ`’öà`nÓ`Iz”c™ O…þ%iÝY ÉE¢W½­¤­MFs3› ®,l*¼6®é+ò `=²  `)v šh7Ïùùgq™ÌBÞþ‘l† {âîPNÑíõ|±Z "‡æsO³Ñr8p)Y”ڳɄÒõ¸¸”VƉƒý!Ýwnæš–5ìÕ×e4tua¾ˆf|fs×M÷7^ #Lb“4pz#\çé¾üÇ1æQñÝšÂâÝ^E—ÝÌæ‹©«â’Ñbpá…§-|`‚K*?¥ ØDäŽà:ƒ` ×<”OÞñ OÎÍáD³N§”{PI¾HŠl{,õ“:ÈC&Hú‡´m˜úÒL°8ÓÎNŠJyà³w}øîꌯÖÛlŸxîª0HФìV­ü 5¯9íj;¬fùK6.qD+9Äi[Ñ)ŽdCàâ§æ³ÊFÉ}|Ü–ÎîÍ„‡ú£,hwsŠfž‡§à`.Î~‹…TJîêªÇšO ΈÂÇ#’:r‚YÜ)žÆ”ÎÓSõW_;iÌ©ísmNÆsÓH6…[ó$Á´Ñ¹Dð17ä>èf©û¶9 XçI\6G3ÛN“ò7ÉäuÃü…é­2 µ×u¶ß’l×&¼™IƒûûtŸ¬òx_ÜgùNã¶ß$¼WLœâƒ6R~W}*_•ê-fã×ZeEb¶Ÿ‚¨ç-QhudZâà°ˆ™~ÊÏ"þ¤›ÉA¦AåÙ'[ý¾ñ©E4—鍿³&Â̺ÏEvûl* „øTÏÐ`5`Ê`^Ø!?·uÈ4Çá[­üvyíš™ÄÏÙ±œÆ{Ö¾9PCÝn¾¤Èµ@5÷8^]•˱47ïË2Ûó+÷\΄z.Ú€2Æû§¸@2 øë–wÙ¯ú 7IF¨z»¶ºˆÃ•WPo7°þ}™gǃzÁºúýƒŸOpÕ?fé:!–­ÂÏÓEx ø ²^z3aòJV/þ¾m{χ%(Xê=“þ ÑÐèMè0¾;Àød£ôˆË<><ò ç}„y"IÿˆÌ§F¡\ò޹´|S²‘·¸ÐîæÈ×Y¼M Ö¾¼`ð}m’—[èUï0‹ë<¹Oò<Ùî$‡yT—~õànÄÀ|VY¶ý‘j× UŸü´uŸQ‰›~ä¥îõâÀ´ýàL}zéþÄ÷E°¼=7ÈÂd¤—8@¥€]í€}ÊC#T¬/Ìe?_¯óls\s»©M–"Ókf6…øÀuaŽ>Ä :¿c6ã“y$™xj»ëˆ<¨˜wŸ>së à¯~:k×OaÙOoï{L7þÑ Ý±+.OŠÇø4sl$T«¢‘ ¢ùÂ{6|5)¿U¦RÞ%éþS¼M7Ü¢„Ê¡¢Ù"›ŒMq âØ:*{ •]2†«´Üz/&èI‘þ«½,’é"Ý&rp®…S¢h6é(ÍYYþÜ‘žá+WöoÙ\ –foõï¨Ï'Œ€•ÓEÎXÒ*©AµF±•0¬=„|v«ó[õÅGhtR.Í‹µE=Ô(®§¡Ú«-Rm¶H^›­ïÍ]™Õ`›>ìwÜæEUÓ$}x,&ü¿}‚_§G+D äS½!"îO Ã…«ÃÉËņ‚ÙªòQwhIÑ \«Å„¯•Ü ]ü#©x.ï½Çm™¶ ·¹¡~¨Ö£¾|ˆH“©J¯.©= d„J¼®â®ð¦šwR g5úÔÁŽPP¯¯ ©ã«XVkü§óÉe‹ˆõgAT¬ÁÛõ¤3VŒ0·…M¡.•°<Èn6Ó½Fºu¤t¸H4(jj(ÕÄ I.`ÝZK¾®ˆË *¸pÖ¾%_§ªT ®ì…7@Í_g‡ã\J- vëåD°Ev—Ѻb‹ÜeÇ‚é˧ÔøŽéÌ¢€Æ’[0õ ºn‘?’g?†"qã»A—ç×é/ÖçYI¬9D"ã}G¬Žå:϶Û;¢îÒÑÜKÉ£É0w…ž°uB´g«ïÖòðPð]Lƒ/ïÄÅhà¬ö®šœ¯„Åsf×¶Mô©!úœnÊG? ·å—¬Hå>2Z Ñš¿²&LQëàdzLnøÅºM­)¾ÑÍÿ‹’k.hV¶ù¨Ï@ôPSp{t'1©!40_;æ- ȪæÉa¯“#ÖPiô¶åD3L&šùÔ…¬Ä 'VFí#?ô®€¥ôX ³:l >ÃoÒ[¬ÙÕÊɽŠçF^vY7¶,[æ²qSùýìšz%‚4¾íŽs6ÝD,ŒNE,‹Xê J±/NnpVÌBb+żÞ&ò½-‹°º~æ*ý?ðŽy‘&Û ¹S¶hÞ!×ølWd î¸t³˜„¯ßP¡E-û%ï²ÚÒ9t]r}N÷›ì'©eht9›/Æ·ãOú™96œÏ–7S?îb>¼YÞÎÆ_ü ëÅøS4¿Y:€ev‘gæ£6ˆï¹1rgTÛoÙÂ;œíS¶}ÈY]0“ÒYÁ-¨æƒ.Ó$Zq/­±a½4$±06¸#ÌÖ)Ùô¾±J0h`èBB(™ö§*ßÞk¡;õËúòl}qÅÿÿ£¦˜Ã8ÒÐÝ2 õ/goì|Ù÷¯ÈwÒsáuñˆoÛpPZ0€°T“)%úÛ ß*”L —”¬‚ ³íóC¶]ý{—lý,çÎÁà ;dÛg"´¬C‰ø”Ï¥TÞVŸ ôVúàúÆl‡gɺ*Wd¬UÇ­Òꪃb$(|#â÷Âø£Jµ–´-“±¢ú~A–ˤAŠVÒzÖ«ýwæHù…¦<£)wŠœNB`§¥}¾[ÃVãZÖñv}ä€ÊÐÃY›†`âͦ14¡ô‡&îÈgOš¬Ÿžg¿Èdk¹YZØzè·-:ŠÀt–Ä·µ‘Ô¦PïGª|V´µ+c¦®ÖÃ<+ VzŽa¨IqÜ·ì›Db¨32\"š¾`RWùy0ŽâºkeŽIíe-Þ´n‚Io)J³VZ¤#†°yø[š©rÜÚõgý$ûÅHM`+`fòPÓS•dÎ7F' 9‡ëÅŠ:oÈó&Ý©›ª«ø„c‹ïƒÞcqèm‘ôödK_ƒ-Ö'z½­W;h}{že?^óÿp§´sÑ ÀwløÅ^”ˆ8Õ‚YCY££}0?ŠãJ¯k¥0VRt÷äXÇ’[cx6M®ŸV"GCÑÚ‡WøCRÀiÐR’™˜ò•Ûù½`bx¾4 RžÈ] ŒAS¯½»bëm”³è”­þ*>-Jõ/æ9ÚIߪ8­Ûa‰§ñ¼ýªAÞÌ>ÎæŸgõ“ó‹ÛëÁ¥v]A@éJ*¸swÒ˜»Z+2Z½TXè" \”baãOãÅr ^äbÙ ?:UE(g„]8\%( ÊQy‹H¬{Å&âÈ«7(}8ÇÛðKök–(oƒ§ .Z Òûý•V‹¶¨iaRw«éÅÍÍ@LŒ×<™}ÄÖ‰ßGè€:x<Ù ,ši·A©Iòæ¶ÛÏÑhå\£Ë+hqÌN6–*šKlœo " ×@:ˆÀ0ú:T[øŽîu¨6ßù&ƒá‚4¸8:uÅD+ž\0:øùF¡ C  óˆ‰ ;¸çÕºžÐû(ŸÐnÇ_¢å ˜ÖÔl~»¼^‰éÏCÏ‹9§{  ¥å›äƒ»,/Ç¿ÖÉPÔ¤ÃÒY\ÝÖ…§¡SÅ+l€œ'±n%b·QÚkþÈî…‚HC­‰ˆæ½ÛWe± Bkõ–fo•4p¦±9ðAÚþ¬ëÁ`å®VG¯ß‘@¢½}CÂòãÖ¿yB¤ ê 8J‰šK9„ŋۻ'a¶ô1øWj0bd‚‡…ø O…ì,$cX]­/ZîyÝɵ~`ãEØwåñTjz)弿mñavH+d*265ÜM‘ä$ ûGPú"›€\kÒÀL×ñ~˜‡.LPZ ŒGpóNmú]9’2éÀZûº§þøw«o˜VjN8«4×bÈV1ÞÃ’&¥zIRáXi¥o!Í‹ÒØK­1ÜA—é>ݳõ/0*þÇäè40%à1‰7ÖÇ2N·ÖÇÿAµÍŽŒñ¡ìÔ(ÜZô/ðë3øõ§±þiSÍuS›äpÜ· ^¬hd§n“¡Ne¥‚àN +~@Pó”šP× ã@E{ùÛÑ2ZÚWG°ÌÒÒ¡5§ n+4ô][µ‡ÕtÇ¥ˆÿ°—»-Ä<î Ž‡¤åK‹E‚IPI £6 OЊB:°®É%(znM‚J‘‹cx:-ÞÀ1NŽJórEù± j:°¹ï͹¡ÒûBG˜Ç}üì*ÚVíÁVoסÞþg?ñ|Ób¼;ð›$á*ÌŽåš=4›Ai]y™\ÓvŒD¨N“ìoö§æK‹Tt‚3~š¨ÊúÅ…¯?&Ï.Û@³±²/ÓòyÜ@fJ?±úû‘<»qÜQñô–Ð"Γu–oú‰köQ‹x36T`jž-‰ÕsJަ´yìKöϙѱ-|Á&¤ö)»Ðä¾Bï'¯Ù]ýãÕÇñ×ÛÁl &Ñ`inÈOƒÉ͸ÅÞÎgØ‹ :x4¾ÜLVn™ãÙh¼ ,·ËëñxDÄþㆠ²úJD“ÄE«+’¸ÈþYO ¸ÐãY˜$ïjüeÔ/tBç0 ü=Ä  •ãb1®"þÊt¼ZDÃ¥/‹€"@ä-¿MC*P4[×óÉ€ÓúòÐÀ·³ñ`1^®Ø¿ÑåÕù|F}M"Î!”jxÃþߣ&×Wƒ°’$´!Ç;DJj³á|2_Ð5– §J£ –F£!c¹ZÌ?rÂûcâã_¡½œ5´|s#úæÕeþúfá€jn‚c™nßNãƒËø€œ'–ñÌìŽbmæ°0Ó[ÃÔ‹'n¨ e눛ƒ…s?Þ`q8B,z25W>úýߎ¶nš1Õ²ýKÍï èwÌ4_&Mœ£ a¿Y<É;T‚!?y·6/ë3è˜užfÕÅ %™Ë¤ƒ„¼Ó‡µË´æh¸7Pkˆr['Øjƒ'-^aÅž*"†WˆWÓÁ¦R'ƒ¯V ?ÿi},Žûê¶U+)-Ç2û§ü¶Òh³M,DÌÒGÉ6~¶RØr|3J‹K“÷\'ù.- }Û\båÚ½º¦E‰§!oÏoV+6©NËvQÄ}ºÃø0œÚyðº|Í?¾f_‹t›«)öÌ(yJצKEæÈï貑žýL6_y‘g!o–¼‚2Aï°Q’¡«f”døŽE×Q}V²õ2µf./rXÿμ1ÓËH;¥#n¿lÍü˜N üÐ9«#\³Fµ/ Íd( ÃyÉÎ'O 1.PÆ6_MåPD®.9±È"nú™16Ú€aIñêj¾ˆ¾±®öðc›üi¼X‚¶‰OÆ«šmÊN–N“Õs”׃vü( ˆÈÀ3 múV½m DÔÛÕ@D{ ¿#3ÑŸÏiaÆaÆ6>ÌØ¦;b"Pý×R ùEh£¸Œ+*İ ÅU!¯´Â€!m2dKZ©‘'ÙÚ$WDïrØRm1ð°e p]PÆqBcVH”Lw0¨”‡ƒEp1‘ÃÌŤB¸Š¢Ž9ŒU‹sZã„ei]ÕçºîNÔ„Ó9â…ÐâE9ßfl%C¸¬ÎÚ`‰Ë¨sôô1 €Eöðw\&TC‹§¾.ú”,E›Hˆær‘–æ›ïŠ×F,~ 7‘{}ëm+Tû<8Ç¿:äŸji¯êXdÆeL¤ËšÀy)w$ƒ½¥ù™§e"='mP¾ü=?–‡cɈ“x‡·g¼©£½—øT§ÑÍù+t ¢Ì3Þe¿z 2¼ø÷NïØ"K' ùæ0¯SÝó dEº$ Ä÷¥8W¥Ñ.X ª»—¸€ÍÙ³@1^-‡‹ùdr>X,oü†½ñhl‡ròyðué…ÍøáaÕ˜šµ‹3Û¦ëgûÔ^‡ }Ðl).»Y ê3œÊaʪƒË“ Í©"½‡©*èùeæ»ÃVéRíÕöÎ*ÆC}­²ÙnÅPS|J“Ÿ‡,§Eqê¤îË¢l\wDж»¨)—.ãu$õ^HíÄ:£¡öi/‰uÿêYÊ÷Qi¦*”›¬"D»n}ÁØ_¯Ú ¶næâüJÓ• Àñ î\¾IæÆ‘=óõ¶P¤r ™m¤M ¾8ø.ˆÅ\-& ñÖ0·sÆÕ™|§-¼r€n'Dðár®¼ÌÆ·óÙä«·¡(s‘‚÷ÌJ ’fÕ  -L—i²—ËCÌõìwØÜ]¾ ›½Ã°vx4Ö¸‡ÄfíwKØxv6ß‚ß{`gä÷ÇØùx½A@6¨¯ `ùͬá{:Ï…ÁúÄN ƒ;qÏ ¤í2É©zÃ57ñSJÎÉH臷 <ýà–$Ä.Û4R –àm™’D9*c]gi!\G*Ò ŒƒoÉlêî%îÈìÄ<ð†LÖ!³îî$UÄ‚ø±’©Óÿ­–K~°s{f£o'b"Ô•4û©f¨€FãåÇÕüIåQÈŸÆ·ÃÁµw‹ƒD$6 y>_Œôu¶‚f¤ÌM˜+{ ëàs4Í?;) \MdzG’‹Ô“ä#½½Š.¯&ÆýN8ÈË®©ZÐŽ R ¼²×¸‰¿˜5ty5À»>ºq ísG’«è³›© Ê^"€MRü(³’¯Ëô)á¡GÆJÃð'8(¸ó,ß$˜nI÷”| ”#géÌû§xì™H w³Óïí5“”¥;ÉCy•>©+ØÄ[¼ Ȧ?¼y+Ìè‡ÕxrÑÞvŸ9’e.Ú¿ âX+0yw½òÅ\+Øj)|Žä€Æ‚B­6a€Ô¾3.R`ø³Û¹ë°ç<ö­¯øcá/³½Mj‡&®&Ô*s¬ê§Ëô½¢ú«ŽC¢ñ´$Ekk?ǃ·| uоópéЇÔRS€`¯òìg}_gÛãn&$Íwx{¤IVözÎçÚ=˜¤ì2}]¶£ góÙ‚4ºI¸D¥ƒ0\‹´½©úÃÕ€Î7³³9MiÜp¬ù¹u @(:íO5Ôˆ+^©IÒ{•žô¼c+ƒz#¶¿Ê%œò6a;*ƒÏ4ÉhÏMªZhÁ´€>I)ý]¦âÄC©*pú€³XÚca×áYІ6ô9M<ÓŽY†döniCIzðÓ›a§ìè•Bö#*=;8že{l³µ:ÏcÂPL“NÇ ÈÌAs†D 6m€UÃ4qØ/g¸ ‡Ágä Nw¦¡[–!aK=³ZQzï èºÔ¬´G`­hS)S¹?Ê|ho±ÀßËíTÌAÉ”Ùݱlrøõ¶øÉ´Û[>Þ6©=zŸë¹âN|¬ŒÃ¹$¥{º”:¹ßËîØNe§àÉÏúžíy–։“¯k®pˆ±õ)š˜TOn£€Bë8~ë(è.^ÿxÈùf=ùüy¸åñüœ9J±Ž÷²öp—Å9ΜˆŽ0Åt®ÇtnÍ/ÊÊL‘™i¼Èr¹Mq tÂeE)}§´´‡@Ó¤|Ì6Et?KxÝÆ9°>rGUuxœkØ:~]Û34(ðUZ ’Ý~ñawk@†ª¢>jŒßR?uï¨þ–w sÕ8W'ÍÈR këäµÅ_¡3Éܒ瞣ƒí•]—)FcÌ¡.¶R=AŽ ïþpw/}ò÷†j)ðA }Ðè…#7 qrV§8Íb¨’-:iЩ´Y6tZP®Cé òiד˜œÓ\ý¬ÓY³'tZŸÂ¼ïoßtnN¹ÄC9€v‘&ÛmډϽwœÌÁEº“\œ‹$»ÑŒ^bãÁUclȃLKÖïn`b,&Ĥ’`B&à›2ÝcNV-WÿE1#«Â‚gŸýAw´áN%NÞž=ì0‚ήþªq+²éÆãª£œ½"íÙB†#Ô› HµDõnb|™saS Ô…Þä‹ûÐ&†_œâŽ•´‡®„üâPžAYjžq:å®YϸŠkZÁûÕ’±žWEŸ‚Õ©ŒÆjH„Œu 452YPäøs›†r 2%Mgs¯n¿N¦0½÷´´Ôé+ôè³2ux¶LŽy"âM\1»îîxí°Ôòšbnê7)JS 4–AÝgæ »6Û¯á\?©ªÏei&ý`ÏfŸ\\™FŒ}×8ü M2k@peƒ7ÙWÇN=¯b÷z°vìTò"_/bÓ®…€÷éÖ¶C! ÒÏ>çÒ—Ärc|>Ú¬ôÈvFAbìâU^úÞ2( ¥¢’²a§ÿÏ£&j&çÏeÒ§µ=©¹2Ýs3Ÿ†œßßÓ€ü¤™Kjî JÌž!©ù×}°8îUmô\=3²Mâ§dÓ¿'z;¢æ”=Qv‚StÅ 1žûvÈŠ ¹[Vøto“²4×½Nbjð´nÕÀ‰}«ÂÓ{xK$½·W¿ò‡»ï¶t’8œäßidU"z|Õ}Ú9ÊÈõE4&kÒHÝ] “œœ494¤$Ðßu%ŽÐe96z*$-oÚxáH’%)³Þ×y?à›ò'ìî~“†ËsÊŽÉݤ^óuTÃ×M…x€wŸç1AЕùR&„ÚÅ¿(ÌXïñŽ™W¿æ9¶Š«!Ï~Hº_¬ó¬ðeÇ€_©À/£ì§§ï ~k%†Ä˜: [l¼’Ü3Üjv~`žý$H'Q>é*^ÔL Ò ÷¨ø3lM^XBë×ÀÅfÓ 9E‰ðŠáÔµj¶ü\.^£Þ¼¦qñcþñŒiEYkh^ÿlþêž{ÚÓ˜g#Ëémé›lÃÏá›{1&l“‡¬HìͰGÕ¥±,JIýŒeo1"ͧœzØW¯XûÍÙw%òÍ ÷«-è)Þ¾.’švȳC’—iR€tŸIñ4_7, 'ZÃE¼ë11åö.+Š÷”²½‡wÜšÔÐL§dú»3Ó߃3­blž’Ú{^{ì)ÂàÄ[`ÓK$|ð\9QMæ³ËÛóhµ ¢ZÇÛ-Ôãp {‹ÞK’Ég$x‘г?ÀÉí ~Ibß«dP~ÍI°©Ÿh@vbƒµâ[ý+KzÜ–éZhW%ccURh/¬,Wý«ÎYz"iÏ_ý{Jìû½AS2éÕA Šì•8ñþS¬w¦qþê ¯Jë­¦:%OŠì˜¯¡ìÕ6‹7ÉH¨.Œ¸vL*¦Xü6L•¨Õ N&½o4€¼ÊÛm]·ðR5c:ª¶ä+FJ£Éj?äïcUŸùõ¶@ߨxqkEì"ÂOÇ&ÅÍtß%ê§â·ÅL|õ0b•§òa?m6죛ˇÞe¿Ô˜Ýê“Å­NpslŽTÂOÆ<› S~¯r÷3È–'ù›˜­Ô Ì|šé¯{É@eòÏn^9Zj Åo‹“øê*Þ?Åê=\òƒ-”øìæÅ+UíÀâ·ÅI|u3ú,n]Q8É+ùÙÍk”ÆÛìAá%?X¼äg7¯i²?žkÝ·úbq«¾ûÙ¼@FžZÏǃÁªùf×~â-*“!ÿŠÈ<=6ÝÚmÑ~´ûn“DSS€Äfª¶h%h"Á{¨mÛÌå[¶V¿`K]ž F0š5Ra!V|~×î‡ùS¡<Øž${Z ˜Iµ`&Æöœ2hÜzuˆÙ«áÂbšt’iÂkU‹ñ¯j“((ˆOñ¼_ö¯Ø3: yAÒúqÏÊð&føk+Ð(¹™ÑX}Q+¡^9Át2¶ gâh;¾&ß'åۛńD*ûvŸÌm!ùò„‡Ã¨ä->ŠÌ.$¾ÏïŠ$2 käOjvãuj»|93Œ7ǵ¾¤!ÕÖ÷óp Í!çê×ürñ?²;ËJ ;±”ù¤âuª¬8‚á›3ǪǛ¿å£$¥¸K’:$ƒ1ê˜ÜÄe\ ?1ŸjRN>O,Ùòg},?&ÏÜ¡‚êÁI¶þÁ Ì`âŒÂYöÕ~Ê1‹Åµwõƒ¾i¨:¦´cQf»á1/´ OÍÍ yÇ©$¤ÞΓ¢”ê% JËë¨%y}ùTçð±EOÒ»<Î]ª»êüÏ€"D dïkØ“£6í¶_‰ÄâŒ]ò­,ç<~X BåW 1tö›·sÉZ÷˜'•DO—¦5ÄÈoÅs‘¬³‡=ë3š$ƒzmAd a¡bCþ(ÒJÔñHs¢@Ýô…CÚÀÏÊæ÷øø_éöyÂúý©¤ãL-™N#xDÅ›M©¼eňú·Ku—0Mü&‚‹)/ž ?a¸'ý.PÐ^ƒæ2Û‹ÃH&Vµ„‘ãý.>(çè›[75;ç-„Ð<ªÓøuÖÿú·ßÞÛ4»¸bñ®a!ò[TžÎóã~ÓîŒCI§Ðª¥Dg;¶*n~=øÇÍK=VÆ[õZòj1˜-'7Ãñl…AQãÒòúÝë‘Üp–H\%@(¬Ý%gm‡ÔšO~Z±7h×}…ÖŽ‡Êož™s°Ã aC Ñ÷¿“‰ÊügfÑê¶Äyõ3Î÷L¡Jµj'ϯÇ3í!¶ê{Áó¶?g?÷ÉFþÍu]ÿX±f8>f??§åã5eÃ5 "¯>¶¿§\éÙј@*7àmÄ}¶>Ó Gã põ>\?\!6w@+ȲûNW`ã8°£íÁƒÃŸ=õ šçØ «Ÿ¿bBܧÇ\¼£9pßãZ9É)P|”£Ø.Ò‹~1~´¬ïÓ½hH°¸N6׃>Ö\¥âõ0=˜"+Jù§<àA Çt—Œšj$å·ÈnÆÊ"^ecÿì0‹2»È³} r*³s¬\|Æ%¹ïZügUÒ*½°¨`Q˜~‰Û÷ú„•#?Á’DŠjÒ]°oÕ$X ËP­ëÑæ?¹éúÆê¼(¸RòEãàu±n©«ËJÖ“A1¥½ÝŸÏ)ÎW¬‚×úSœ~2îrªÇ[ÈQdF¦p­¸Xð•çò1y†YÔ 0=S½ÜÿÏæYÙA4ò+Ÿ %S=hy½È€Yoýe³©âKD¡WOÝíÉ*Ó¬BWwZ>òpç°?ŇÃöY_J¹Ö_žF9 wT´ƒ^Ñ*QžÜ¿ýÌ Á¿§-…àœåxïÅ‚M¥{~(Þâᙟ;°oÄ>]­z­oÙŒÚåa *¡—CØ^ét~¿±Ú+×Âoh”âͪ­8Ä ]CÖ{ùLZ;¼Ð0T ÞúÊjù¤Bjn(þßµl·çìïºeš:Ãò+¾cå ÉÊ]8Œèa›ÝÅÛ«4Éã|ýø¬¬‚Üt)3Sã=+Eõ¦n?Ò#RRÖ*gPÈãñ"œ„`µl ªC0T’HPï§’²fúSù9MvwÌ`yL†íãdbS™ÝË]jß¿P÷ÀvÕv§a )ù%—í7J‰Å‘ìtöo(üéÜ_ÊMOÈú½÷´‚JÊŒ›áAYÃD ~ê܃º{c†²šü…z»ƒùˆ :P ±’ƒä¬"Ž» X3@œhtwÆw¾Ìä°ÖC¨é”O)ÁƒióäÅõÃü2íáœYÌÁL]0%}º Ïâe5wË‹*ð:“¿N·}å/TçJ5üEZ]¯†¿XÑ–®“EòĦtì¥Fa8‚3<ÅéVÜ*NϺ¡éœ¹>Ð-MqR‡g™£d›<°åŒrÿ<ü>ÍCŠùpD„å­÷¸?/ï'¶Šå¯Z^'û wwÐÃᕳ–Š uyR¯ÒŠ.óS»Ê?Ç`RHÙ©&²y–U[„=,HEu±‚ oDB©Ò òªuZŠßtÉ$9?‹±}‘g;:Ýr!6¥dûRv„ä^Èȶ¼/!¿‘É‹-¡©½¥u8(ýÆŸ!E2“õºÚ³ìBЯý0ÛVOX[«G¶ß»Îfž…ØèŽ:Õ°TÚ6]- iÒ0–Ù ÏãgýXJ€gÒä—òKTÊ,×6u£êc€Ž³Ýd´0À¦î¤ƒÍ†f=E nt+ç…°¢;çM­ÂîsW3e™ß‚¬Mªœ ‰|J5gPYób¦;ºþ¨è ÕȬvØI ΟÒWÛ@^¤öjë'…RgèFW7ÞÃcÎCàªtyÊ^œ–è§c*~¬g?¥›Ž ÆäÑÖD×>a/EÔSšÆï¦²M‘«¥ÃÉÅš#zÄZ½ßX;i—á)Ñþ>;E×ixµ]¨¨¿5Ó³dX\u¼€ŠÕØwT°t_¯¦É}g.§PÒß‚ú±–ý_¤£-N¦¡õ&*4Æöˆ#Ù¥0g]D²3ÌxhfÀHgÝËœDXÎ#X¦¢O) îPÖµ¾5Ý„(°°–.ؼà JÂÆhñê1.Ðì 6ïK¹Ó¤ܹÌc€Í…¢ƒ@(f#¡°­Q[ jöam~c"lŸCâILšÐª´ÂZN&D¨.;…f.L<8ÍfMhY*×ôëóár)FüKí­Ì éURb­°@öµ ~¹í?*÷MµÃõ‚¨³x¡äÉ?IÁÔ 0 ß½ãp“ÜbŒÍ–/i2KÇÔú¢nÀUÛc iåàøE²}JòôþùÿP=IûÍ4~¾ãçLë^Ð_¸ã­·Ù>™ß÷¥¼¤¯BÌ6ù“óK‹ñîP>£™Ÿt©žiÓ©üM¯zÉFÆ$ùï"Zx€J=~ö2cµZO½\"Tÿ¾ n5vï/šI£à«î'›©_O£í;ú5NàÿëCGôCÁÿ²ü¥m/$Ä·nRüåáuµ §‹²S”]ÀÂâÿb°q¬÷´¥í³†zÁÐ;4‡—ŒÀû«Îö#ùÿ)—@Î{_…Oá¦Vï4…sÙþ8eunî*Ë~t 1-Š®^ß³ö¸ùwB¦ü„º‹*g»<óñýӆВÿ_2\Ðü;ŸQ˜×‚¹\ßòsÍJoïsaœÓ()|ywteuÚ›ìÁxêËj-ñ®›«¡pk74«ÕÊ_M¬µ&‡t#‹¤Õ/kéà¬2yß«âÞw¨¸÷/^qï_=A×Éœ¶âêy©Wý5LÖäMe“R8ȨwÀYÔÕ]Yòö›NÂ;@CÞNh*›ÂÔ†ÕY×ՀɰH*#¨ª]rà˜É(-t>Äu˜Íæºî*]YÈ‹SjP=uEõR ï@jøùº+©Ö#õ…Jpã5LÙšz–ð{rB+½á°OÚkvzôˆŸõa»Úäõº§;]Œ©-;ˆ—ÙtÞ™h¬±]ØÆBE·žñŠìÇ*»)’ËcBµIŠôa¿JwAy‰¼N‚i>…ÑÔµ6Ýt¼q(tæ$™ý‰y½XV‡7ÖP7?BtÞ ^òÞtgúõPPaç!ê±–õ¼LÊdô1yîÍËwSß«­L>Ðý_=Yÿ[휵»½±2^Œ uKÄ蟃íVµÃÔËã‚øñ7SOĪz3õdÜx9OÅGDæ*ø/}£Ý‘ü‹äø·yµèO~¼£µÕøCЕ1¸|Qú mX_.š×æúš<”wëHŒöI²)˜!X’ û)-øÀ¡Ùšþ¡cú)K¹— \Vq7Pm›ÒÞ­‹æ ÄÞ¶À :Öÿ‡ºº6jsø+vÂŒWâ¬@d Êi“ y©yЬÄ>EÓåN×3N¼ÿ¡ì{`Âvïboµ‘xvpœÓ™wØÎ\¿É}pËØ`¹8¡Ül‘‹ Ù¿L-üõ;õFDç´~ ÐÀÐ"C *é›TxVl0©ÀN9ùß Š‡ƒ7i6ܦ‡3ÝGÿFçX£€Ž`±ÂN™_ü¢‰ø~¹^Z2CýäÉxÜqÿ0wÿùXÙÏQ¶fûÒ,Ÿ·®Ä4]o³[–Ìò/  òtÞey¼#÷\Ž×eú„vFq÷l©4œ³IÎãÂ×&[{1Ž‘|Ó®Þ2þF¦Å@Ô¨£·«Žp.îÓr쎴ê‚Bé®ãœ™"%øðêû“VmgЬ«Ôݱğ‹D±DØsÛ•š»Ó*8¦í5·´#8W¡ò½¬/ Ü/Ó*l {9[•"'¼)ë îJQp׋ùõx±ú:LÇÆ=•*@kæ¶$´Wot·@»­ªcõ|H¨X¹’*ÂàÊÂÌGÈ:Œ¤ñe aût¥–îÕ%ï2ñ¼.öC·Äè§Í~é"E„<¹ç;„ÕºüC—”Mr²|/#bPÆŸÏYææPJÝ­jˆÌ®«;æ=ØltöZ‰Ãe•ïÓ±djúFª KGCª¢¨Á†isŽLÍBËÃ&óç¸Q§Ÿ'9pp9ùX³˜5O¹§[¾†nòµaÉ/>õ{@éfcœ0°A‡œ_I˜òÚ8¶„È›â³õ¾7Y6d“‡mül¹¼ldi¹l ìJ²qlxñÏ|F,P¥w*3µ¥í–·Ê ƒi1}Æf`^ÔÈ×+ÑÉH\+(…ëuÝ+IŒ[´Ÿ7¿ÝÃèÊÝÚÃâÒ¡Q›Oñöˆ‡K:V"`Ñ0n>'Í,.åݱ.i¢•èƒ;Õ[lR^.Ì8_)ñ¢ Wqñ(t©%…eó›wwl·ŠÖc(Ó…ñon•ƒÙu»ámîÏ»3ëhÁ­sï±ëø–j,Ÿ×gaMß—ÜÞJ×ÜíÐî»Ê¤eº;l“:EŤâ_‘•ª M¸]Q8!ÅLr«`µ4!ñ«½NìX›éÉ#UŒÜ·¡ù¶]#Êz§ÍZìv” µñq8É2À”²• õßJÇeÁwÔš~k1€¡Þ›è+úN·(m²±Ûu5p©žÂ×ÓæòÀK¼HâÊóLú™‡w¤m³µlü|ˆéncÄž‚e77”×jì'Ú ¼QdO.©ØT6úÙ¡³- ¶'âûÛ)·õ ôï“V„Ê÷¤5¡0>qU¨ªÍgS$Õøuø°€^=lüv‚Æ;Õ)ß3]ì©SºªèZk€õXJžän*Õ†=€Ñ¾Ì³â Ï­áPÜ€Í7C$ Uñž¼³Üzg`yÚýzû/†¾kPÑCÎTBºð¯n–ãÛÁdr{>Ì¢ÙÅGF—³ùb|M§ãQ4Xé$4þ‡Í’ýc+ eÆe¾‹÷ŽÒèGŽ–"*GóOvص)ŽŒ¸<Ó`±êΕ#ì˜# &·l#Vƒª‹\ÀÞ³‘õp$ÛE ™¯ -Œ v¬{çI¥æ=…¬ÜíÊt5sçëÇë¸|Ä1bĽ橯EêkS[$uñ#7>U¦Ós—ÚëU–MãýssQ¢5}J$ªsÅÉOz°á=èÈ,:)·Þ²²þì>#Hºlz¥¾ëåQ€<ŽÉçÕýöX<бgÝrkã.òlWaCf8úñ”ÈÅEm]­íLW“£Â\«&˜“ôÞ•píµ*Ñ:0àóY™3Œ÷v®:cjsèZsíV*$¸Ñç“·sõPÄúw“‡VM º³tMï¬æv«kú\˜f×xÊž¿W"9å"¹Ý™¦@Ú"aàìæñÿÏÜ»m·‘#é¯R¾p]UuU÷Ì¿—÷ ERvº(RMR®¶}¡•"SRŽÉLv&i[ýô?yÀ!"HÒ5{M‹J|8ø’ýó$úcžn¸ÃH=¯kôý’d¤û¦êçµñZø]Zlwö9Wwíú‰,Òíéa—o&–ÁÍ!ÜóKΊá˜UÂ(¿ÊÝwë`ŽÇä3¦þãrŒËõ¯ÈãB5ËëÕéA‰Ì;¶£ãsU~ëÍXžs$Ì–º#4àÞ`¬<ÐIcš=äÝW±ðÏòz”{ÿ¬‡9´§Õ €¦ð­6Ú‘ÏÀ6”üs覶+bäìí<…‹¨<2•ÄL\ƒ2Ï 'óg~|Ö—ê4 9c•…âÜâ¤àV-œÀjîPk.þ9 Cq?Tù>—WH”Sv¼'yût÷U¿µãFæÑ`_Ó¶Yx=HôCÄðÉ>Éx~±ýx>:YyB|ÕsMAà"û¦ÎlånËÊìÓ'u:+ÙѾóod¢'Ò€A‚9+JÖaH„Ǽi¸`”q„~Ñ´ç úZסkæð½!¢%z.<79|ï‡v˜#4—x®ÃZQ×y¥éƒ1Êa,>†Ö¾  ¯«.Þ$=¦M¬wN®Tlx˜Ф(¡Q/v ÎáÓή†¯þ’Šýˆleˆ£[h^TéFå–¸>Ê3xy1ì#yÑj(È÷9í_S†–:Ÿ<ÆVĤlðSRôѲ€EåÓ¶Š:KÀ+ôôþ†Ÿ#J2ÝæâÏ1t÷ z(OlÙ˜§K±‚®Ò¼È‚Ї´ö¯ÐuãÀ+üøÛ%®ýð3k—Éoè¡2øÀKÌ™!ø°PÔ)¡p!‚ç‚`ŽÃÁÕr.Ò“ip™E µÿ`S°zg±â_øˆóúJê0÷rœ†b³©ÅuÜ+=o“€‘ƒ1n •}æð19Å¢M¹?¤U¸Ýù'ØR™¤û_œM˜ôÆÿèÃ~°8\5³0ì@m"-=¼õfƒ…nÝѦtCØ]°ãú º¼¾Cì…¤r‰3 'o¼­ÒÃs¾igkùi)²™û7Óü¿‰]0åiÐÊv¼ô¬Fõ:sÞucÖ!Û¶è³\§OuøèˆO§ªè¿»x3¢áÆB]”…\EEÖ6{ms!{îG¬¿Ö?$"ŒÇMZ¤O\'’M‚<ƒÁUö$JU½0 ˆÛ—`›UMO1vô8\¥.Ä8‚'4˜’¬–µ<¸ >ÄÂÚßg>'ó’û¬íF3<š2Òá䎢Måf´I¾¢^tGø m í·´±¡êtŠ?p’3‚Ž™ëú·Y˜S^ç}½ìÌgTãB ÁqÐ#7o_û ^Þ¾v$/¶õóÛ׆y Üׯ¤lð¾vÿ,Z@¯ö8ìYS‚?aj€ðçJ û4©QQɫӣ Vµ5ªÙ¥]ç»cVùGL²æò©NZ ­LÃN4`Sžº;ÆäPÖ4`ŸV_X <†Jò¢>UÙâ ~ ¡Ô™Ùsh“ñc¾ÛK'…½·êÐß^¾Z‡dë/ùáõûŸßÓ¨´ø"ÀOöÛë`“ˆ…“ŒË@I^20·1ÑÜ•u–ÄhÀMMåŒ;3ÉÏÇ"‡’…@Æ’…qÖ¢ƒ¨ÁN²ÈÕíU¶«Vªîy§D“•?ÑQrïÞ8}¯ÿôy6°¼@“6hR!æ¤ ÐUm²zö0ÅsMæF³d2ZO'(æn~3ZþAä@ȶd>rÀžÅ?3Xi609Üg׌V4¨™Sdq¨yÅFËÀ¯1Œgy‘Ͳâ©ÛÔñ)\©ÕŸay¥IŠÀÄÑ PÕm´:¨t¡°Ç°6™00²é^Â}ÃU >#\_@ulH­· ¬2º¬°y¢¹¨Òo%#¬ïÕÁ^è?}† ¬<£«IƒôH“„é‘6Õ# €9è´¨s¶ÊäåµþÔ¦rGþ Žšì†$0ÐThªi`Ä$Ó öyñI 5ÜBùË=¨¿éÁ¨&Àå¹íBž_ŽÙ¨ªÒhݯ мËBl0Û¾¶!äø@\# Â4RùùÊj7ét$„õu;Šò m èU†˜ÚXó!zƒ¿æÔÛÓ¹`Çø’ ÁœáH,hr#Æ6HK#inƒ Bø-¦Õ@°»Â}´¶ *ð>v]rV =!9îXvß_ÿüù*WorƒÁáÜ}Ó¢ ƒ¸%ˆûqe9ó+t`Õã⬑á&Z*ÚMÔ‹[ âŒ)7¹U·cS&P-¢. q.ÌÓÚ Àµ¶]¯«!6¶ 5¬!äk²òþÈòz"$6+×ÅÁbÓZ)H·ÛV"X\W7ö`*:QÖHejCÀn 5zÌùcÈll$…ˆf ønNÖ¶q@Ÿ7 À`ðR}¡w’}Y7­"A/¡bhù"!J¸H„”, Äê=…Ð2uMAš„*Œ=NÕ/–¦¥°½‹çÉ,YA Ø»se^lÆÒˆÆ:_æ#\p½Í4šS@Â-(!ç&Ž”vHɼ‰#$ß„QòoâÈQ`é±à6 _ºÝ6F‰Ž!t3Ÿè;Án{,N×̵‚…P:GL¿ëH—ù¤[•˜J jœö|œÉj]‡\Î}u3zEú‰* J~¬‡ÔÜLÕŸªì1ÿî¤ºÝ²·›ì4 ‡Ag¥;iÇýAþwVn¾8)Ê‹ømî <Ú&?é—:Û[ö– ÒbiÊGÆÒ69táGfÍ6I+ãþ+ÿjñm© ¬lã ×¼=ÔåîtÌ,{¿åÒ&2¹¼RŽÓ¢”ÏMïøt$ŒŽåÝrÖbŠìø‹øÓÅlÒb©ü‘nõE‚ò¶ø)Ù÷¼>Öþ÷¼žä• ú%êûßÝGtÛ¡uŽ7åV…p¶V:µFîwýpç<ûg·ÍvT'ý}QL¿ç¶sLg–ËÁñ+gÎêù´¶èÞ0éåþ&Ò³=0”[ñþ‹P~ªÏ€\Tª\¦›R1õpuvœ™}þBHa];@Âd•–ey 6Þ“[ö¹ìö"êÏ¥l7Ê ¬ I…ßHK¹eW `õR³}Àäi@W£ûé¿’Õz…¥.§oïf£%–á ?Ùë|ïUþ=JhJF®]òòÃôûfw’æîî…Š‹b“7{a¬>´öÇXþ^c̪X¿›È³"õšEYûËÛŠê)» )v«p6©Ú†Ð[t¥`±í TíÏÎÍ ÓsoapöTÂ{nä./87ØÐÜhš:ܸ³;â¤rQû”k‚x.kä9­è¶v0)æ¸vp ¯ÈÁøW‰ ¢»—T`>öå%¨ãÜ¥.»Ë妳OW´°ÏFyž< æùò\ Æa÷k4Ô1‹[¸ùc1e—~8 3Õ½1g!0)7xg údü¢œƒz´Ë–ê%}?Nƒ—ã, ¶üx Ròv|B8 &¤ë_ž.—;&jõGr{uw}=]Þ¯’OS¥n8wfUo–—ÔçMÔá´öëmZcÓºšÖÒ1úÙ[N£ÅG>7T²©uüÔ6àÜË1ƒâ”¹=P©…Ú“!Ùw•…áš q”´iÉ«>ò›¬Éºì¯BºúÃç*C›rXz^És`6Ö Œ¬Q}6з¼ÊÞ¥Åv—ýî!¹Oó§ X<>Š5,Y¸t·{H7_ȼ›;e1RôêÆq`4e…\ -õYº0puzP-(µ:úš†¹_ Žª'yN)Ø;Ú<ÊËWæâ•¢â:QJ4`‰ëQ.¾fU•o©§ŸCyŠ$m,º¥Qú`5õp÷,Jh¾ [?ÿA:镈€³eŸl{ƀʔ=¶VD ³6Ž©y˜ƒ\o«òû‹f ½År—³úxWgÕ${Ì‹l;+¥¯ëµÇE§y ˆÂþúÚ+ùålªn݉n¼Ù*§nj… ãXªŸï2ÝDAQî&Dû‰ÝØU’0kÄï‹2ëEèRuPåOäê¢Ù(-UÈ7u×óóuu ‰þ¦i&!U ®WÉ=Uå7UÃÕQNzN•޽u9-¶‹Ç«ÖV k‚¬ù@ŠBäOE?Kb‚ø YöE_Ü¢–™Z2Ã0¹' ½ ´KvìÛƒ1Ž0ÏgytŸ~MèG¡µdŽôš¶9˜ ÷XÆé!ÝäǗתڼj_^‘sO "5#üÂm?‡ü¿!âž_‚³„Âú"H7°/ CCû"JÑ îK³õÃû"2êø…anˆ_åùEºÜ ó ã€@¿„ 9‡\idHÊ€ÏHµƒ{eH_…b £dWåöåõûHÚ¼øZ~iæá¥ž]åGÊw?G6¤ÏÀ38>~˜ Â»­ä[ù×Lá…ixÊ L?¿ÿ<uݺT{V§÷”QÕ¶=Ãì„’Ö1ä|CÊcé[¨ ÃÊÈB[Ã$’c”?‰(p!ÖC½8¨—ª_ð6à üWý³5>±Í¾`n æß<¦…Ý ¤CRL†ï¶ þÁg+™Þò4ðƒ1.‚DÚS²Ä  Ò^”L{jêçÖö`ÊÕuº±Âº2óúMŒ¢›‹ê #P(e í €f…ŒrË ±ê…x B 0‘ë‡ÕÁ}xA4-„Ë J&ÖçÛKU~#LFh ‹ ¦ªÛóLL…úÃ`¸øºvO>>U”<òÕyä!ñ ¿?<4žä“óÈù“žËϼËã@£³'ààˆc =:€£K•î¹ï öÀvŽæÀéϯ î˜%XpÇ-Á‚;v ÜñK°àŽa‚w,¸c™`1x<+ž¡1Íå3d<4‚ÎØ ·X/³Ã.Ý ±l-ÊçcúÀGWÙV0škêYDÚÖ£Wñ<‘°ØîÊòËé0lçʲ¦, ïÁ´yë#åÉÖ H­ÃgÀ®'@…‡]CIxöZËþ(OÃãKM -=Ð詆Yyàl|B”Yöe )¬8ìÕ,˺Üïȳ,6Ò?Ò`_™‡ŽÍà±€ô­ÆJe±ÀÏý¢„.6uzB¢ÇWœ Jõ0‡o«üé60\7È! žÌ“u2šÁ7¼¡.Øô»ZA^íîªR_$²2T \Nog£ñtt5£ë9_¬ï¹Xú‹=Õ™ ‚ô˜mí§†®eè,º³bέøÂfÛÚP IØq;pÚÊÔîHIì¤,ô¶*å¦lg›Ð¤0йٶ¤< ¹:d1½õù+ÖÀäôPóãé¨ú4ÄÑ÷§ÓY4'fþ4ê¨Ù¡U/Þþ=h‚’ÓVó"[ÃŽÎב€ôï4-ŠR ëÌŒÙnû€Š·sÃ_üÎ`gTí‚ü¼3žn{TÇiÖeAý:¡6b:“L§éˆ&"ý(ûË!*oºšCu¸^»5ê´nÎvfóÓn7*¶‚s–Bå Út»mJ%§õ ¬Yq•'oX}ÂDá;x&Ì:ñpÌ1vþúU†ºÓý'—€Þ0lŸJó"ÂÒ8Â@aòkÝÁMÍêƒî‘;NàO¢`ïQXt’ñŸ…EËì= Kˆè?‹#þó°z –j¨ÐC¯T{ ¥ ?KÏ6?êp‹kœyºÅe§¿ÒÇ[bÕ·yhH‡O°,8×kÌñäãúkº{µÙÑ÷vO3¬/›%óõŸô·¨6øÑ¿1Úà·Ë·ÁoÃÛ`¬CÛª?®^䋱Q£ ód7`‘xÎh^¡ð&'|›ë›L†ÚÞ^}LƒY„o1¨Xg7ÙMv|.·«ü©H§*®¹\Ú}fÅ SÔí¯¢*Û—òêJþU¬Ò…±½’æ‡y}¥Êå“¿è3j 2÷æ ª —ëa—s^Ë¢>V§ºMá™­LÅm†Xx_ä!£—Ÿ,ž¿¬ÊÇã2“¶xá;gÜä!¸d¼=Ô@ c]kÐ ókÿ ´ÜùéõéUè>¦…"n š¸ÌòSÈGp×ÀD”à5Q‹IYõ>1º–¹w&Åj¥Ó^…NHP'>Â;&î9­ /§¼íxïÖ_Õ·˜,ªîž"ÛÜ ƒU)A-OPïÐÝ(KÄóZ¶D"´N*F³€·Bm-˜”ò)?aç¢[n&V²®Å0"»ó dCŸq˜ðpÒ´)·´0•$˜¶0É“J‘ b|ÿÛÄÎ÷×Ét6ñ.¾ø o%Ãú˜ÈN I±ñ,-Ú´2È2ßÍf÷£å[²Ì‹dÆ,Âc÷*p“§š²µ¥Mç¯õbi‰¶D¹JšÙ,â2¥Ï¯óÁ]Œ¯X„KáàÜêqÈVΘ®Q9Žvù‡ïg8µûN”ç‚Åb^ŽËÃËùŒp¿À%Y2»8œïqwŸÎ·=Í3(iŸo¤ÉR½ÊHCÐð€[Фk/Î̺Y’³¹dëdþ¦¦™åX‚|€Ð¹Tj!ðÓQLYSó•FØ6&yÈ=ÖÎFÛ…rÇzÏf¨¢±í:zDu7ê†2IlÛI.±[[›T çÜ)u>/‹öRÐNÍ>|R<–‘ÔÀ==í‹7©¸e÷·ëQtÞ‰™7 fýªVZÁ—æj¬¿cYg…5,0xªèp\–(çOÏG5i ½RÚabõÛW!@/Èb" ƒònÒÄ\p_ÎrÑ÷´ æ[ižÊ@…Ú [>ÎMÙŸßLXBÇ­äY¯M"òÖÎPë4ˆ^k²”M³Ðä`ÕŠ‹Ä(ö}í¾;í;ÉÄLSe[?ÿf¼~öZ)±n;Å$u¤>º%f7 ¶^=5S ‘WÂP¿oÓÍùÞb>ñ»XH‡–“¦„ÕtË_¶ ºm­ïÛ«Ñ¿QãŠÜOjiã·²­!}&û¿Ñ5ZL~ûkÄ¢ü]PþìË2ƒòït»üÐÓáì"D  †û:žÃã¿7ïÿ7˜òÿHJrlö/f“²œ4±IøËÙ¸T“ö‘í ïð«õr:º¹¿½M¼H+öÃt¹JÞq½ß_VÞ l&R Ørz=]NçcËñl´ZM¦«`vqõ~:^3€¢þÉü-8Z.G¹¥ä´ãl1þCžÏg`§óI |9]M9uïxά&˜þk<½]óÄD²d·íírñ¯1Ý{3úWõÖÙŸ]$ƒà0ßÿ¹LÖÓû›éúÝs›pÕx÷œàÕt™ŒfÉ'èúŸþk=]ÎÙwW«u²¾“=s;]Þ$+ÎXdªÉï“›ÛÙôf:_"9ˆn[/Æ‹Y«=îÿMñ[ˆ‚©,™o}Á$¬G/HRºp¼È &ß½ÔéÒÁD¥?B—Ñ]+ð≉z8=–`X$êýŸÿP­‹ï×o§”Fè¸1®¢›œ·ÆèU$Ƨ5~°óu¬RŒQ†|y dúm»§âv :2¹õÆvù[T:!¢Ê-ä*ҽݿ[¢#¦`Ç94®îpÀV qiP^wG(ÑEx#ÆÚ­¼.Y]¬‘íðïG4åsn„˜,u·¡-/¨•YרÞ~HÌÚ´ž¾U–V›ç?²Ö¨Ž^Gv¥íò110˜Î^ž7âFLkjfIwÒaý°L¼S—B¨¬| AÚ[ÿVQÈO@ý¼+Ðð¤ºÄº0¼*Á¸ò¸»_HÀ«x€nŽdº}KÛO< P<ÐúC ÷@‘!¯´fÆHnçж¯Ëëú^üŠ0À—ýŒ0@‹<» ’O¾{ŽýÒ ÕèÐ"*2=¦ßæ‡lË~MÄC+¶Û«wè¡À¥ó\¥,‹B(.ó`SɈº¹²Áƒèû;4æ6¹:Q<̃óê¤0ŸSñ-u⥺#EС†‘“˜¦5çQe›LZg åê{ ¸¥õ‘.xåFÀ†n$i•‚¤añƇ?Ã:cÌalߙˋ/T:(ئ(JNƒ`)àg(E Š@`Þ LuÇÒ~Ô(Kã]sL=9’¢”–ý‹«€®iR1UÔ$cZ¨Iв}sþî«%üÜ­JÓã‹€Mƒ%òà‰«àN±Q&F×øCßLtßÓu/ÖÒÔ“LJ¶©‰T„9k»B‡ØYFÉüv·i°d¸/<1å@šJ&Q!ÃEØQ®NÖϱ#šÙÀ§§cy-s…“•º$‹$ ƒ}a/#q#ÌZbL§Óë"_dßfnc3ý ¿F›\'£¥ÑÉhetò{:ùšNžÐÉxKét~KyøÖKGáw¸(¶étÛ ]ƒ]h_ [Xè6º• Ðλ"¶¥wPøGD[†¦$SzJ¬IÀTg“ «Î&q'FÐ*;¤UjEk7!®Fƒìˆ0Ü—•X¿›ÍŠÒ²øÄg¤"Z¶M%´lkV Z–˜¹½doætzÈûÁ¡Àð¨^nÒ1½l%£åÇô²•ìk +Ù×V²¯1¬d¼mÙzÃczÙÄCzÙI§ÛÔË€n_P/;ºA½ìíÌÓË8®—›Ä œ¶fa?@f…(…Ös»SY”zÊ39‡8Dë¯ç0瀧BAƒ%npžÅIACÀöLHùšÕkë&„Ú§•<¼{(+ù:¼5)htYÕ`'‹–EÏEbƒA lÒ@áC¼Í‚ljš„ 7ê.Ò=¡„ʆxs+‚ øìí Å‚,‹£à@ VÀ²L‹m¹×§É… Q¡8<èã–HäU”5ÍGK{ËCîõOŒ›Uòcã AYJ™ œBñˆpÀ¦AÔ]²—lq@6#¶Æì@ÛþÃSœ9´/®mÀ£Ö[ÐæBÍ:Ôœ Xg«ìß'æŠ}"Èèds£J·ºF=È2-Nû¬R·j­þ R;ëÉà"b(e韯CPx!=‘BA®%ñÞìoÐß5Á·YµÏëº;YˇòãË/WioúT³X uº‘Vq¬[±´07§ÖªÇeUꥊÈ3¡(=¯Fj¬¼ëòKVÈkÑ„Ru‘•³^wÓÕ{Ðx²µžwå‹?NîÇïFK²ú#¹½Ÿ]Yˆå¥°­'d\ÌcYmÄ|þªæ,™Oç <=+wI-c&äù&-Ž·8´=ó¼’ÿŒË½ d^ÁÇ´b`7ö7y¼¾ÿó]²ž®nGæÝ>6IÞ&k1šÝ¾‘ˆÞ-Öt.ãżá„cŽt}Öëûé‚èz•>#Óçw7WSB¼äÏÅrBóX¬ßYh¼.üšîðÔ‚L,ž¤t€ûË×ò€þKqL¿“EúVV[mjÚKZ÷,,Ëún2Z0Í‹´z‰Å¾&‘=®ÂÀŸJhá)Q¸l~’aâj²‘\a/Š‚z€7u ßIí7NëL…"¡¾ âJ´°|Ô_$J*f©–É6’»½EIò¡ïæx³ ø¬~¾©Š¹‡ê0œåµÆ@ÎÛoŒk€ÄPÇá@Ï€DÀþºC"f.Zˆv õ¡¹6ìt—Ë´]9±÷Ž•hÇßµ’ä IŠè¡%¹©`a®£–v „.!½ê IæéF3wQi%£‹ ;±@®ÉÙ§äõØ9 i%“=Ÿ~„ÒfÀLéî®áˆXÔ ‹„wåÑ"yÊŽíeF'`”þ!+—bs-t ´þ¯šC䀵ó»òÑŒ‚ö3c’)žUâõµ¼¨ŸNä–¦JI"9åû cL ªqºÛ=tïé‚+S|¨òR:HЦùA‚à°éjBêÑz;ٮŸyñûoÒ•¹z©™uò¢ùÔçëb••†'§»ãŠFÔÙ>ß”;³û\ȶʿf“\w›ç ‡ÝëBòZ•æµhÓͲ£Üž"Qªâù#t—˜Ô7.5·9 híÂÀÛôøÌR eø¸Û*{Ì¿CŠSpæ Œ²…5qL½)VQŒª†ÍÀ‹¨N¥ƒ²óh‘:ÑWdoSù®/=ù8z;™A&Õ^<%2Ëfœd2¨åËë¸þPƒ,)¶Ù÷×cªÍü|ƱMsWg•å¸Vi3>W^ìNïš6†Å¦}™íâ+M½¥8: ìéßëÊFt‡:kE(l©>¤EÞKe±t϶ë|ï5È{šÚoš°ÐeœÚ]&¦Ya,‰žÜÊ“(õ6ÛeQƒB,Šé÷üA&ŸÔv៣DU¶"ü¬…¶H½¾à“×Á~} —k™E±‹)sêÈdô¥lãeYë__SòÝÁÌíªDDë[Ïö Häù¬|N[OÐh£Ø³Oð}b¯ Ìaañ¶`ÛÇ‚œ©´,^ñJË. [i¹¹Æ)-š¡´ì‚SZŽÒ8JË"¢´€Ê2•–E¯´,òx¥å’ó”–+±ö’EŒx{T#^úFz}»õ o³cšïB(Ξq‡¶ü10?ÑŽ7b衮 ÷µéWȦ»Ç=Úâ§Ù§bÚûUÖaÜéÝkÂÎÃàž/âé‹p„E¹ÀPå‰RìÄ¢ãX¥íƒVêΔ‘šjZ=æ;Ìzü,>g Öd‚rq? ú]4Q¡ç}vÌ7ÎR©ËSqŠÄ=(%\FÈ-c•¾¨UÕât\<^•§b[CÅE1vqHnH84É¢ˆ&X ›Åw“O‰×òÊØ3˜^²0ëåÝú~=š­À¡úþU¾n % /‹Y3šJ¨ þ ÿ«Ÿ[î&M¿°‹Ç€áØ ß@îx ßYá%i%gfPBKmƒåï-VÊ|s KÍ÷ôr4¢éýu‹‹Ü$óû£™#b*eô/$Å0ùÑ—.ù•- èzé*ÔM­N ¨cÎ@]EÁ e«I¬_6¦Ä‚´[õÜà Òfè]9#ÍH ŽJ‰}ÿ4ãÑo—ZoRW^j^´i‰—¶+‹§&ñ½—ø(Ïy7©×~›¨ÃÝM2!8¹ÁƶLãl‰㡪~³‚§½E fyˆFØ.Yõjuz ræðÀFfÀ”ŽÙvÒŽ}RÅ!¿+r9 Ô‹]D+Ây[ÄW£U2¾ŸÖÉœV¸û¿Ý¯în›`äl",}>™NîGñ$W ’äv¤ dÀòƒ@žyLæoïo“ä:™.ïgÓõzºäŽ7WÉ\O’Ñx™¬“ñhv3ZþÁ¡~»œNÿàäòq™ÌfÝÛt´}‘Œ8]ønzµœþÉâ9ºbe>™~ÍGoGKDÖmy›ÎߎfäÛ»åÍÝïxÐ÷¢´kt±L>r$p=ºIfÜtv÷öŽüc4Ÿ&œ¬oF³ÑGñÿ7œìß8µžfÉÕtÍ¢·ÓÅò-SÞFó·w³û÷£N\]1™$òµƒ§+Ô¸êhYµ˜O—bàÞÞÍÇ뻑ñd©7în…–£þv½ºÍ'÷òaý'gPß-åC*ïWo®³8m£4ÌýõbA­µÚ,ùcA¤AËœn8ðÑr¹ø“¼­ßMÅ?J_.D;ŽÖ –ƽIVãél6šOw«ûõtün.y°Zo¾^.D''¢—SNf‹[]@yÏ`4­w¿œŽoç SBDÿÎ+)¾òH¼hËé2s2¾Züë~²ýÙŸ'Ñêi“©ž‡YÏtq3]‹²Ü¯ÞnYMa·;_€&¢ W#ÞˆxÿGËX §¸Ñø.YŠ©gÎÑ«ŒÖ£?xЫÅíâfqÍÑX~ƒôV”ù*™%ë\m'Jsu%Q²±;E5ÖîwÜV¶ÊȤ¹›KãhrŸL¦‹·ËÑ-+³¦MV…ä\ÍX‚¶zqñv´žÊ·Í§œ>º]&þþn5å’xW-5œÅ™È§¦«î)¾š”@˲‰ûiàÝhvͶ6ý:s‹»†ÈL¡ï?ãnÄS2x%9V¼¬ÚŸÉdýNI÷õÝl¦ÿb—ùv:NF,õ ÿ•×'Ž5ÍF/5-êòÑ>þÃÞpÊÁZnóÖÙÊ‹¶M’!É£‘ÉΦ&’]o\Ÿr7­VÉÛ9bìý$©Óåx$ôƒV™0j¶ø“Z'ëÙ4ˆrÖ’0h!l 1c¦[žŠq£ô¤@cz¥æ7CG y}ÕϾç6™*; Ñ•¤êÎáýjz;RV ’S2bd¢Òá!`c ‰RÃŒ`w†9Õ uig/¤eG«wA»æ§Õz´\‡aS†$«:ŸŽEK„¡º§‚0iº7v’¥½²  ¤KD!®Êž$ š§òÄú5Puø`ˆNbÏ -lÞŸf´VD^ÄPr©g¥ŽVÀçúë…ÙÙ·¤/ân2Xh‚_ybÔ·9'ð†`TËðuRá^Wå|*‘¥B¸Ê3BHðü¦=Ú`£üWN›Þ þG¹:‰ªF8þ®ª3¦ÓÍ÷Ìfó &èÚ·?‰Êc,jYˆqM?øj5§€e䉮«ŒmX9¥@å¯î <¤-ÔÝ-Ñ–²ƒÇ1Mª~D4Öv6|Õi u^¡Ó‰Xwˆ‘(ßA-ÝÖk© Qä€fdWàã·Ä™YÉ׿߭ªœßÿvÕ~ˆ•¿”<,³º5Ä'ÄQÁÝ”¬Uð0cLÝ3ºÉäAËæ¶QâRµÖPŠæ¢(ä¬=ú} Ôó%WÓcô<]YœÉ mqò$È›YÕ_ò‹Õø¿òT~x-(Võn •H‚ñ¥ˆã×ôyµ9IÓçøâÞÿ˜å…4½û0QDQÊ&ZGLM¼l*¢XZ•pÖûòkº{Uû+k+Ý;,ê!r<q+téˆs¡ÑŠfå~“¢‘+ @B4h—Oœ[¢!ûÝ’¿©v@›é7nd]€RÆÐšî²½Å[qt„Ïi}#o¤hÚZ--©Úþήíïný=ЭxuÖQgý画óÚW‡Ÿ¡ÀËü÷aeÖ¾¤YþP¥Õ »ü6ÕsZlñš89yã ãá«r¯RypJKØÈøÞîÇË• ù{ù©PùssÜŸg•__çHS¨í Ž+d¢C$¼úí×_‘AiãAë–f®üª[Ë*’tA΃Tij}#'ªÖçë&B-ËìÔÏ è˜óÜ·>¢4Þš•ªßâwV%õ@½«N\~@Á.ÑfP/Í·³n…¾ªOÅ/ÂtÜÈšvß9wþÖŒ—çl|ŒVÑy=*DÈM ÌÐC''iì§»]VSÁä­·h°¸4>à~Pëí>6Õÿ•_ÚAÆ:L`ηX†1rv7C„j&Ћ™û;} &æ:oÀÞ™· ¤;Œ= XXfVÁ0^ Ñ«˜cÍÃĨˆy-Q”²¿3ÐŒÁ‰--vbhb´Ê*˜Î=òÞÀ±hcm·bñÆÚÒÀÇšT,æX“ŒFkÒñ¸c ¹@Ö¤2oY™­Kù4öU~¬E?BenaËô[¹k’×e#ƒïÁ:€SR#Ô`µø—UZÑ£Ô”{–¦3‹LFÄé™Gf »Ζ6#Z Y"þ¯+î™"ŠšÒ]UÝ8ÃŒŽãê0ŠE¤9N±¢mòJ†a>œa_O®ò§¤ Cv âϲ²¯HuIÛô˜‚ pŒ_7ù=<ó“ÞП“PŽVLl²“+o2´ÔÝûA7®âï ûÓîhGuïJŽâÓíVfŠåªX‚MÁÎEäp&‡úôp&‡Íþs€òß§r™í“c㟎!Å&ÿRòZ ¤9­¤5­!¤1Ý@l[ZMé& ²¤u’kH믞­?SSˆFt­v0ðŒ|‚F´ÂÔÊ„V?!×>6\¯m «Mê W0½Q ×Îø3Ó&DZhV2Ë(”Ì5«5³ª›NÆŒê¦$°M­ÑQ¥RQ‹Z'ãµNGìiÈ4§‚¬K1Ì•…| 1l0Â’&a¹N\—Z¨b M¬…bÉ7¡£,hb0É6¹˜—èÉÜÁæ}hýtGçÙ“òÍP¨m¶™~×/I˜¼E_Sˆb„<(%.² ƒæW^ûS}\eÇ¥ôzNr_©Њ‘—ˆoÒú …ɾBGyÓŸÁg%í•æ*OÉPy½[øÊÂf³(Èþß§ßWâ¿»«¼tÌ>/¸Èô{ó3,=–#†¢ h!JèçüéY*á &'ÙìÊo’ YéZüÞe+†Ìiä4,yxÍ‘¿ŽgP ¦Aëx†¤Vo"$Ä¥àôeC%-bÒ`—éáä¨å8ùÛ¯‡òC XX!ÊAŒøýµã}¬Fg%挥Âÿx4|® ®’Ky!¦¾kñ’JoßLIĺó`И`´5ò0ì^”MÀYfzÓÝîx[~ûÇoàr*‰g¸i¯5j®8´nM µ=ô,§Ýáõä`Tš¢uÌ7_^Ô,/rðÍ8Ë’ùšíʃt±êü:yïº) ËàtxM£ˆ•„‚Ö"f!e*Êåz Ü‘³r°èÞ‹4}1q‡*K·ÆB°gÁt5aZ7ä²ÄlwÊÐNv;aïô±ó¡”L@o*Žãy™mzîN:BÅ(á0_xË£z:ɫб7”Qr²À:ªÈ7¥ )eô·côëb$ ªè$ETñÏ)wD/PÒõ³T#hy±N r¢JO0ë@hÆfI—œAÁ-zøé@RX⠼ГIñœUùQnäèÞ›•Ë'b|µ³颂ØÍs¾ÛêI&úÄÂR†°Hζ™H}ó³÷I¼2~ BNúé]8 œ†¥ÝWG(ëìµØÏ2´Û1W»ƒçbŸ ÒáŽ+”&={.†©%:tŽÙ“uÞË_÷´p»¡K„¶)ÚDw7¢ýîûÛe‹E#ž¸(20ÑÛãh¨]ŽÓ™Í ñ:³Cñ.ûÞ±i›£œ'#©®ò"­^¢Éî é›Ì¶ñU‹ÌJmÜÈ•œwbÇ2(`æ ,%osŠâop;©¡­¡ŽíÚtb‹íÛ´dç¦MÆönÚtt™Ô RtÅå SNŸ6™¹çÓ›`‘âç]J2a‹ÉàÁåËz”bî=u¥{¿]Õ >¹Žn.‚»Óö‡¼:ž¤á",©š­M2d üÙ¯ªN‡˜sç ^0É+Ÿ¹DpÏ™9Y8°,‚Y¡?Hó@@Û@§@†Jq­õÑ›¾ÕWjîV€N½MV ¼ŸµßóÌ)›IbÍ×Lg²æV'&5éÊ_ ª{…àÌ)Zbý²ñ&g˜–¥%aRøLš™šÎ›Ëµ c¹JEfq•†Má*¿u› “·-8¹A¦m•Æœ³VÌ’˜4; §}±KæNšÖoþ\ªEŽšHoÒã3yÜC¦Þ—ÛÄûT¥Å¶Ükþ6+äq;{^Q¨¢9ò)«ôi÷`…‡ÒGÀA89©”:/^OlUß7e ~K_ð{Š1J1N)ÆêX.ÓmžHÊIöTeœš}?€ßwåø½þwu’étZeò¯¼>›(Ëw ­Ð e¦ÈCÂhcüg#÷Áµ 枣2Rœ« *EÊÁrþ’-–¯¡Â=Ô¯ ùý=‰ü~mkÅî;T‘}ú].ý dÂ{(™p e!ÀÆÚ ñ„ó p"ÎCJ:”©@Ú3]ê…‚UþŸè‚8¼Ãxž%:/•_o’=ꛪL:H”@r‹¸:mžUpâ¡þIRT_L –mhOK:óyíhò À”4®)]¢pñ6æi·»-s¹é)\NÉ-¦4CH˦P‹Á‚”Q¥!–v“ŠÙÚM2jm7鸽ݰ%B[7{‘7R7zàÆ(̃h1ÊëVÝ‹?B>LÎÍg0×&¾Þ€ÚИH© YÁ4©Ì5LƒÞÈx¡-¯Ë]fµUóǸÂ:m´ÛÁÉßÒüè.c­¤OSøµmÿQ††ÚؽÉöeåEwxýwÃÛɜƉ0:zì §R?¾<ÕÐ÷Sµ¿ïÓü.øÌá†ù©>dõ –©¶“ÅZ ‚Róýa‡r–‰gŒq®³tw•Ö cæã\|%j¡CRŠÂ¨%n*4œ\V8‚:­¤‚É*ºM_v—>¦ðy½}˜mKU^²æÖ…CÀãÎÞü3‡£d„gEó™0¢Ñ97áR˜<©²MæÎh->Bþè/]wCª6TP¾ëÒJ¬³‹ü1«,¦]PÁ‹„Å*B,t ¿PA†M†mk›%}ÒjAN5C‘izÐj1ç}‚ úæž²ràû•(-¯úFü~NÆg ­ß¿¯þ†HrS°¿s FÙ‡·U)™Ñ¦Jƒ À6Qô°°»ØžmÉòòóó„Ôˆ jPb±B BetFJSûZNe ”š}ÏÁÕi›¾½W•/`{VÙã/×¹ æb¥ùzyP_Ê–§¢Ây¸„lãÕ&¤ßãq± „¸ U’`ÓÑOã¸XFÆ¿33î~éó‘Þ V<—Œ½"ÞVåé@v—ˉUrèû2{̪¬Ødh^?ýû”ˆäSÑ®>ñš‹YgóO-œ7#ìÔC•}ÅSóâkù%kÿöÇÚ,„u•eEûÁ5Hm°ŒÔA1«ÄR÷«»·!~·3 Ù:ZbÉN]½*²Peõe•mÊb›V/=I¤1òÓQAØÑn×ýí:œv÷fùÔÉð?¥¤¾ òp¦~ CVΟðmM û({Ÿ1ƒü7¢ØÃùþlŽ|I{Â×õ[Ñ8€)ù=Áf—¥Ð¬Ô#òzZ¨*A“rË4ˆÄD̺”K?Ú82Tˆ†C&" Ä!÷&”žzß â·›)^3i²8õdЄu”&;š£­4Pn½’ˆ@‘=·ü ÜŽ ¼‡ñÁâçy™fˆìµŸæw³Y2ÿónz7`¤jÓgjâÐfœßöò‚þn÷r[Ê-Äø‘¨y΢n2ïÏe0˜>¨MVåãšE-^n&6Ñ’ "Ï]ÔÇt aÓ “0vŠ±Ù¢“1Ô’fé—è–´‰"êÏ$d÷ª·Üuà¹Ôì€ÔL4§«Õýíty“¬VÉb΢"_UùÖm-¬‘@ã9KeûoÖ÷‰û– “õ *wAy^òÚ(§9aLSSýý˜ ž{@ui*yÒ’'š IWIAŠì›¾o¼6“°mÎeõ9Ž—<ÒŸOö¶,x²Þ£(¢ó¾*K±Ð(@V°4u”/G(d@bŸ óÈÆÏ)ä§K~“d+y¬ ¤[‘tÎÕÜŽŠnY÷’EGöž$óB¾vt×$ÿÚBGèÚn!v aÌ26B0-Ô‘"2p Ã„` C¥` DÄ arð>@‡ Âu€—„I@·©ç*6b-Ÿ£ÌÕ†)ñq_­¬†T*“ƒÈå?ÿ ê]d$_5ÚgǬZ¿2Т0ÑÝ+,ô¾ÜæyVä„eÕ[y¢îrÊåExpÎ|!¤7m^ÃZÓßZÍkŸT`wjµú&̳°)rr‚rOA´¦={3ÔÔ]…ƒLÓ¢ÃK'cK§º§JíÔ£èC<•2B :L:ê˜Ò…†F”bU¢HñÕDÁmz#Rd»:ÄLJòXà¦U-ÜØ„mÍŽ 13`S³£ÂŒ ØÒìÈ`# ˆÛ™f^Àff?@0ã¶2›v<×Èìxà=ؘ=%Üõˆ‰Ù‘!}X˜ÖùˆÙÑaë š é~ļìȰþG¬ËŽĸ´Ô—Ržc=BÒòKН¥>ÊíoNâó“O¥ÏµÝbŠZŸzysîÛbV¦º*f@Ý SÕßq4ä|$³·ƒÁç°ÎãÅØXp—"kb¼šfK¿Oß¹Ä_Ð:—)ñŽV?B‚÷èíÝÕ,'Ñ0™Žg£¥·ñdB†l=yŒÅÖSÙ&Þ&Rk 4¨bÔ¢nÒ1“ºIÆlê&¹ÊާJ-Px©ÛëÜHZë †T/ fx÷·äqÝßR…,ö¹ì8ºhÖÀ=ý°ÕoÛ•q+‡†*°thP±k‡† ¯¹³2>ÆÊÃËk¿yÀCÇz#< Ø‚ ØA–ɇÑzÀ,ÖÓñQ•-jµ­™]'ó‘{Àaòq>~·\Ì“OÜ>,f"»]ðõr4_%ÓùšDÍÕ‹q$$™¯§ËëјF®V"Ç1›€$­›ZT^ß K9ß¼F6AL`•M YŧlËÀÊèݬìÕÁO×b#¬žBáÃ?”;Q€§ZÂê(ê<+Ž ¬¾ ϪȃҜ cGõQ>ÏÃjÖ*gqc1E":ø;oÓR#ò_¥ä\v+óï8zÓ»ÕüÎÀ*ﱉɧ§›gДöÞ9ëw ìÊC#¬!& #ư¼åÐü !äÚUÿ´z®ùö"'¿6QÞèuCÅ·iév»z>·å·â]Y~ñ¯Š¼éôù×é'ˆô9Ý¡Å1oôÕ‹b*Kþ «U¶io¿nÓŸhÕÝ\pÛWf ™Oñò»¡pï²8þç–×+?€å°:?VY¦ƒ99‘×ZÀ±<¦;ñ´AÆ suôW AÉÕR–4« «±1¢€ÚÓ2Nw;'×AËÀûfVp3ÉgùC•V/QY64g䬶k7ú´r¡“3pB8œÄÖ Ñq°b@0BCtZ2])´åá©9c`¨½†zˆáê“2 ÖB^%VMic­RŸlaWº›´HŸ‚A6|ôñ9¯_ýJc€Ù˜7p•zìx.)qÃG‡«óÛÙÕùmpub*óS^ŒŸ3ÛËâCòcpaúq5cõ 9—ìXfòýÙ?óBu<}Ûr¼ËeZmyDYÏÑ·ãô«0„Õ—:½¨·ñ˜eÜí˜  ÌÖ¬ºHÍ#¨Êò¨àh''’™Œ…Qð¸t˜#Ý„h‚a¡ÀI¦^ª–Ñ{ ²#wŸ“N‘>§õÈìOçÎŒ W(5®@RWÜtÀçR,<¾C{^µõÒϘþÎd㮊cóë9|rËÙûq"f10$a$ÕeÔ âà¿ðB—ºÞJ0R"B×vNH´ÚO<ÐnUPŸ¢<³­¥>…ž "ø„ŽýœÇît%ËVÙ¹¾§.øDx~PJ*舢…bO ¦€ËÂŽ0¥|,`å2ëVkÍw’Õ›*?Ë€)ãÑϱ«ùR¥œrçTÃdYI¶Ë†Òб^ˆ*Äy!¨µ¢¶X¢*Åah¹oäÅ¢MÚ…Õ”ñÏh»­¤?å,®8J®*Yu̳æÖl@™4/¾RàwúÚ2ƒgsräÅñ}ùÀ/¹Ú×|B˶f‘™Q~ D+…ëk›ÃšýÖ5*‡±YeÇëTî»»íƒ è>'?ýqhÕ=» °ïÈö—Çgû oØ>ÖD°3ô].ÏÇwÕ¨åt|À’Æ‹ù‡ér=]ÞGãwÓû•Xa°p7[ ‘ÛG·Â3Ûd–£Õô>™¯¦óU"/&Þ/–“éÊE˺¼®Ja—Tݵ&’qjÖãn€K€úTÈí*Ôd]Ê%ý(†9Ž×W,Ž’×º”|IŽ„Ð³]gúó˜Nucì9éWI¢§Ú4HW׫X|¨rQýpuz| Ô)IþØé£Fúi#šl$¼cDEz­Xãr/Ú^Aîê ”¸þüùŠ$õÛž&€“¹Î+<e•IÍÍ´Wé:ÚBóHO@"•ï%ÉÛžG¡˜E¯ X)›îŸ°>¦Õ±F@wU±ÂcO*×–ßÐúÈL…“ÅL}LH‚΃٩8<\f4 œM}’׳sô25EÀ¤‹˜MJ<Ø ¯²ÃN^úyøc9+¿e•1àÔ ’êÆÌÓäÁ¥¸;ÎεçÁ¤¨ò=»€ú.§höçÏÐÌl0~ñZúÏÌ~íñ|Á;¼|8“*®lŸâà‘Ü™háïãà×qð ž«;|L¡c8`´‘ÅXU5@dmÕ¤" ©&µ~–÷QñäàʧF½3³pªl =¤›üøBbd"—¬¨OÒÀi8Q•ȾÒbË‚Ö]à} EÙÆ $l!÷9Žv ‘ÞÀäh¾Ó‰­"X¡3#“¤°Ø¤†dŠI9¼ÀÃK hF&% $™”€¾ Qnõ9Ö!Ý¢I[qާo.p Í-ÖÈôÉ¢èòB¨fQíaÝR_b€¼7b_«á´†iKzF®gt€‘Ú’ª-週Ze_…!Ùí!Ê8üŸ«VÊ:¡&f1ó5‡Ô ¾+xºÕòmÜhV[÷¥QƒL/8OÇÅã•Ü­¡{µ(Æ/ÎŽ°¢‚D<«)È&›AãÝÔmAÂ}Uƒ)Ñ÷X[BþõUEÁ(§ÀÇòA³ª¾¶·“€¤CU€è^ ×Aè¼ÃA A›§Yäº?‚Í RÓL«*‚@ODq.ï¯Ñޤp¤.V ¿Fóxò‹ñ3Ájz}Ê~ï³›|·Ëk÷ ¯†¥ÒÁ¡8À.ðÉ]?4Ãe+²åy׺,ƒ>âv˜åÇþ΋é7ê¿¶–‚ûn5ƒŸ®Î¥@º©½~3À½Çá1”kýC¸Š²fÅ×ÁUÏ-6œÝÈ2­R$#Æx üt¨F²"ÁXn$—†dŸ ìü«ŠÓngFp k1 gšŠˆ:òB{)+õïTu2 ƒídëJu3kQ~­µ¼¿[È‚¡…xVõŽÞ>¯7¿¬ò'!$ )×2KÐp¯Ô@éäð”—°äc–VÀ^3²EÕfº&âqo>ª¼t­—&I†ø'’eÇò|¯…”ï²{!Pê6Íö¶Ü’ ¼{(+(ÍT¢Ixr#P4ß7ú»qÉåÅs&/Ý67å­÷ªÜ5—ßѦHD7ø7»ºJ”‡5vÃâ¤öJj¼`2FßšFÊ«d·Ëd±LÖäùbyC¥ËëfD2m¡¶"%Kÿ­â¸UÛÞhlõp}ï @ó"ÏÌÀ9Ö»,;¼~O¥%`¢AØ-zãs1xœ¯a ~+ âÎć Édè@8Ó8&Ûñò¤öîáþiC`úÚM·ÒSåFŠ]|0ºj'ŽblU§’O—,Ÿ @ÄA>˜mV ½çîxt F;"¤¬OµrõÂ-›Õ§½{¥¥%”Öªžr\û°UìÔ)uóâS˜tôèØ Ç eºÑ‡(OÅ.wVˆV©d„þϾ„µ§d¦.Á\Ëg<Ü—BÚÉ¿”'ÅÁºë$¸U˜²=í*W´ 'j*w-ïNpšdPr̰& 9×IØwØØ›òYQ„úê úLÿŠµÔ¿Bke¬—ZÓ]Hb§9t†19ÉìûRÞí-öCÜÔpaا'‘h*lÂê´}úý5e5¤Ñvö6·@ Túu?ÚíÊo+Õ9°u×SÛx€Ñ¦ÓÉ…²lÑd:•0H,Owb$ñ6BSöUÜ‘Ü*¡ˆPÅåM/ êÔ@R_uVxT@1v ³X º0ƒ}ìÈŠþ„$¤c5*4aiTô¬Å û4.!umÔïsªÔ4í´+§‰©¢Ög#£¤MÙ° ̶>“Eµjp Ù¨„‘g©[J¡ëÛPd3;_øwˆŽsWœ“A²Kf¢º*tÓJàTlÒÓÓ³ñ|¤_"öº£i 9éýdFu5m‘Áó¾ò[°®šxã÷Mzx5-Ž•ùŒQ•=þòg–~YfY%¯Íû%&øxçã‚ØÌ§`Á`qg›;Yù67úþaßè ‘…îöñ³ý-*[úp ºŒóeX£ Y2OÖÉhv?ÝŽÆ Û $;º¶Ø:ÿ*­Èú¹ÜÖ,ÌZ/l lu€dÒǧ xw¢C•}&úQƒfì€ù\gèͲ(’éèQLã79ôSsOþ’1ë¾¶~¡¾hÛ­Žé.S%äçaŸèŠ«Löýp*žÌlù# Êäõp^GðróñnÙrÄÝÃÀ ù¾¸ÈÂ×ÃãKðW pr%&î¬aîð´‡$0¨T®!Ì»ÑêÝ}2/§7Χ&ŠX÷ûYK# kv‡›³tl¡PÚ0î(—P‡ëµ¼ë`WÆ8¯Ó1¾ú}˜uLù4Ÿ¤ÝUÂÓÍ™åÎw[ÝYL3 æÓ âßÑA ®ˆÑ ¸õz$4|ÔCºù¢Þú“·Ù1Íw7¢¬é¡®ªô(l¼ØÉ ßVC T—ŠáÜêiºçv¢‰#¼ä ýèŽcœ¨ãÏ×1ˆYþò†ô1—çhÌÚ‹b_@ïŠ/Eù­ˆ `fQ²!`qòKT§Ç¼~̳­Œ¬î–L~’ CІ#ÙE<eul¢ú6£Í-ªJ».«}z„Š‹³ÀФˆ.þâÐ<8ûFÍ#Tœ„WQ÷üñ…+&,`–Ã&Ô· „™+súT”¸•ÕG¸@*…šéþÌ‹ßkå œns þËOÀ¯¹ pt¢CË>1oÒŸ›/XÍá84¹>nóâþqKÊÓ1€Èª*€™Ôjf eFĘ́6hŠ/‹Ð«h÷Äñ‰âü¤ÐCçJÑ·ú\ú¸c©.µ³Ã¨›¾¯‰úÉ3:PÈk ô-Íbú¡ ð&…Ѷ=ëh5öÅ$ö;Q…Í®¬É¶ê|¿¡*–ŽX¡]¶®Â*bú§ôqÏ^BÙüþ#Êþ÷¿¦ìÿVvc"†Úó/WùÓ$Ûä{Ëåa{ua:ü<’X˨ X¼VsaËÅÝ|rwK&OÎIÀxšÌú€Û0æz¶X,IÄ»Ñì:T… –G¡¦¦4ên>ŸŽ§«ÕhùÁ…תÅ$˜Y‰ò8¡u‹)Š*AɺíÝYð&DGÖï»q|êÓƒtT/Âl/_:ì^.Âl›Í»‹Y.MÙÊ4³È¦è.‘0)Tì,’¨ÎŸ ó<:¨‘ðäS¡[ËêŠ3ªÐŽ+Å=¶™{ÂHÁ)¿f·¥PÀ³ìñ8˜x™?=GS»aâ<¡Å˜_Î% ÇÊój——›é÷‹ðñƒ¼¹†OÏ'é…2RVýGc\ðrŒ žñTô†ŒW‘|ŸÕë¬X—ëgWÝôsHT÷2: UŸ‘Äæ$éÝŽŽà+d=µ0­®Ä}ú„§ˆéö´um«6ý!?ŽO@²Ž9„¤ïÊobi´Êää1¯êã¼,þ“U*|æ­…‰ßpàl1{3Zý—Z>•<ÉŸÐR­nF³™¼Út3ÿ.&wã5‚”W Æ‹ùj=šcC)ï†ÕX^bz¢’?M— $i1Ÿ")ë?1š‡búýpSnõ1޵q¬ÄE Ã$ß ­! p²?j$m+ÛX6ö¬,0” B>Ñð=Ä#AåPÎ>‡À ¡…ùQl1„o‡:ˆ$Ì$ sñxÄ—뉡|Q-‘ ÇƯµ¥/㤎ÁÞœv#aç~6C³K¬¾&Q׿—ê]œD¿û Ÿ.ɺ°¸XV1yªòA ûm%æ0;ÖôщÞ>UW¬÷\Œ(f;yõRÌ’ϺgÕ1ãGfq ^rê:«g§MZϲç½ù´?]mʇ|õ²(wmëyk?Löv}«öI#„Â9®Tµd´‹¬Z¦ò! ´^ÝÈÀ+æhQ‰7'u²\ã¶ÔØZ5PÍ&Ó÷A¾Ÿ™¦QKç/‚‡õCª”ŒÈý3&È2yXv3:Od5=,Ï–Ùºö’”"õ?¢Âb¡Rq×6‘‘Î\«šf5*¶Ëî#„íç(¾Uˆ]ÜX/¿yKÓÉÓæ2⽋êÕsþxÔ3)Ú'R!«'4ÔBÚ À§ª†`fç€á;k]©1¬€%PAØ¿VĿҘò2­/øÜvOTÿˆY¤Üno~tûR¸Ùö$æC©´()S¹ B=ÞZM@õ¶P†ódßš2cBn¶ÛE‘½¦Aº7~;oin0û-vP š¤Ð‘/2—ÈQzÍ8„°Ç,@)?&ÅF¨ÇLÚò„(¤Åe†PyüýB|Šò©kDCÌËËG±<ºRQ©0K±Î@ßÍ.K«t»ü0€Lì}3¸îçŒä5>è['Éb\ ¦/‚Fæõ­½‚C;jƒ¸žƒË—t=zYžï£îtšç£8Ëx>êa|pu×­šSŒÒÄHbû&æ%ÈQvgÁá.ì~â.ìÎR¦\Øú5:̲tÛH»ø^“ZþXä#†«X:7#ýÆÐç+bE”~ÉnKýÌ[6VBÚEÚ‰¤†’€„R.ê¥2|Ç2ÎŒïÓɿɳËË&V8~´ÞoЧ•òaÊSÞò,,!ÎØùÂw\åÙWô ½ zè ¶v€Ó¿IR/õLvÏE‚©ÌÍÿ†è$hš{‚n·õõiïÁ4yçÄ›#ÚºdføI'Mþ»“öæùµoðZ Ïî5°2kPU&ïk}=oêmAª÷=g)>Ú¼ûŒ@ôˆ¦1Ö3ÜÃña 8¡°„‰ó¼|’ 䜂áûþÂeY[¨Ê¤°yY…bJh&´í âýðU6Å{XÈËöÙP™a/µ ø£œ?Z{#Pܺ©ViÝF¥gˆe÷Ó™2Ó± x^Ëe¿­A!”´1°é׬`ÀÛ-5W=rMK`Øô®º`Cõ~À t›mâA±ßŸvõévÏøhÈÉ,àh Ò8›ñ2ùüã•Í6l¢|œÇÚ ð¹œUa‘…µÛÏA»âÅpü³¬¶áuFuÏÊýTH³>ÛJ…>n&÷ïCãX”YÕüsò>(ŸÏ/U¾};žä‚L¥³xÈ‹´zù+²Øl=’/õåô€^¶X½—õæÖqÑÆ²Ê>åö÷ßÂ6@ŸñÕíotýÎ*ìF¾l#>æßO‡3àYÌNb!±5d%ÈÍ]l¬ÔF–0³H¹Ô ¸2€“(t„‚£*“mGöT‰€Ïay³0_¢ß¡ÙÑÅŠìøËèt|Ίc¾¡øû@ñÛú€+yx¥>мWù1cÀnË ÏÖ€Uå±Ü”;tàð\mž³=^FwA¬¬•£-³ÇTPMG{7${UÒ[ÑßÄÜn$öaì$U"þR_É{J‰/œ/?÷ÜàìÞ ¥kÏ¥Õ鯆‹Æã å¡_‡ÀT«—0‡ýá8œ^ËP,=Ò¥œ^pÆóU^l«÷òóªÜ|ÉŽîÅ{Ÿ |†¥q¼l7.‹Bh‘¨òx4¼"adp©Ž¢ ßéWH(ç !à@ÚàÙ…9Àï–³¦x²ËpW÷0~æÍfýŠLèzºŸÏµ˜zJ+2d -Z}—×NÃßîñùø›¤Çô©J÷·©”ªDòáôˆ'Z~V Ýòâé©ÖY8à`O[Nj2±¤…ñP ¢óyÔˆŸ:C©û´¾.÷1ò‹±¥ƒª;C¬Üý4U7†z¦î+×;@¬jÊ¡)Iå½l ÀÔë,¤ {#&TëhÎlùþ°ÃS7ZeuÑâ)Èn.òwF‰”NÄ!Z“áHëøKL„ø´uÕñ†PêVÂLCŠt›×-5SC”BO+…S÷ïœû’LÖ¿Ê6YÞm&F·ÑÄΩ›bÀ¨àqUÊ×&˦$z–=2ÄR4›~§w%÷w‚|mx€ùR·lŸ‚ʉÁÂþ’ˆ±Þ˜%@‡{²ïùêQrä«H…ÞµBAÃqE©ÒÃzIÁí‚=“~€ŠQ´ƒ¨¢>dÙlRÅ%D‘ž3¾›’×ëÙkxÊ5pO÷3d•8ìÔM¢™,5":®=¦ÅF4ŸF׋Ƽ[¯oï„1ãåt´žNÂÀÑx<½e!ç‹õýènýN>ã9Z'¦yé}ÝÇ’&°Ëéjʀݎ–òa„0ðæn¶¾¿[$cFAo¦“ûÛéò†‹]OonÃØÕtz¿X¿›.yÍ{³˜$× §3îV*âÀ¿>†¡W£‰hÜÞMWŒæ½›7]ü‰SŠÛÑG(\±O–ŠëÅò*™Lº@T¹–q©xU¼™ŠrsÅX ýèjÆ ÕÊJð£n–ÈæX'7ÓÅ£µÅพ%còmÄ@ͦó·ëwÝq»œŠ2Ü_’.*—¬?Þ¯‹ûÙhù–Q"Q _tÑÐHé[ÝÝÞ.–k9Àúx©ä[~˜.ï§Ëå‚1Æ¡‹–óÑŒ‹—²’ÜÜÎT8|NIA|+ïŸ#ÆÀcíƒhxž6\ù²%še•,èqfí€&ˆO#ŒCgV3^ ƒIž|’IO¡œÌ0Òp¦ÍfÕšŠCû*`Þ6z¯ aÐÛ.ör„‡ƒº£,ÞeÒ®¼–/aOàè£ï»³²0Ì#æ#OµÞHüþê éþê7o«Ug›“|Êð—>)X=vtXdŒþc±øjœnž3÷1ϪF(žËúh¼8J ýݘ}?ä:îw‹î#úË¿÷t30ë®* à§^Wå^r]eÕ×|C4#£3ÔKÀ³^ÅìtØ [$À±Y«—›S–Æò¶‡-È3B;.4 z-7r¼ŽTäò²íÈžg8^o—ži„0¶ŠnL£¶‘ÄW/Šœ¸ÚËO×ÊPêÕé…÷iéa(*éü)T&-'Ç„!Xñ²/È<¯ouÈ6u™hÈ÷]áÌ1"I„Ó¶ê$2m)U`:ÑJ¿4ßCä7i‘?fý¨îèÛFþúQF ú˃ÑQÔóá$oÁ»,ú¤p5òâ"Œd\¾üQy”l>;«¤HýÅ€øù›t÷XVûl+8;gå"iC„i F"a}î–¯5Í72ÁÞ2ót(ŽÇPz_Xr“ ˆÓ(.)¸Û °=T mËBd“Õk÷2/ÔÝœIÃ%V{¬ƒ©õ جzìßx‹¢2éÃÆ€Ÿ=µƒÈìÜô\üdÈ«´Î7}ª‘¯MÅ;Ùˤa´y¹,…ÆY—rrŽ:–ŒP2«@å„O{SÖBqª³Ê™¿ä¡ùFâkä±Uk„\ˆê]SªÀÔŠ3hSÄl0öo'&씎¯VÛå€Qõ©+Rµ:ƒaÙGt0çt0ÜÃ:}܉¼"øÑó•7_Qüݹ•DæQŒž}ž;ÿP}ô 4}ª†Ó޼3=ƒ­õi1ÀJ~Õêçêìºk>oàˆ©¿šG5±²W4=q[o.ÂoÝç@€6²è9//B”¿ÅÔä7Ùç•ìˆZº‹²JOK$E°î¿…ë° |ŽC[ã÷˜Öø=\·ßÏì×߇ÖĵڠyÜœ¹ªì1«ªlÛ¯-×ð”žô Äj1þc%ÏO¬j7:]NogCÐñâæf$ŸX[È×ÊÖ äUb!qaÍÙ˜û·Ë‘³É!—Ó÷"ç(¨< •L¦óuÑ$¹¾ÖdT‹#ò¶*!¤<‡ÊÁ5·q%\ ; ý|:ÞÛÖ1„øFòÐ?ûMYû¸½“Ûãý{30ÈYõ»5Ïß ³Ta?­Þ݉¡zM!þ\Ôêõ­ÝO4Ⱥ´¿ø¦sÍ"íº¤½Æ4“HÛg°ÍcZ,¥R*ã3ª.¯~H2ã `C­´ê#ÝáÛòœ¢ÉõJS¿ý>-¶z‰€-h^rk€Éæ³gÂ|ÔÙU{“×Å©ÅÚ‚îòú¨BS ù@éÁlTælõ 1&©ügÁ¢MóÚë¢e ±¾­Fø÷)¯²ë ëú€K]ebU+j*“¼Vë€í¢jÔ(ÝírØ–ß Õœ4窎Ƌ0o~s”l=gpªŸWCÅ\“Ï8®¡£¡"ßóÄ®6–~œ\5¨‚œUl NëÈO‘ cÉ]6‘4¸û%>žçEé€25 2UjcáœEVš÷×J†L„ßcFß½u©‘[¬™i~vÇÊW¶72V‰ºêÞJ'®ÈºµB.ÈZ0æ9#¿ò—É´SæåRWzˆö«toÙÝ¥x«m°m[4wmÝ®’ƒps…ã»0#ëè('Æ·•žm <¾fÁ¸ãófÿP&ÅEJó)>ß$1œâµ¤­‡:5¨tÒFØç=Y¤YÞ+µõæ0/'Ù.}y5 ±¬_S3ÎDÿ‹åà'P`ž TmJ½{Ï‚Šx`ð!"ôÌBz~È=Ë?²ì0ÚÉí'¬¡{ÔÎÐ$Ù0Ç—ZmDNŠÎthL{æD®‰é¢y&B…–&t¬Ñ\•máïþÁ~#Ñ e®ü¥fÀ“ñÙ ÷­¡î±ÐíQâúy=†8<Îðuœåæ{8hçχÀtØ5kÁmÅøù³¥Åfº6œõLŒZj\;^N§oYÎV³±#ƒExÚ§Qìàýwù¥˶ïŸÌ®†7|š¬|$ÓA+Û³ýÄíúôÚͱÌÒ­ÜHŽ®4އâq `ê/ùáµ}ŸÐÑjÂâÚÂÌRÌq‹kXý0Ø‘ô±w¦èEÂ}¤ÑzÌ÷ålàz,ï#O¦3ëj±Y-Ôfçh2YR˜åôn5%A‰ŽŸŒG«õ}rM1›%ó·S2;ÿʲYÍ'Wwd6Ëñ‡âéôv4³ãRØ þ.”MR‹p³¡¥kÌ?K“ Ô&T'bˆ>±h…ò§|‘ì56=z!">êM3Њ`ΕBÎÕŠýv§ ÃßnõàøGOƒ‡ƒ=ÿôƒ™%«µgÃCè0b9]-fÀˆ2 s;2…ŸÉlF%Ëh÷7 YNý‹Ä,“÷à>­¿Pé©:ÿâ¯P ÈÆ¹ªíóЦ_Frù–ï¶›´òJF Ñý·üø|ŸûãÜÂ}ÒK²’«§J¨-²àê•Hu=ŸBE4ÀÔ]s…Œ…Šh·zRÙ6¹…xù~³=å½+eC7à|³ÅéÕA•¾² eGæ¦.Üe¡O•‡²-Ac䤔gí1( Ýn }òT”UfT‡XJTÿÌÖRl‡óá]ÆöÈà[Þh¿Q#­yBW")ÒHÊ"ûÖÿ5.w;}øˆ¶ÑƒHÆjv†@µ¼´¨E¾¢ «˜ˆ™¸¯:'÷"SƒÏ¡ûHÍîÊái÷‚ 8™\ÎÓ§l§œ·¯4N‹Ó>«Wît€Œ1ðò€L¶¿…€é æƒ‘CŸ#€‹\šBµ ÏcK‘ÞÀ›Ëý‘å󨈶۬›g¢Ñ©e°L&‚ºÈäCsRâ6=>;G[Ídçó³ E!m³üô˜[AUä§Ÿ2kÏT~KOÇçRŽ—cj½ ?É‹gIñX:Ÿ«ì( F¥øÃA}Õ’Ûx‡l“?¾4‚/‡­[EoØÈÃͺVZ·a朱•éÆ!ð-\qì.Ë }¨áµ2Û!"'Ù|Œ® NSè¼þ —ÝSA›X’¨ +KÂ,²f.¹I‹ô ÊRº£Ïê².ÊýB2(&žJ0Ö¨Ti<ä]£VxèQ«¯˜Åð¶!ÚÞ³R Ú ÈB#Í 4r™=2€<ßÔ¢~uk±‚Rå²ÇœÇ¹-£¡ÓïǬ*ÒÝuYíå!+zÅ ÜaØ.w³¯i×Ö:¢w‚0óÅ%wºªÉß4Gàðr±tp(O-: ­eô„½|QzX±ÜY¡ÀésVÞÞsug3t¤;˜K=¹dñeWá'1 £iÛR­_‰t½.Æ:²ÄH¾Î ½VG1žÝ]5›&7È02Ô´kP˜Ï„ùãM¹Íól»ÊÅàCqà WñØ?¨ÅÁ(Ñ%¸A>{#öÞpWì–ªŸÄi5P‰‰ë{ oƸÆË×Ô×teŸÝ‘o?DbÃÔøëŽðp8^¯Fwd4]Þ4?ô3†•ú ì(I§Å¦Ü²“6ù´{Kâµurת÷ChÈ,­í @‡I¢úPÌ’>~C¶~ì+)ƒ?²—Ð)²1biÇ\W.L6À©k3Š~ÈÅãu[ţ޼°bÓó½ù¶ršèiÒ9wî™æYÙ³æ2K[{é…dM½!Ö M ÔøD¬AJgÚÍú¡,z Í0±M€×ïi¶.< 1S…×¢¼:öZÉy8«Ž/¬ÍPºzaޱãDWéò%e3Ž,°m2ù[U`z ¬6iAØ)DÁDÁ‹ÇÇÛ´¶,!×G¨¦ú©;{¥ýÉÅHL‘Â’Y—Ï‚~Å%r¦kÍÙ/OÚVÍBG#F§fyØ.¿šWRÎ-À¶™”À)-†·:‡ñxøŽp•Šá ˆµÀ;•“LX›­]t¶(dQÜ&oÕ‡/‚•é,L‹ÚŠNšgÙ¶5˜aÔ&­³Iþø§"j“³"¦B`tó[nÙ@½m,RräD }Rر›£:Qï;†K=¡‹Öë~ðØŠ ¶†ØyvµùD1è΋8Dd®ÈQ’˜|×ÉÐ@î"ûõÌê©l3 åœgÁ=Õ d;m¤WÓ!iäƒö…¼[bÆ0g\©ÆHôÅj75úèŒQ@±°k<­ÎÉc™°Ìöå1sC$ÈÙ_>tEe|éÐn/H†rYòU¹G~éŸòîrŸ^«XYM•uà,£8uw›‹ÀMƒrUá¥(-šKÑHI ¡j¤WõJ ^õ¨W£î'§Èݘ¯–7Éx— CJ_F¸¶Ü¡C¸™ÍÎä¦Y-»ó܃€ìIÊ1->§»]Ö&{cĺ8ç™'´`;¿p@ ¾‰.)ŒS¢ò&¾Þ$·ÿºJÿ@”•*]˜U•=ÉÈ0U¨ªòžö#G­†ä…JÈmÙ»SÁ-±dÈhË컼®a°4ê;¤.Ñ%-ÑÅÅó¯ª!=„âÙ™þÀ¦dWâTÐÕøÄC±æ{îÍ/í øµÑ_ÌáJe# Y˜$»NÅÂieS2¸DÙR5Ïò<‡Ñpc´™°EMô$Ÿí ´F‹U%1žT£Ñ2¦[°›Z°|ˆËÜcZñêÕå-Qô…4P½Äâ²™}’ }«%"b}±øÑeâ6”°âšƒ¦\[2.ßq;†‡uɬZçðod™µó‹Ëh©GäºREÏq-Uø²Mo]áâèGg2±µl(Ëžx›…:çãc~›O=Eñ˜_ÖÏUùMNìQœe˜Œ¬®åIØRÛó9üquL7_ÖUÿbl^þr«ìKWžCkFժؓ¸R%ø9Ä <^¿Ã#ÏžÒ[¢}­¦Cı͋s®Ÿfâùèî õö¯¶$#š—k'ið¾TÒNÀœ›´*X¦’&ØœªJýŠ„sK/ V/b!¿gâÓB?¼ђ㲨•r7ҮƎ,V—6ec8)ãÇfèΚ1LêSazÝõÁÜâL(æðë¼CÞb¤ ûˆ:Æ‘l½Å+·zÃÃ|–œi^2´Ú{–YœÕúñ–·8ÛnÔÛu㙉 ˆ®F¨¡5ŠÝ…OßPyÆ?X,rìÁ¤¥‘K%&ócU¾Ä™ÒÄëff«™WTb 5ãßœ³ú0éùnª^—F¹ªLðªyboZ|Í«²W“‡Yr³þtRG¼=‹ºDø<ØÖòR¾š‡ É0)ç²o"w/–Å+]’oô ¸ã6\(ùþ¿ž„ëì)8žÀ_ùàCUø²?ÌâôZêNcs:5Ïj¶‘t{Ìxºoñ·ç:Ì,NçxÍ,Fg»Î,níÁå…XTù6³c+×l^ÃóŒ¬×"†äTÞ@ý–L†i7AWó¼} œÞ1Ñ"‚Ž·ª‹3¨ÛcR Æ~X­ ))ìN¿_OØa,‘Ä*f2¨¯4é«}v|.·÷†•|ÿk=ë4•b|ÌS®o)‚uL]9 '\G¤fiÙÝ|*wŒX¿Ì¹ì×åVšë_½nâ œŠR4ßÃÂÇÓ”£Yˆ1×å)Ó²bKŸ¿|n,î\…&P“! ¤ŽŽlG1‹ŒvGöFì"ÛT|ñ‚kÿ¿8oônAtÅZºxOm°“ZÖ‘ŒÏò”¹Õ‰òܾ犒¶j¢Ûº![}\­§7ê&E{&’׆®Da Í̼?’yAÙp*Æï&V帎ç¦D%Ô†ºûù¡ï¨"³;¥}‘aFµúq‰^ü.¯qÐ2v¢tñMöú˜[î§m{Év{:«Ýbš#¨yc§·vîé#qPöiè$ÜÉQUœ‚ùÎ Á,y†.LË}kf¦[ᲕsyFÕÎ%Ž©Þh'ÍЗ«òT¸„Ñ3]0 uë $€Nd‘HV…š«³Q‡=¢.–wJŒOÆ=¶Üp4^$‰¨ªI®¬‰Žª.‹[áíÓæ—ÉÛ1¥öZÈ6—q+>{n A MÛ™E0ËÒ:3•sÿ`½ÙeiÁeýáFéR¸.*‹Pm4èëÞZü éî”)D¯ö oßú½Õ=…˜eú럔@REuZARÒGô ¤2Œdîñ¶–„“«~I]^‡SäûÉë/õ9Ð) CÕñ§¼¾+òŸœsÁ]2ì é’yÎΈãdá7åþp:fÍÕùw¢,¯þ|Ö‘ðW4æF”Vóhˆ†ö°<Æ'ãê3×®ò޾YO2Ÿ SÛ4PÿîhÆB¼ )yÄV8TÀP“ò²’v¸ßˆ ò wûÑ^°}—‡ãY‹^œŽƒÉŸÓí¨(Ê£ªy=˜ÛU–¿þ×YD¡mmÇI¹\»Žç R&ëÇÝIª¨ðȤæ [>üÏÕË1£zJŠD#u9•Vq=Ö×UÑ#s7-µ?y°˜Êyº Ú0òV†ÅÙê?îð§ò ã¡;e¼}G  {CAA³> y M2:-ÜDš¸fø.^?7¿ñ‰ònPBŸ „WÙ9YírøudúøZC¬îlI/dÕï>³Ñª†è—–àíÄxBšÉˇruÚ<£ Ü‚ Ĭäçå1Ê-áãÉâ¹`p`(VºîUÓWÖv251¨pÖ”F®°qx%—dFJóàþƒ Ϙpn1ôŒËõ‰Ë[ü•1Qc¥/§o“ÕzùÑÝNô‘æ4ŸÏ )ÇgÛè|ºsÐrúƒ'»Pâ%’4m‚<Ös‘A‹e ï~‹SSÝra«Ó™4‰·¢!41G¹Pï²´ €f 56•ñ¹Åì²b_[v ãï)‡8Díìð›ÈJêXíå⥙E€H)ðÌŽ"e™;ËæÙ8 ÚM \’– ~ŸÝ˜l¦*ªO”‹P­‹PðÚ7–˜ë4løêgzªÄtiëU¼E? Ææ†ÇüŒç-Ob7’4ÖO½vyØÏ‘þÃ.‹§Æ]¨¨D-\mÍR€æÍ0'ǃà¥ïÊ'ÛÁ!´Â¢@§ÇÇ "Ñ*™Mçk qµL¦×àÃtyµXM)H`‘~L¨mh;Ð¥å°åÖGR^¹g˜ÓÅ¢vY„':¨Ox`ŰX i[å¼}p@Ÿ¯’޹åÑ)Ê,ûší ~NHA#ö©Ì}_ŽsÒÂ'…zÏ%[ ÕU6ªEÝNÒü2dáÉ $“/ÏOÜL £2Ä}VÊnz—¼¥»5McúÓ¸nyˆ¶ÔO£ñ:ù0Z/–fòvL¤–ÿƒ·íOµ˜z]®÷/+*ù)+ä#Ž% ¢æ:'˜é¸£’#RÇYÈ(Uç–¯ñ,ÒAW¨`qá^Ÿ¢DUô [N%–+‚Xf÷À¼øZ~Éü¾7Wð/+ÿr£.ÅBA‰ßƒ‹Z<Ó"û¦<"² à c«Òß$ï1y—ŒÉ̽ûä¸HJ '×ãÕtDxæ_²%ÃJýz{=xj?Xí ã°ç²<¯êíR…cÙ7¤bé û&\TÁT <¨×mÜ ½Þ°Pá2äî—|8(FÛu5k¡§ˆµ³›»¤æºìʇ ÌþFÿ0!\ð÷ÁáŽp*“šŒl_ZÌ‘ö’[¡ý;êŒiÃ& ªo#Ïõ¹Øçt(ëE2hCÖè?9-ÒxyÙœû£ŠžÃ˜9x|/7â¹RèêýØ{•²¢ATÉdPþS•ñ7$|šGý§Yc'Ä?Ø3Òo@³@„M³)¯­¦0¨R‹Ä~®žB¶ûÈCLYóÞ=Ië­ó¥ŠË”Ù'Av2¸¦ù˜)xÆqù>¹|óØeÌc;ºøBÜkùÓˆ`kØvs8œÁ;¬9ò6m´HŒwb•m«„yy\rÖxNÄÏdåÅ Àa $‹rÒÅq@w›YlÙ'8(&ñ§9b¸ &äžò°x IR~AY Š@Í•€”PÖ!Ö)‹Ï{Òc¹õ’XöËM­Óв÷©Œk<¤ ¾d»ìÈòÏwÐm^Òãæ«ìÌHÞƒýÙ25ýò}ÈUÐgªËM^ïeù†œ­Áy0ú¥"œ 3!ê×À ò¨Êø<ø•ñiãtz<›ÈcDz^EŽ«8çPT„£­ʸ–ŠeÙNw¬]f‰:©ë¹pÚ1‡|ewêæì©@†[P¢ä…¥;"kQ«ãÍ^¦Žñ"ìOb '-æÓûÕt¼˜#åjžÜÖE›Ÿö côŽÞ“6’Wôä=Š ·Eîb7~}ïüíoõ–Øü¾ó¶¾%¶ñ}n{ßñ¶šG\¸1œûqrS[°fÃÃ)1øbs€†z왪ö°‡š‡p\çpì¬'jtãpðü …‡–—{Ÿ˜È@$G²ÅÕ;g7.Œ¶œÙ­MÚ‘fu|ô·ÃÙ^\3îÛÁõõç óŸ² ª…ÛàæÌRUö˜UY±É¶sÌ„ŸŒ? ,tO«ª¬8‹NL5&Œe‹J$d‡6ŒbÖ1.I¸˜‘¶7›Škl7“аC…¥: ®e°ÊÅùujqв&¤j0».Ž–[ù;©êÄXŒ|k"#*ÁyÕŽ¢äWZÝôËœÈZtdµ<·Þ1¤üŠï„j¨ÈJ{hn•ù„œ ×oá—Ñf“ÕµÜÖ­Ê]³»‹Ç/ ‘©F"À‡-||ÎëW¿2ÁVÓà73)©ƒ¨; “ìáÔ¶b—r[ ØÈ¦œ”û47¶B…áDq#y ꌟ6ú¿,l^ßVù×|—=e¬þÛ |‘ͦÜ?äE·Ü¦Á[Ù ‰èG>š…TÛ,úëzŸFÆ>_FN¢DÖÆè|ÆMÛFæ,þ_šÙ'&?S^û`\á~· ßJ¬n<‘~Î6_n3¡¢ëº?oÓ×°Ká6U3FþÌÏ·î óJ Š+ùÎß>ÿOvA–Oeײ±RfúérE ûBúT»ív·“š5H™œ}7n`$!ËJ˜*æÂ~ˆÃAˆ26is<¾¬í~cÀºBfpd40q8 'p½‡8r[zÎSmÊh£-<ÔÃv¡ Xbÿà Ñu௮›Óª·<_%Oj@ / —›,’â9“û4Û›ÍeÆM«Ð0M7;Á½hçáêì¨Þô¥¢Øä‡t‡Ä ™=5Ìð4$Ýn§EŒ -€K¨ˆ€Ù¦å+oU|Í~kK‘z³bÏÝ|­rZœöýÙ ˜o&òÍW.9t!¡¡ªkJZaöO°%¹¢¨Áµ|÷³)0Ñ´XY5“'“‰7Óu\B™gO©·Bðñ>ãvf¥eýRÜâÇì`6]œ\kŒÝy¤øö!±ˆÏ<¦… YtúuuÎÑH!67Ùþ¡;ßËš\‹Ê9òúê½¢¥dk¨YZß o÷$Ü5%£cDoËÎ'dä¦(Xb ‘B Ô¶²uf»•'Õ²Á9¯\«!ˆ¾a5‘X;”ñ“Þh÷TŠÏ{u~$“o™µ¡>‹%‚öP•_ó-à>¤hä'ñçêÇ¥mZ âÂÃ)D¡7³ª#Ëܤ #Ÿöj“9sF€—ó&&°CÎátÁ\ÿÒr´½ØPMwÅ0”bbŠ qrW®œ&êP¤x(~»úm¢•øüƒ¹_®^MP¡¬Kªý©G^Ç+21tÏÑe’wÑtYñ”YrYpÿoô]_„·?¶ë=WGÌ>µžuXSN3ÕÔj`åé.ÿ°OÀ¹3R}ù™¨¾À TŸ=óÔÈ凿{‰™¥þ!Ú¼áúù* |†°XED/®³êÇÌqZlÊ­ÜAì^õâRÕäñ¸„5]›|êÈI§>' aÏ4j Ä™³Í_,zVÖq2’Æž;èŽÁnç.F{ÕÕ%ø…0©Y`,Å`•ï;éY&¶üm[‹CÌN²EHmôZÀæMfÃQHOš&m‘}ëÿË­”Û¨pâttæC)E[Ü”UÆ'@¡xÌîñ!©Š>Ýeû¬8ÖÐá”VF’m#„ÁìÐ!×C˜ÃŽ+éÒÝî^üù ²EaÞˆ7óØúû´ä–?Âçìoðʺ¾gúñÑÊ©]ÏW¿þú+[RßàUZç›úØ¥û–ï¶›´òúÓÅÒãscؤ´Šv #N°I‡0"3.ˆéÂ%%& 7e¸ÔgN4óAQ-1ng©?œ—±7Ç'"´N„ê?"ŸH ˆsº€<ÇiA¨G7Yuüe,þÉsùp×+ã÷2 o†è/Ï®ÑlÓcKƒjhb&É2«ËÝ׈Z—itÓ±Ú*F{´B/ÉÛÃ¥äÑFhN–PP‰%˜ÿ*Œ¥Gÿ$Íéa—oþÈ^8­b1¨©cŽ@mÐeï«ý®`A>*€è Y4TUwˆr;Î8Û„3Fõ1›î,V5‘êiç÷nÕüͯ݀Z]²6‡¼òîÉ] Ï\¾•ƒ)‡×±¹9ÍXúâ”ìâ÷$Q÷‡6CKüÓfÇE¾®ï“›ÛÙýíh9ºYqɤU¢ƒ€s)8ÓV‹Å6mÐêf*ø°uƒ7PO¢Å¾jÇ^i¹äRÃÎ}îFVˆ¸„Kp†áåö—ä¿qC0j%õ,ô†©‘Ô/·¬…V !Îɱ&³Tëbą́{2œU%õXxt?¦ ñ±%‚, בõÊí .“\3 ÞHÂ5ÑÐY‰ÜÈ"hìÓÙ`!³þ!"äø£†˜Ul¥8b3/³ã‡t—_ÞÊy³%Œ¢nmÞ¦Uý#VA_v=1ÊØ:.gÌ/€¸±'£}‚&z¶•…ˆ^\ ¢¼^fòQÏ}ç©̫߲ºÌJÑäèrÙÇÿúǯÿǨb@vÁR¸,è2»huyC IFd(«Ij>9O3Öì¥aî'€b¥öàæ'u¡ ‘²}z|þå*JŠcö„Ù“¯¤®OY5™G\øA‹uR£ó"¼„–¼ÊË*³<Æt…YŒ} ÅsX_­ÌióøAM‘?éQ>èG4Ú=q¯Ò\Éä|&êðGS-M:à©,ÁgØýŠ ÏÒ?²—;O£¶*Æ¥XVi®6&Ø£oúý˜rÄŠ±ׯüöš—ÅXÄ߻ޭè:{Ÿd•ùw`1†äöœÖwEݾà1~MNDŠY;u{ž?OS T b=þ-]ÈÛßâžþ:ÐËÏ%g,FÑ9sŠFž¥ÿ é9¯ï[¥"ùªVÓγïÇ¡´Åä¯Ìܹ\µ4Œôµåø¬bUÓLz6™å2Î~@¤øSH4u˜ÔÑS†IÌ™*šQu–úl¤æ|µ©]€Ë%Ô$ïÆ·OÁR•:P_jb¦Ò쮑35g‡?Ï 5ÉqºQ' &Ñ*¥«j×wÐ=Ÿ"z½çµÖ™#¢ct‘aÑq»«³Håž„“{Éù­añ:¿Ÿ,v<ùšØ[tmëšoOBãÇÚÒÀ ‡Å`.‹L™RTÆa3ð…Rt›Ù¤`°s¬Ü×e%ôGc˜„¦ù‚=,ʸ*OÕ†ÑÁ=t×(Q"EÑ;g¤×"Ñrµïqºaà|ϗߪ=KbŠ2P³ A¥^¢Õ-ÒvY[hšÊ¶ƒ$˜!Çñz]õªÌê<]+ d3Udѯ¦CLÎ;[:ÉŸ2/Äq´oÕå‚ÚoïWÕ ŒšýÔÖù:ß³ÊHó6I±Š˜˜­úÆY5qÔ¦#UÍ3{šй>óþm>æÍ 6Ë0ÃÚexvÕ›6¾ŽB€Ÿ¯’„Cˆ†êãâ/jæ0s$ÉL‚ `c²d(a²€®4Yê`P_Yì/"OÇË”ÅR¿«Dˆ@±Jª8pJ¬,๲ÂçÞĽ ‡Ž \"àòc*Ÿï¥Eçƒbv;ú~ˆƒR;\ê'd1Qd[ó­PFºd`žNÀ•#â7JSæ@ 2'ì}v†¶Ó&1\ ¶L¶Yq?‚ÍØC×ó:`‘î½Ô.ñÐ.žPD^<–x!6¥¿ߥn £¡#ÁE`ú<‚•,ÐÙa†MDèN“F•Å›Lì’RôC–½†ˆô›&ƒDttK)¢˜–J·€sZSÉ^¦æª¯Cô{+Ö'Ó±ÒaÏ/Ò†\R+ÂŽEÄB¶³Í¸9ZÅáñ´ÛEË{Ì¢Ï'‚]˜ÞÉr;˜u³Ñ¦‚¶vXÔ„ã¡ïp9‘FLÒ–&`Ü pñAíÙ£n XÄH™!=1hH³hõR³}£*éš0+¢ 2­ò}6d`¡Ì† 2”Y[Û‹–°ez©’Š_ã2{ÖNv [^ K_˯úRr@T%2î—ÎøåJ.¸j(¾Ê3ò~D¹s7ÓŒñe›6bѦyŠ&Ãjf&!%²¨CŇÀÑåÅúC±Hv»ì)ݪ§“Œß*ý€.¸DËs¤›3ƒ5Ò‡¶¡áèh¬#rH¥Î!l["›c•õNÊèydJ¶„?bØ’7©m˜šýÇô-Ñêd+”î_ÐÛF´ÝKvûMZ¤O™5•GØ(J$|Ô#ÝIU¸C×£(Ûàlð¬á^Êdlų3¤#víLÚF¶Iù%š¯ó ½šdÒªó.Úº8¤,Ÿ/ýž‰"tb¶ðýôœ†‘|LXœsÅßyüϽÒ„'Íw¦8’}Jšs6’0êl`ÄVG;ÀñÄrù¹üPŽƒ <ÜÌè‡Ë¼î‡1>³6b‡Çn˜Ç•Óôh¨¹ß_NnYÏÉ|Ïnø•`ÄÙÕ7 T3·˜¨½ü–Ž]ˆŸþ˜~\­ËéýúãíEAXºDBùkÀ—æ<çh ñ¨Q‡AM‹–û¹+~Mô4¡È ¡Íáw¡M57ŽIÓ/\¬ÐÇcxå‚ó1ŽèŒŸÓ¼€Ú<úŽ ’Á€°„4ë*믥¢¼ñ‹ª¯Zµ§ùB7qE¶èçñ€‹UÌì>_ÉÛ@2«“~—cL õ’Ö'(:ÂMY…dÖ#ÉÊÓ;[×·|ê¦×{5Ñß¼f42Ao ³bDŸD(ˆZþ‹Üà:ï¤]™n{:óI&ê3ÉÓÓŽÐeÔŒy§¼Ã'8¹Ÿç:iç<öT²ë:é;[Ã[ ¨ªÇrº¤Î·ó¸òï™®þÒY€›ïYÓ•Éúœ&'ˆžÃhàLÑsž2Œ£çã¼a“ˆÉà¬ÙzŸVŒ¶8¿ôf‰Ò»Ö=>ÌájÜr ôÕH`„àá¥æºX‘6»²@p`Ñwò fâïã3 Í$yC xN…C_ˆ$)Û ¡~h|¯—¤\fÂ^FÃ&[¤TZHrp_® KæÉ:y‘Ü\Ðýírñv9]yþm Xôú=mæ<°Qnc›0n-Oßûá|ñ¼â×÷6‹o$µ8ÆÐé¡!à–7¨ZcõÐ Ó˜ƒï6e^«+U"‘7÷ÙØªÆ~ŒÚÁð¨cté@ N¼HèÜb-iþ7š1&à%ßpÏ©Ï@ö¿…jéŽQ¨œ c®à, =tuè!Mî=!sZ÷ZÉXð´ŽGÀP?=Í’3î%œŒPgÎËÕióÜ)‹s½(;´ËC|_…æÔަËÔÄç¨JÀ¯‡û´*1²Ì‡5 ùÃÞ95¨‚PÊ!ï?{Ê”÷Š©ý€)÷òàgOÔ‹§ßø˜)øÛ¦,3ˆT0¬bçŠ{‡ô"O^ìõÑË<¿ŒS¼ês¤Ê &rÀV.ý 5Ìe¨SYB]˨Ùð<£žÇ š¶iw|aªÐ°q¡“¯5Ù{R@ʶÁE̦7r÷¨VJ¦ º"û~lˆ8‹B˜IÛ]~ùSØ…7îSáÇŸ ¾ï„]pž†SBÝ¥@壀g( E¦R<¾«}[îò çiÒˆ·J‹ˆ:~¤©˜ÙÿtPÿA¡ ç–"TEÌÜ+¹RóÛ^'K=«~ù úì‡n^ŽU „8òºË&C«cÍ dø×AªYgRebxÆõ|µÝÆÿ M‡ŒY„tD1nÀžŠZ¹t rá‚Tš{˜Œ1€ñÎwÙS¶1.A܈w¨£&âÄ¡+8eŸ™¿ïÒ ñ‡òQ1Û›?¬ìÙñ™©èU«cºù²®ÔKêqi»MÎ[€DUÊðOA-ݳ ,Š:^—hw)#%Ý ÊÈ×!7ƒk¥”ƒÐC¯ÚƒXx+ؘ8ÔyN>òÄXÇÔ›æŒü8œÌ¹kØ å2dw¹L†È¥v,þÔjâÓAoðã`v`Ð+Ø&BA8»Ä¯Z'¢é™<¼±V$.`,ÖþãòTàȰn€¨sÂòkÙ41NCƒ¦{H ¯TDdËŽFž]ì6jÃ[ÀèSÇ0Îjiˆ6»,­À Ã(&|ò…  Ñng.^oÒEÐ Zðù“ŽBÞˆÁ•£Ø‹$Zct5Aƒ[æ$c‘ÜòÔaÞ ›4‚ i !Ùf§§Ë_ÖÏUù-}Øeøf¼£¨—B©¨p>¨%ÆÞ¼¹Ä¶ ;R â¼’?2µº‘gɬpçÆW7ŸŒ¸ûâƒÛM*% Tý†ù j¤r„rà@·Ù£<)¿€M÷™¿µ–”¡ü~ì*Îϱ)b2õcÔ‡2Ô*ƒÕK›]ßO¸8ë;s†5£?Àü0v†ËÕÆÀi5›mÑûê’¶Ql0tÍBÀ/TXJýçêsŽáîjl`7Ø´Ãíe6 :“áf8„ºN`wèÎ$E$žÅ÷Â99má­Rܶ ñ‹?Àçº(Q¶ ÷l |ÀÉí%a–ú8ã7™È7Ü8@}Ñ–‡Þ•ÅÓº”UUú"ªd/šºxŠ:ggEÉ9gåâY#Ùº7ÁêùžbÎîZ?ÔŽÑ+hÝÅÆ&ƒ¥k¬1QΘŽî7~1~“ë…WÐÊÛ€D¬A ªaeÿ_ößUÙ)hJ<ìc€†´ÕPc#lIã”*Ÿ9Õ i]€aqÃH ¯Ä]^´v›ˆ¥¢é&€‰Ãíw™šUbåºÍ8çC0ïƒÝ>yVÑE‡*¾óDbê,­6Ïˬ>íŽvÐæ_›ˆ#ðž7"Ö  Ú„cƒrd9|j èt:m¿È¶¿Îw„ ¥kó®+Ãìh%kA£äÜŒ»ƒ3t““è¸b›V[åøãØÊ·=ª"¶ÊÈdªGR«&‡Û¹Ñ8$çR–¼«ºNžFÞcz]ÿa&i®r<±@ÿãäÚŸGùrñl à ÚÜwèÏq"ÃåžUÂÚódzSNŒÕIˆÅÆõ iG÷ÁßÊ1˖컡âû9ì¯uš! VY¿&9EI_®0KSþFͲqÂË÷AÛ¦ÈeHP4e#Åeíþ¦&„Ý?O¢±_ƒ±˜”T³Cc ðu&%5žäa0hˆóòxW«‚À~Ϋ4—)z^+yn /‹•0ÄêÇ<óÞáñ›o\oäukWŒŽGPœ)ÚqYÔÇ*•Ç$œÊ\°ˆ2 ¹zœw\îuÌ~ž¬YJ-¤ŠŒë”šˆ9ø…™×,G‹´„›7à*­ó ~ø °¾çPó·£VùS‘OU†Eè^y|Ê:‚\é>YÞ¶@n¨€3û’)@ÛÄžEû ôÀcÔ³•$;™èë"–/Ê ¿©"ï*¢TªÈo“$€ï*¢4M3C×™ñ|š§¸d¨EZòÑûg1¼;¢¸ hoéâóamØwj "¾œ. ÎÐCP/X‡¸›7Á’OS¬ƒ­’·s<õÃt™\ÄÓá-´.9F½vD‘ÛE-®aÎß(âå1`K§#ÏÏÓz=#d’Íf¸¶äS{pë:¤5" åy¹ Ê#‚cxpGÅ‘º?:DOs Ìh© êpˆÙ¹J»{ï1FKc¼â-’˜e$NC7T=]£W:Q}‹GÕèl1z ¦á•bKN­çÆá.|;À–gí›àôp@ÎÕ˜¨pánçÍ'6£á3BŸS'Žèf3ú^`r ™¨Gs¬pkûÿbº›äz®·âÂ\J›"i³­†°Fe–a~3ÿ@¼…©©åy‡:>g¤Mß-“—b TjwRyù#§W½`ÿtÙ‰yVÿâÎ&e— 6*Lp´}Ó h1¼îàp²z.Bq›TÅÜÐmÚõ¢þÛ=X kÅ9MÓÕAÓš~|Î…y&ãž ÎÍÊž9ø#%ŠÊ}±²yn΂xö©Ódܽ’Å .¹z(g׿ò$#*GNÐr¨<Ø¿y0ÏÏÃ,sßÜùê÷=R®ˆ—ÚQì·™Q‘oµw|ºQ×Ñ6Ùw&—‡‹„ÃeÂÆ]L(¢EÅ)/ù,=—E¼¸y,âåÍc1TàÚÉ/NÞ,*oÆ‚a¸´Y0\Ø,.kìOÔìÒfÇÑ}ìrˆ4—C¼œ¹†ˆYóZt”94Y÷'M\àîƒÖ, êÍl´%ú§Ï%›sA$KÔ\äPEš8îkè—®˜UEš6²¢¸£$·ŒWÿ4(+q I:DÃw„lÌ/W#ÁBtû¡ý",ýü?žo‚"ÑoæN¿ë%1”×Þ*“Dÿ=Ýt_5¹ ¼ô[eÈCLÂ[«u¢& ¬f¡S/-qcÉŒ«#1:–®ÅƒÅç¶/·§ÝÉ»€ð$ Ó_î³ÛHü?#ñm±bóié"òÛTÇq™=>æ›<ª~°©ö›€`Ïj0K%@—cg%’¬:±»<ËË”rl ëãÖSMì™Í!ã)ªaÚæŒ!o£1otvŒÝÑfívKüÒÖ£ uнÀåÍç®O‰qWkC;Ä[y2•Úÿúǯÿç"F0À(d$ ¦Šµ€e„áMùU¬xvRÀÏ]áüÐÅP„¿‚â%£‘m¡rxÄÐ‹Ë ºÐ S&Ÿ…•gÈxÈÛÑrtã=3íouÊ6}¥Û”EqðÚÿ2àõB°Í'"Â\8'œ–U„!Aî@F1TAz"0*ˆ{¦ÛRðH¹ä‹`ßDRo[²Ž»µÌ}ƒnlÀC2´Ž…¨ÆÎd›sŠa0$bf(É‚ ‹ `7<qõA°)}Ó%é¥4Ê8êqS^þ½ûE…vA Ñ è*­3ùÀs(è#Dcè*3YÇ•!ÎÃø`£^êÊk íû$>,3gÁ§(S»8Ë]-ãˆx;Òs•7ÏútŸkEŠÔÕ?gžÑˆéãÛ**jÂF˜$ÉgãÄáøÅ.‚8Jíf4¯X^$~OîÊJ ¨ô]óØÜ{7Auõè½UÊLÍ‹´zÑÓf;,œ¨.Õ¡¬se$|¾zïçØ¥Î¬ïoÔ©›Œ·+2ìˆÒTE}p•=åõ1«„ÑŸ­LìbS…Ⱦ¥õü´Û¯%€0‹C™d ­ŠAÒ«²Üei!hƒ¹Èn¸«`ižËJF*[…€ban4Ã`³RÕí}w½+SÉð:œ”'ñI 'Á*çO“l“ïÓìeÛ­Ð$„[Xg0ÀåJU÷bl=XQ­ó½M%?°¨êcº?x¤êk¾±ˆÓh°Q¶i›{Ô¬ rZf¯íYò1\¡],"¥nBTc—jÌ¡Òö‡I¦¾é´,í#P™¼Xÿf˜|8ÅʃCÅö5­O*l–7óØêôÐèÝ÷!ÅÛPŒŸE!7r Òüäsv†ÃÓ Õ›<çN–c`:4ËôÞ¯0yŽÑɳ,ŠÀÈ6j½ÍW£ñ:YÌïç‹ù4ŒZNG“û»ùxqs“¬×Ó “" ;­GW³©" ¬¦KuW’Àèè‡c/–¦­ß}|“ªìV-ê„·½er•†fè )„a!–Œ_3aÄÇEر™ÔBšOÇr\î÷ùÑ ‘hÞ,˜m–mÞ$#L*±~H­ Ìý®¬345¯Ç2}‹f/7/²c*húÚV¨éƒXè¶ixKtX¢í>réñ‹\v%}mÒ+zKÓuë*-jí½Nêr§|¯"À¶ö,üŸiUˆÔÖðùç¬ùŒL½²ÐSbí Ð$¹ìµø]fZ,¹ÃT¶úË!¦åõ‘¦Þ¯ kJù3¦+ÜÔ$àaU¹É¶òf¡r!Ü_Šò[Á¢˜—š†ÉþxªŠ:‚b\îNû"¦@š"‰ %‡Ö•Ž"`7ϼ”‹Ðš‡=i93Z~£ Í(IdÃF2Êð Òeùmíe•V/l¯èUfíKH~içåñ¶ÎNÛ’ ›WØÆÂ³ŠbQ„á¹ì‹£Ú§õFØÐL´¡fieÀWÙQJ =/GÁ>·™O²Ç40 ‚DÏݽ²¬ªúW ¸tÉ~Ÿms#„L°BGUhPÉírÆ(U0Æ5q q“p1ùnçed+qr9ÆÁ©øf!àJÅUÖH’b›}Wqëc€qïNr¡K÷u—qÿ¸ØÅñ9#ÛA>OÞ*íz¤-Im›¥ÙZÂ$É*“ÛR "éŸ^Ά)HUgc;ÊsÄÊö€…”jY5*ÞåOÏQ³ò[~$,WÇHši± 7pûMtêö´ ¾ÜÆãÒ½åϨKËA}ן›ùMú?eÏ$áÑä—æTgõ¬Ü¤;'¼t¾Íª5cÔÔ§ƒTÖõMþ]¨5‘¢¯D?æ*ö1Mz,Ũ¾;²j¡ëa„CŠêÖòŸ§RHýàº#ïj<Œ|páå~IVÄáƒ8±ª³ú·²Ú’ç€ê¹);˾f;¹!C)OâWÍÚ3–öZ´+ŸFùWGÕ‹g€T:M¯ÓM¾Ÿ¸ƒé$ û¾ÌÙ}(KM4Ë÷¹Dl:9ëlž³}º-9`¶éVré›­ƒ!ÔyÝóÖ6}f+é(—Pu‹ ¡_oÒ"?œÚýV'uô]ëÉ50·‹;j5+Läã«yŒRéèÕrý zymI,*ž”¡é‰áMØ3Ô†=ùÀFì lE³ƒ›ñ¶Ùm϶2@ö‘;•õdMøDfÇ«Yöº¬â¨ä:eÛ{|¸d§‡ŸÄ -$_FH«¼ŽQƒzú=¯Ù“µI˜ ÊT¯ª¶lQh ;1ƒv|˜¤wÈ(ìˆm/Y1>UuYÕ£MUÖ5´ƒÎ§^v;èlún{rh\Ì2ÈÍøô»>W:“¯™¤»Ysp'äËtrÙ5€Joj»>šHÈ\gqÇ)ÅGÒ-bˆZã<†¦ñR±HÚÝ皇WBÙЪ©"ðzŠŒÌ¤S‘±R g’H*¹ChÏ€°Û2«{pRlv§m&'2ìJÙíŒi»nвàJR"ë®÷¢$³ÝàæÒlÁ…­  lÀrÊM-¬^3òÞ [×:P(ŠcŸdki,ìf=Ys‚Í#y*¤E’ÄTÆ\éðžg"ÏÉwgÈLÛåÿ°¬/S=lλ¯{nšÅGðþ±üF¬*/7 ÌûÿþkŽA´Ëÿ„éì² ÉùJŸOéw?æ|’ûóHÊ_«Jò½0hUØà¿.פ?öñWf+cwü/d;V«ŒL9홯ý¯ŽA¡Î’ⱤєM¬¨‡øSüðiMŠ­.3m›ŽH¬6§JöÐKp§üVhg‡<ñ!¯s}Ñ+D£½1q4‰z 9†F´©ã‹§ÈâK¨È¢ yêŠ7ùmäþN€bÛ•ŒK‘w…âR´2aÜieX€w“õ`ë'xsž°Ûµ­9Bû¯þ­iI¹®NÅ&õîK7§Ú, p.4ž|hoDáÚO•VøÊˆcé#ŽÒ Ê“FµQ$?}r®¼:¸VGùë-Ô_õò$ÀÊ“]!̤©d(ÓµQU…õ;²y”P¡Ÿx§+»gùÜ‹¿fÚ{?¥nnàI_ÓÝ)[<ÒW|&Î?EɉâÒbEåß•§Ê_Ý«¤›¼8©Á%®²MYl¡Äºe ´EÝs…S[¶ tIAÎ"¯&hÄFJT?¨nlžϳú 6 ]¾òi®Ã±–§~ùä<õ¯Ž“³³W Ï3‡•É(™rŒ Ýz ~°­iÛíÃFzøwyZè•<زá~P¨­úI¥©8AÀ܈Âeƒ  F2=ÀêݤEúÄ‘´¸š®ïg‹·÷·ÓåM²Z%‹9 ÕUòëÛ¦‹Eq^H­PžðüèO ÉoW¡ï¢ˆ\:o‹bÔ ý&+㊪X¾GýÕ—Å–¶6iAR ÇŒŒ ÷Âã8.¶©‰,ãÙéyBap6í]k‹—AHtÔ6;ƒ¸+>Ɉ¯n¨¸Ó Æ=Ð|6ÛæR¶-µ^40$ïF·IÒªw„v LÐÃ$ÝíiÒª³R]=GeˆH(’tÛÜ.éúêÒã)wä`èUB|¶€U—åµ×bMñ|°èmà”žj,tM†b›Õ›*wc2À*û÷)¯€9ÀB)s”†lžË|“ù›ŠˆÁ´›wý–j6œ}Ï6Âôüç)«^‚n”¼=p‘àZ_+sÀ.NÏ'Vê¹ ›H=«02Ñ·¦ƒ8«ç}Øë¹#Ûh=FÅÈ2ºëÜÀ2Œ6ib)t,ÚðbYò™Ñô#>K·L “™ÁX$HÅ]á‘Y‘WZZd%ÌÀ C’t“–†„!wE.ŸËÆ 6Œ‹ ÐùœÙ ÌÔŽ8dFâ ‚úâm£ŒlˆK·[åWc´‚Á¦oý&‚ £:*â’©X9#KOê©TÄ%Fy²1¬ ºÔÓé˜KB$&H7s´‰ô ‚éÃ*ê#& ÓÃY:dÓfþcÍìBR¨¹\&³b“zl›þ¡™· ëézüîþz±üs´œˆåôÃt¹šˆ»ùóÅŸs±þx;m3¹_ÌgqÔj¼\Ìf÷É|5¯’uòÎÓÄÒÈñb>¾[êÀJhÖ èîv¢ƒ) "ûîõèÓ€<}"ú°Of‡<´HàP‡6Äqhç „6´~HC+eh¥C! -ºÐ®B\ÈB¯ú^¨B;ÿPˆB  Mè¡™! -:Ë6 ÆH³H‹$ŽØ¶Câhñ¥WÝLy¸™}PCÀÓc  €"4jÎ0N’ W@öµ±ã<’œ9ƒ<øce5h°žËͽç2ãÇ.3'@4t™Å»?Ø­³¨¢-Q‹šÝ"¡5Åã1/ÚûÊ1êÃ[’PQ5IJJ¬âBÚòM ¯¼¾ÊË*»Î«µºòzô(jgûTá1 YøÁAîqF½OÅR>[/`ûhCwO. 9|"Ž*Á2Ð-‹eâ©}0vÃÕÑE8† äA ‹¢ Æa„ðÑG•µHeDô±gPeUV?ˆŒL²[¶FºÜ—_³u™„ЬaceÃQ8å~jƒY‡aƒËBÃ×~vöÏéç6ì•Qè™ Û| =¯aû%ÂÏjðV·ç5é] ¶ In,’œÑz$=Ýœ¦iÈ~„ã;‡å ‡N8^·sYžñf Û«ÁÛ?ënB¸C*OÞ ±½Q¤88õcûÝuKõ0²6BÉ'*’bS5 À+Y+ôQ­²BÆqÁ= ¾'ÌaÞ] BÛ6Áv©Ì"äO…w5‡h¹I^véK㪠¹wD³ô!Û½ænãùôÊ/:„¼ù0ˆü¶fs­}<Áª®6)£ÅÛK¶ƒËd–8£E›;zÌþë¶Ú£34"/‡ÅVžg†&p@¶{aõƒ¿½E€TÇQ}«ÎB ¯…<©°«ÌGS["y?«t§IQö{hÝÕrPo!{,ô3ÈÐ óN£ZÐÛTü¡ÌG,ý«˜QÊJ¾U!äY,-æ•O·qÀ$H‚´l¨ö †E6­*ݪö„åÂæ¢m»ÎU÷ͧv ô°8)q ŒQÒι–fQ´.&kˆÛéL²v¸í,•ÛÈÚ϶Ò×°R•+ÈÚ«¶’µÓÇÚ™¶Ò÷޵m¾wä„7ƒ¼jË^ÑŠO yƒŒc ¬L[ÂhõÀÚÐ Ù§YÌûxaÔ#yNóÆÐ-nøzUÛ·YµÏUXóæs¶9ÉÍ¿\ÉçuúT;7ƒŠmyqh`.~©›ó9Á‡ì è9ÆêÑ,XrcF6†:¤µM RBÍϹÁ…ÜÜ 8V›àŠQs‡ à”€dÀfûn@úý:Ïv[ÿ”†u"Þ‚%$»eù­¦9)ÆD@tX}´®V¯6|Â3T ÞŽµXZ0,k½óA4ÿ@s©>Pg_ éÔ…F‡w• ø„Õ¡³à=B‹LËà†´»¿lŸÒtŽ#Ù·ì¨ãH?ê8’Ï2$œÈq$¸yЃG0Ü?Æ\ebw¬àú“×õ æ3ZÀøà?z†¥µ›BÄ9:šÑQ$>èð,f8G`™Ѹ[[ §JràãapT*ÇL{ï§Ô`•Ä ƒã®W%3 ŽÂжù˜É—2 å¦,Ü ³mÒ$}ÁÜÂmEU>@ëÔmFpZs7ßH;Ó›î )Ò¢¬Á”:«òt×D†¹K& ¨ïÝêa ä÷¥Nfw¨çNèyDt­&ö¬ºß%mí›t¬RÙ¿O鮆W<ŸÂÖ¡¯ׯä ÎÚ¢®˜È`©”6Ò€«dí}['óÉÜÿ¾ºÍfP‚ø6};]ÌßBðëÙbä]NG3ïãdqg_GÓŸçw7Óe2öáÓqr°¿ù¥û0Z‚ßg‹ù[,m2Zû¥Y'7ðÇÕzts ´Ê|´üIi „¤Îïf~…ëw@¼}Ý/®ÞOÇ~óO’•èw aµ^ÞŸGËåÈ/ÌÕlqå·>ôq9½ö¾ý_0~ÆQ¬6~EyL K¦]˜ÀÂMó—Sî#—B(”’!á!tIØa¨4a;U÷ŽÓD>cp,«W]]w#HU^E#¬|a:ÄÏFó·w£·ÓxJyk5™¿'Læ·wëû›éúÝbr¿š¾½™vz(‚‹ê£W’ꕤzÅ¢ŠÏ&¼¸`ž†"˜=§õ³½!A̘´#¸©4—#˜iÿ}]t„¤îKYq—bä ,b1T[¨Ú©hžõâö¼E5‹¬ã›s²Q&°\„Ç2QϵE×PSýðšÙ «¡¹bt–C¸ ¨òà¡¥2Þí:„Š$þ³ÓÔ`ÐÃï•û!rh„¸—‰?ØŸóúÕ¯Ãh­É¤mãˆHÆÚ;VÂbÍàIì¡]YD̺!vÍýÒñ0j}u q#kƒéu@•ÄýõÕ ê6@w2”ƒ<¹Þ)ÀÁò >5jðg3Z<1<.fÄg´x,iÛ(†Ç_ÜQvƒe´Åá6mÎ-í´ÖŰW~ð48Œy._.ÒÝêlõÕ\ “6‹|„…\[¹¼Dïî÷ÑC}”ÍŠzG ò*ÊX’±Ö¦¤‰³0%EŒñ#ñ ƒ'áÛ/ºÌÇêÅØi’…AÈæ ìyŒ£– Ú-z¿J>Mï“ùx9ÅO Á±?) „œ¨“8Ƴ(Pí3‡@j² — *OÖ¢ÂB*) vu…èÜmÍ6!ÕxYf¡!Í.~(@ºÝž1{}é?:»`›zûáQÔÉþ°ûKм©2=Eu)òâA[šqna⬨O•$¾\¾—€ÂD*ÜÔ_QGi»7Œ{Á—~6Ãä¿]¤Çó ±sËEDL0CVÔ™¦%z,œÝø9Û|Y Ê!'ÑY§ötvcœ@ê ãá:˜ÉWÖÌ?Ö£ž!ª…Uö믤ášËß\B¢Ð°ù-ÀæÇ ISß»‚\¢ÿΪ_¶ÿ¸xk!’š³SiUóŒY ý’½©þöºeÎ ±#t6±þMM%Ô‹Xv³ï€MV·dÌõÊ(äyÕ¨¸SÊ4`mŠØÈÉb>ÅSÝÃç„å¶IOo‚#´7—(kDP€ÞïJ€ËÝ®ü–«ðÐ4¯M¶ ÂòúJ¬ë¶ieÞ­†Ú´õG¼äµtUEc`Òv…M_7ô¡E…dJ1‡ÈËj›4ÇP¬â[H¢è.C“ÏJy§ÿÍ@®³¼ÈÎ-™Åãb%ëùÌâùŒ.VÆ•Yù^ó¹Eôø\¬„£¯i®Âlh6ýùk“·¯[»6S ûÐ*Q‡vTË$³¡´"Šãý6O7U~Ì7¸|Êöº¬ö ØxÉÍ® ÍsYge÷¾-ZÿSñÄ•<Üt± Æ‹Ùýxqg;áÜ* Ö‹Û {êK÷Môз´Ú2ºß£YAsÂDWéæKtN-+«eúí&=ò`}éîÛÉÄP絟:¢ë]úT³« îú^I’ÆñáXкpÔ±­¸ÃZ>Ú5À|´1 potû8`CÛ!×>Û  ¡Ñ Ùp±< aÏú]/ŸÍ“ê9=Ÿç§ýƒßâ³—×Oî©-Î:Òà¨UòvŽ&Nÿu+ÌÕšàv¡ßœIæ×É©– <ïí±”!žš0^]t77<öÍKjOôZ0L¯Gw³õòn6…u‡†Á‹bC.ˆmÎ(›Ý.“›þ2¬¶šŽó –ºž.× –˜LÄš'w7ˆíÔùâ~"xßèµÏb‚Æ£ùb.Y0°×ÂÐaÀZm &n³Íþ¦lÒÍ308EŠèJ /EÂôŸwHÝß.§£5d‘µ‹dÀyÛMÐA*ÚUKói”ohƒfï"Ã,tÐÙn¼â7}Eòóu^)@{u§p¡3 ½`pÊÖl&™l fUEð²qÃÏ¡õkQ…7"¡ðñ»-]:¡äd*­Þ„ˆm޲¨9|'4ÊB* בí¯f‹ñ«wÉ5æ–Ì'Ó…¹)³l7£Õ$ê«ï®u!y±•NS7ŸH”ìð#¤ÏaÔöyõ9„Ì´7: {íŠDÊÀ_=8Ä×Fáý!TýTþ»ÌžÄ¸WgžTÌÊDüÏ3oÂcyÚ<_íÊÍ—×îAAû akI`ű‡Á­ã¶µ¬V!´V¦ˆ!æ¶ O ¹]ÊÕF€‚ZÉå/WEÛPWu~¨J"jJ.ØjªÔT$Õ” s#Õ”c– QS= US=WS=U@B“õ(JMy¨1&ÔTiª©1‰tO€¯ƒÁI5Õà 55NÄÿ`mÒ†ÕTe¨©ÌQSÚVSt“Ǩ)£K£Ô”-ʸš2øjʪªú¡Î¹;€d3¶$+T½%Å‘­Ý:l@¹u8R·Ù¨ /R³Ù(^¹½ÖPµÖ!p­ÖCÕPÍ×!(•æ‚àA预B M}‰q´T€«£ÍhR™u¨°Jê  Ôa9 ÉÛúˆl²uÔwH”6²¤ WF=÷^!ªB…šWàWÌM-”Lºpý!ŸG`%ïî‰lïÞ¦ÊqWµð0 âÐÛì1¦äþõT l-¹`Ïi22%_¿%ë÷” ޮ巿€9>uõ”qbš¾ $9¹8?rsqÜò!™C§2ƒOf©LFÄ”gÀ„¬§§c¤’“Ÿ[1qb\±æ©jOlAÎÎ<Ä“3¡ƒìúU"þOvex5ÀŒyÔ@sfRnÏ¥|ÌljvnÔ|êŒ|Fuê}îsâª/TdbÁ` xGÐ÷Ÿ íÚ÷K½ð~5 “éÕÝÛջş‹Óålt;KnÍz9OYÌe¤^°)›'§¨ôüá9 FÏ .ÑœC >‰ b1PY{†9ÈŽšK 9Eø¸ðÑŒRúPóvÖ/†GpWÝ#¶§›5pæ«è̲f vY%‰™/̈›0 ÊÀŒa ûç‡Ü ø ~6‡²1 ÂEßîÒ\Q³<âÓ´‡*1ã˜mšŠ/ùñå5l'ÙÝtg¡â`8´H¢k¡ˆ_³j§obÜv;±ŸÇ tèG¾àC÷ °Mó˜4’\ GØ Èt9º¿N¦³ ’þq:Z’€›Å|ýŽDÈí$àÝâny¿¸¾ŸŒ>þ ü•.T2¿ dªO¥¸ˆù•Å‘¥ús:ýƒƒ 6©É/™ß‡[X!9œ[`˜åèæþö&Øáî¢ûIåÿ´˜Ó=…¼Œá®ïlËH’û±>žN’»LFÞ-–k¬“ô9,$µ9†O`¹à¹|,çî1’ÿµ|V‚Á»Nð³Ë2’>tÇØ:¯}Û˜Ú žôë;à™­Æ¥NÎ$§Ï~±Ê¿†×Æ¢Ž¯M~¡Úœ×?‡dXµ¨Ûð:bÏŒYý8n,Sa´ß3Þη#ü¢Ä34¯ó™ ó;™±ÅàgŒ^ÙyŸ¤Ío”»ýFfÜþ Qâβ"—·D?¡ÌóºÅØ‹‚, sAbZ­œ¥ÝòÉ«sÅxͦG­^öåŽ>‘í£³*­iÄ^>-À¨‡ð[–}يŃݟ,hº?ìÿˆ>ÓS^xЗDåa€r'{ñ– çÙ]ƒç»]^ßfÕ»ò„¬Z¨:˜½Õ2å^ÉÇÐrì…± K… ”W§…èÙ·QI3«oLM¼& fª…tX¶ í°ŒWý–»É`XÚ5,ÿŽúŒúŸW›Å°bŒö·ûF +„É`X>õúHaHLF!f® Ý5 âs‰/LäœÚ’§÷n†‹åÝVÊÏm_.QŸä3PòîÖÕ©Ø¢¤#“>6êEØ*?+Ë/§ÄöóP¾»2ÝšRçóÆ9q9«ˆ3ÿÚ@¼a¦»¡Û;>ùötØåùn*4º¢«³)/7™´µkÓ€÷€oÈÄPAJU" üä”I¶É÷éÎóøbGlüj=Zß­î›xÓ ° Φó·ëw8l›?åÇY^eÓw޾f·Uö˜ãV§GWdO)‡_‹ ñùjVÒ%‘šY)òfòH&ÏýiwÌŲ£ؘ§ª<ÉÝ7½Óiú¯UvHÕÿh÷MÌþÂøFdŸ×ãæåð0ÖZÞqÀ©Î¦ßB—R#Í›'9‰šçE‹ŸHy#X7ÁVæê€(© [:Ö¿­×ÓåüþÓt¹¸Ÿ$oíÍvûv¹¸»MæoïWÓÛÑr´^,Ã4ÍC¹1$·Óå½Ü¡ F´;ÁƒbðjQJ(pŒ”{6+6¾[.§ó±|ËÁŽ“dÃþy· ”¡~¿ø¾y Y×—È´_/Gcy8ˆ'—¨¶ÔRkN ¯!!HÐjäÍ dµ˜>j÷Ø ?æõƒ¢*9{zx4]‡¹}ú4 ¿KÇVòj)­ðæÓçOŽ dÏMê²'A¶³1j„Á,ÏZQÌ[Ëb ®âÜ"9äqQú–-':{‡<:û[Ë\û†|pífïGgÓYYî*ØÍÉ@&¦o ³,ÄÖÂ’Œóz‚r®7 ©»G`ÏU,ß‚EÂuXD˜3±£ºdj®-¼D¯ ¤„eî¡(É Ñž¼‹)Lz8dhÖ|DGª {}X&$˾ï€9‘®/?f%@êuý8)YåZÈÊ÷§}R³§¬ÒËz˜K"aÅ霮el)1gÇeC5$‚¡c}²=#¬9ˆà?YUªÊ‘ݺUA w=$8dÕM¾Ûqp2²x¸¬Š5{qübæÅ£ì–— pžâ‹°~ ®8Õ«ü _Žw®½ÆÏ ÿf”ò¸Ç‘ìÅvLå3†Ü¦ÈzEË^÷Ùf:-À\‚¾ Öî&D^pÆî[‚c.;~j¨s)©¼ó2xëŽkfF>3C×Äbæç‘1³»ÕJ…™K‹æ3ßøAÆ æ Ím¨ˆnêò[Gãq‹ï’1³K}eLùvôQ‰Q¡‡‡æ-I‡f{ÓªvfûöxfÃÚê}h.Ck›è7Ž¥u”î.S2ŠåàNiæ¸Z%gv™áàoÛ†•¯OÇÉ0~Q»• Ñr–¨þöë°òl#›· Ù:óh»CÝŒþå?àÒ'O®fÒK'6Vóa½q_K6(ýM >KyN’ÿåÆÂýrz‹!ÞþíW8 ¶ƒºä¼–öˆëté+³Ëä!U„X/®½EV—.§HàÝŽho!f¥ nûNí%”L©@Ÿ\7m“±ž'h1tª»Àí’+ù`^‰ú¹<í¶K º;¸´íLÞS%xæÀÊ6~^• &EFÅ®G»wW>ýí×׌ ýê(mÔ UO Þ¦9ë¤G©Ûçé>ƒ“½h#}Òã·-œ€n9áøÕÑÚ5!ëi#å_xrÖ<-ƒ#º§jp ÖÈÆÈ×AäG¶<ú4އDžÅ±qµÅ‘,am°$Ìqe!cËÅ=‡Ù8‹Ha vIíB 6ôà ‘ÿ˜Gsðâ·ŽXÌy<"^XóÐ;!Gy]„ìL ˆg±@òí†Ì¼ä9zþ3•oµ¥ÇñãnÒê ŠÚ•ß8ÌZÉË3x¬T?Ö•ü%{qOaYéÓ›[û(+u2M×Ó š.ͼ»ùÝŠ€È˜ïv z+‘"! µ¿}f¥çõtËïO¸„œŽ^,  ®—yTÙ¾üêm̹,&†´R%®(Å–©†m)†µ°-wœµ“ÝÎýZ†*p•Éì©>½Ñ,}wt¯<æÊ´Ä+!ìëúøV¬·ÛN $¤%_|}Ô¦¹ZNGàÉ¢¥¿àÉ› O+Ê⊦.xÚÿ|«¶xê¡ÊÞÓ€²>Òo3Â)ýi{*6¢õÿ㈟ÊcFdQï‰Ä‡šhçÍR;|®Ô†Ø/•:iÎó£.¥÷>© ø"ÿ¼†_%Å‘öø(%`ðC£}cÔÆÉ¿ð—Eò!ï‰HçQÎT„Ò7Yõ”Û'$HÇ6ûs5©Ó¯ú%y# ad¸£šÌè˜OµŠ\B ®’õh¹}tc5¹°ëéíâOû`Ã<ØèPõÛ¡å7N: àPÊÙj&záÏüøX“2²ý&Hls§[ö¹ ¿½ÇÒvl•³ýè8¬5óï ó£%‹Øv,Í=ÕDù¹Ã0}âú±‘ê¶l†§üÛ6@šô£åÛ»›éÜ>ÃlÃôr·Æ¥z!ޤÕÓI^õÒçP à>ý®Ÿ›Ã!Ç—Cæ.s&å6̳ŠFm…™xÃB²uŽIÔÞâ »úmºîvœu¹ˆžà´pÌ(§A¹çç¼ ê_ÝÕ(ChCM£µÁ8¸„Àk»&iH‚­+\?ÔcæNßã9 BŒÿÂZÅH<Ìc?€ËÅ}fv¬µ³MÂ\ÆÛDÈ:ž©«â´ÐL2@¶öé—¬U‰ËŒMéT@ÌÒd/ßÊjxàÕUOï4Ç.¯Í‡Aÿ8rS^FÅö:ÿþO¹”…îx·!Nâê>d›Ø‘"jq3—éø©^MÔ{r¬°û8U~´o3âȇÓ#¸•O.ªçÛyxõv«³ÅѰ—ÇÃaééÒ8'%Ȫ–ÆÓœ=”ž³Ç~š,æS$‰zrÓ€1Ý4Ðô³›ðÝhþönv5Zaåk^Xdò~t³¸Ÿ<àC°fžßÈË#ˆXs Q—O·2… Ô sF¥ƒNOÆÛZÿmv3‘â¬Â2ÞËåŒ÷¾¼‰ZO—7Éܽ¦j ¾èÅUŽâû˜LÌ8-Ê"É©C‘Ì6¥˜zŠ#–¼×'ü'¦ ¡]¶¨Œ¤Uóè7–)!é›–;^YÎ ðšEÕ7ÆåþAüBaÜ#‰Jô_ Ç©Y¶žÙ–7W hàW›é:c<•Ž’ զЦ¨&Éñ¬á7çí ÀWæ H•©dŒ9gþôŸôpÛ*œ‡|ˆ=/O5Χl‰¨¤ØÊÇ´îüÁsVöƒ3—ïaªå€Vö§îJs¬<æß;}_ãg=íÖåût_rcä[ÖÕ¾\—ï“øÌ]…PÛÞNÔ$ÄÚÎx~m®ó7æ7‰aw\Cô{O¤µˆ÷ø¦¶É‰±à"ý§° ùàEš¶P]¤FÝ©±€ó»›«érµþh‡é°0md ÕÄð A«q"0Éu2¦qí…·»Ú~Ì º~ˆåá30ýnß2¤X2‘ÊÌl²_»*sïF%•ºvbÍD‡.ŠYàà1í\Z³€àþ¨…ø‹]“¾\ÜéUoR€Íû4?(z X¼¿ªƒ.Ë„Å<†G^ß:JÄuÞØÃæèÁ?c‹²ú Qê~H—Ÿþû¼29<.T²öÔyeó¸\¨tÍÇó ç2¹PÙVÆ;Ì7çàs¡ŽbãÅ[ Ý ÃÜf±§WÖ ßVo ã) (,h@I€a"ˆê2#KxÙ@%Ù0bQ µq‚J°ªC¢@ê—'âE„NâGÄ]‹z£ æ°8Y,ÈU–šãºÓxÆÖA÷Íäë ³ª*+ÿh‡ƒâúó2ô¼ãÿ:ccÙ䶇ôžx¶“Uµ<'¯i_ sDе^gWæl¼óäqšv¥¢¡O”*S“ÚDˆŠ¶Aq×Ì3V¯#z ÂÇ¢ XÙ7ï7mÿ…°Ì£Fp6އÖ9G5%» ZNWÓ5šz7§Rk¡Чã3 ØPÍùSjÄæ­ÚMßvMÎt¼¡Œøëa&ì1cРCÆÀpo’ZDú5JÕüoui¿m¸Hþ¬p÷v3o·ëR7$ÚÀŸ>ñNi¢ýr çØj^zuÅ2¯W‡l“§;Ùp¯ÇR*Ü1º¼êή¥¥\¿ú0TÃTW§|·Ý&ä8'ÈŽÏyýêW&ØßaóÀN³ÌóÝ.i¾¾6E¡ñ Tû ìC&/â¡_¹y èûâú™•£_ýí d[y¸¸žúiú¯ÛÑ|2~7Zª–iðx1—ïT¯™ð»ùÍèöÖ¾öç£äÝ¿Ñòãb9™.Ý3ü>Z¿¡Éǯ§Ëu‡7…™$××SéIŸ.æ³ÌÅ™•ö^¿ÕšAPvö¹ò(=Ï«lCÃöþv»’G ä HýICuLK°åéÝÞÊø]ÔcQmíó` pU w=áSŠùlyRN z>ó)óúºíÇæ2nÚGŸéÑ6ÕV,$šÇ©Î¶IѲYeÿÖÓQ [±:ŸJ1hîµ$A…ÞªRÊ÷‚æs˜è®È7Â"R½-Š&¸éÅÈyöƒ·Â„WÙ× ô.·ûß¹2/Žø³“)hŸBµí¶k£g¤O¡ÞìötŒˆ ØÖíÒX™ÿÎËÜl²hAo²úû_—Õ?"šÔ2J~ÆXÙþW(ÛUHÖFÿÍbäÛ3*U™M%ºEŒ “¼/–£«™wYÐÁ™Ós2/§7λÞžŸ9–]Â!Oó$£ÙZ–~•|šЛѿþ˜~ €”HÔ`¼)ã@òZ¾IŸ<e•°/Ù ‘JÌó±Wì2CÆ ˜`€X8ÔLqòC [б@èVÞ2Èâô ÿ˱],*±¦ë“Vç‚DoÊý>wÕ¹âQl*õP› ÏÐY7³4£ˆºÿ4~P >‘ £ ã@Vµqw F –ÛÆ 0xnsiË «ê€ö7 ¿È¦3:Oé ÄÙéÎ(Uóø]m<ªÖ¾ôzEؤÇlˆ€Mw¯ö/dö º ¢C*ÏíDúž—¯(ÓЙ§½Áeëp·ºD5$›ØšHš•‘ný«T.Õª¼½¶Þø-õ'kùâáa•£öä|žäžœ÷䦳ÙH^^ùcúqq}íœÍðñ€3ÉÃÈ𪢋O»#«³ vÌ*7%ãSU‡:ç˜VúÄo©ã•D¼’ˆW‚&gÕ‰ tÝ4%Œ æÎÞØ‚(;GV3 Û+gø:ÂV>ÙÙjîþEÖóó–êÄz7ß%üzˆõ·±4THÎYeŸŒy0É'DN'5nŽl˜5ó÷84°FU¶# æW™œ6Ñ\}ºòøl{|}H}H7 b·Ï W­ø¸tÿ?Êz-ðr²âJHþûH­bRg<äÿ|¡ò˜§*=<«O4vW~˪±èQv:8°BS¦1^HX€MhU'ø«Àú0;,îÄy…8xÁ`}ЗöÓ56LÁDcAb$80¢Ac¶k¾àÁc‰r#Ad '˜¬m[F-‚Vùþ K~¤Èþ£Åß% îwzàÐ=Sš;t×Ô£Nb{}-Ñ“:Ö< 0%>U/+Â$ÿ1s¤Ê¥Ùç»]^ßfÕ;aòò•3G%¹Ø·7ëûÛÙÝ*ºIæaÝ¥Ä%uÜx»ïÕjä~½¸fS¹;îß„ÓNFëéýõby3Z3ÈáÑ‚ B8Ÿ¸×v'ghÂÏcLÛÐoʼnx^Œ X##Ô ê¶íHÛ,§Z&Ô£zôxìöUä÷P êìø›ºw%Ç¡±ž|?»,ºÆË–>ó­X ¸í7ÀéAÿz=n;ŸÅ›æ*ß<¾M·[ÔW½^¿OBWà^pa›Ùîâÿ7Ϩ‹Šé¬¹`Žr…à`!ºCÕ‰æÂd‘Ž“OŸ?èUZÔb5”á¡}/àÁö³å†(½§ÕcYD…2†©£Ÿw‡t‰§¹­Å¬¯×CÚÍçwÎ4ÁZû{TÈ ÞÃ1]ÝK¬þ ¶‚ͼ‘¨,i(Œ!@u(ëB~@¶ eA„Ít¿¸K¹e2Àú>×U¶Å#ªë,JR8,d„ðYtñä&ÜðwARÌ{âò˜Wµ©€É78Â(umœFliíbÓ±QyÝþtŸá„*\îvå79² ºÉ¶[ü…—¼}Ç!x7•COÀÎb›Å‚Åuòön9eH¥)à ‘¸½›×wZ¹i¸þ}»H:Ƥ”S³¿M2‰»ݾãÒ z“Ìf ٕеAëw‹;©òuh1YÜ]‰¼ÃÀõ2¹e›‘8žÎV‰½y†A¯Gï–Óù»iÂïœd2]¨Vc3¬¹1Jž.7)’õtÉœ5ß%BFóÑýl*wæîWBÌî邺4qhCE‡Ö9ÜEÑÄ¡u´„¹4qhÃ"Š&=Ò¨ë¸vŠ„ßÄÕ@écœøE›<âê oòˆ«|$|9¤iÿŒk«Høº•„¼Jær2ýc´ý! ;Éx*feÕñuœ´`’Q©MV¤]M#´±K‡æhc—&ÍÑÆ.Mš£]š84G»4qè€6† P¯.Q$< á"Ô«K gic/!ÒP¯^qð€6†‹P¯.Q$< á"ý1¤ûþˆ{"ëÁlÚNKß.¥Oã-NèX QìñsÂÝ</&S¹²½¿R%kX…\Ú2Išeñê㌻‚–ÐàÚyüþ¹ð¹U½JfÉúãýõÿùõ×X’Ño´­­ï§érqÿg2Y¿“þ¤û‡’\biÂ(eO^ÝõXÞz®Çó}iè‰éŸ'ø³¬¶ê”„r¿a¥4ØÔM‹f ÑÙ^ò2nœûÖF¿“ËÝ?˜Á>=X´Pü Enj@x½‹ìmÔBÐÌ<Ð^‡ÐÏi FZ‡°)|„‚62ò¹=e§€ö†ñ›ÏŸ>;’xÍñýó»c¾Ët°é3]G·S<åþêãL~7ý—°²ÞÚî›60ÔÄ*@.óÇ©¯ j}2ûº¬Vê"püû— ÎvL¿› Î.&c›F#xò.;:Ûéþ%7;}Ÿog2?íqÈ¡Êèô²¦ˆR™êçàiª@­‘ïþÓ->DþÓɘ9Z°–4Ðk-,P‡„h‚–…è¾Ûî|4Þ…-¼?KÑ•-±”çÐs8'6|õЭá&@Ôy ›É©Ëó§}`ÌÒ“ºBÄÌ>Š@@ý¥ZrZE°…„XàÕjÆzTAÕÃŒ‹G¨9PyQ*6BHMAm¥å —ÄLqºÑš®‰`€tf$0É“xúúô _pñhqšð=ŸÆ¿¼€IÏR0Ì^'î& .ÖgíTo}_Á³®†ãúX§ãŠX¤#R¯)ã»^Óv¹D[ÚšÌ óéc¬‹ýf=éFÿe,idŽ'©®øžNvE3}c´´-£11†Œ¦0¬ª}~žQ4-›¿–ÍßÊæï!Ùü}˜lþÞ¿t„ÊæïeóïlÙü;.›Èæß²ù;ÑgÈæß£eóïLÙä¶ŽŒ\ëQùBï?óRIËGh± ø $¢;åÇ‹‘½ŽÒ‰Ü¤{‚mRvýt8A Îb‰»!¢Šå¬åI]BšN½ÜXzFüf¯É‚†F•É7×b²‰4V$IÀV‘a.Š•(Œ¨@žîŇΞ"$G™ƒY88¤ç-!fQ‹ ‡6rYáçmÑ;,â'Q‡ÛLÇE'~±*i¢mÌK’ÀøŽ¯Ñ«ªôîrF‡Ít4`c{ÊÈNi÷œÆqÓÉH"¡"öër¥fA’õ©ÊÆé!ÝäǼxÐTÚ%"i—ηÞz–ÜõvGµJIã¶(wGÁ£²‘Ð1aéÕ¾¯†©ÒŽžå/²Ða]ÛÁ¹êÕè!À0sgï¸D<%í”Üô@(•>–f|0}«„އ^-NG â•Wn¼,PíÕ¯¢µŸI‚ă…Á¾ž4SÛS„,ñ±Ê€¨#5VMBöh³[eð 3ÙDé=“0 caA —i‚OLõOuY_~O¥#¥M%ÓHÊ•FRŽ©4’òŠJ#)'TIyM¥”¿ÑŒ£©ÿFtÜ·ô€§~Í6Fì³íïM2 Ðmîhç+æXj—{BçžrGH1ÇR»ÜWtî«@î¨*æXj—û˜Î}ÈdÅKír¿¢s¿ äŽÊ¬bŽ¥v¹OèÜ'ÜÑ!¡˜c©]î×tî×TîÜ9£YWOÙ ¡á³ÑäÑ -ƒK>•b‡NäÕ3‚I|í#˜W†¥‡´ÃC^¤Òƒ”V›g¡ôÞƒÝoƒ±A«43@WW Ðd±Š~}ͱx±üœ—aƒÈļqr|~/ #)ѧ'Ÿ2}%Œ*},L*]žÉ§Òei*}"Ì*ýZ'T:kÄs±:“ÃSMb’PÉÈxlÉäl[6‰IB%aë²IL*ù ¶/›Ä$¡’?}¢“„JžÀÖi“˜$Tò5lŸ6‰IB%³Fo yÂsCÔ?¥úqRHýs îÊé*ïý£ÈÊ©Œ&“åtµº¿JÖ+®ëþnÞ]03qŒô{蘆 xÈ5ðù$nuRÜÕH­â ú6 gg+RÞ)U¶Iw›“ A×ÂYB6Ppyi§%`"í¹l@»¬x:>¿‹¯Vì •v9Áii±—Ök:á ˆÖ®„O0.“²â"¿ó¡ˆ_½mß¿Ò6;Ï…ßµ$Ã½Ú MTx“4n‡lœ ±Ø¦ôYÜ4]ŽÀï§£%˜p³˜¯ß)N§È;Ø(i ÀYLúûnÂÇåG2ï&]!”.´‘ÑèæþöLy·¸ƒó– ’¹ÈnÒd~‡Ô{5/æ„j6KˆôO‹ùôÞzáÔ©ñjM%«‰¬XNÉîæh}hÒúnºÂÒþœNæxêúÝÝM¼^&XÒj´¾[b‰ïGó»Ñá9½Z¢‰7£å‘Ûe2ChBÜÍáÎ7ƒ)FwoïVH·Lo×SL]Œ× ,m¾ø€N¦c.yV3¢#„ÓÜÜa ÛMç-l“½…`¼[ôø1uªÁ•.ÐÞ=é7)`/1Ìœn¾8¨õzrβ2ˆö£ýxœº+ÒVû÷‘q*^["·ŸA\h•i@cn5“ xªAƒnHƒœwˆA:þebœu«¦Œ]©´˜£•±óD¾DêîBTQ =C"‡8?Ì’1†”:ö2X9ÕÜüËì«h»¬?§Ê¶5|Jn_ø”ÁNñI6ê'¤BçzYEÜ I9`Þ´ifˆ öú"6ƒ€¸ÚàA2k³f‘t<ä0ÙïOÇnýÇ\ŠÇ—!D_‡¡6¨ DË©7b² pÓóð…øÕ-¿³¦g*‡ ÅŽ1'Rä‘§®qv EÉ’lž(xPhkÀðr÷Bø Ð‹¶ä™Á|¨) 2‰7‡-6g›Ä€$°­SP4†Q‡ kÖŠ¶;-J®½cqguϸ‹éá¬]Gæ¨lÉZšlÿ°c°apXjÉŽ)6ÏUYˆJmûï|Ë&gËLŽú优Wð„f so·(iE4 t0C)#0Hna^ñ›ßAVgmŠã­5L7ÀÌâvÞQ6Ñ;òÁ.ß§êxAnCwö †Ãvüñ&$OR;ØÐ5:‹çp¾œRvÏØ`_Ñ©Ík^£P†*ɘ0Ç$ÎrÆ¥‰õƒ{ †Å½!Y²"J‘˜A¦HÜH<´dF% µ ;dUp¬Ä…ç³ã…§Å‰ ÎÕ4¡´ÝÃOÒíÙ@®©ÇX•;èàÂÜÁÖæÚW{~×xú¡ãœ³¼wàqÆäY‹|„Ï€u¾Ãéü¥¾ÃðBñ‚©,†Æ;O˜ì‘KhˆS™ƒ ÛsôŠqž•ÁÜGtI.c>Ú~ËXðn}pˆG?T­E\±§X°OèZ„eu4&ÏP¿²ÊÒ±¬YdšµMã6%‹×àŽê¸oºFgxva‚"[êô þ£”*Åe÷œ¥[8¿KpÓÞîÇqWWcwÄ@NÒPGÅ ž¢bši=Ëše¨õxLè#´‹×yHû˜/7€TKV ™ÄBî¤Üg'œß%¸Ëô㸫tÞèQavRŒ 5tà‹ì•BÎ]À!ä¨çÁôÂc…§W4UxaƒUvˆ—á5ÄK`u¦—åμÉhøAw„Y¬Ãa3ÀáŽ!h¼Žä6ÜáŽ2êpÇš°[fr!á%‡óà”(êܶGH¹×=p´{Ýã0`ùãñ`¬R=šXW8ÐÀçºÂ=–Ñ®pÃW¸Çcˆ+Ü—¢®p¨M¹ÂA¹î §ÙÅ»Â}qâ½–I·ø8#E ‰ÑcwøüƒŒ¼öÙ…ù¾ëW*9#2‹?å9<£è ³ºÌÙЙGÎ1rvÞ\‘Óp'*'C)á°`åëge1=ßGYŸ»ž 2¾àêÍëì^ó¹Æ2š9´"ä}èT3È^&w‚] ½¹ë¢C›».žÞÜuѱ›»^cñ¼­X—bèV,Æ'~+ÖåtöV¬ËðlźY\b+(vÔV¬×#­XxذwR±q4˜Á°­X¯g[Ìš Y<ƒ!ÎEq®‰0pãÔeÁÞ8µ§N/°ÊÂØ8…ñÃ6Na^Ãwfºü¨­M8»KmmÂÜ/µµ s²µ s¼µé³»èJ³µ ã‡mm¼.)â?tóÎîR›0÷Km>ÂÜ£7a6ƒ6¹«‚Ÿ*,azs»öƒ~{€Y² nF·`9ý0]®¦÷‹åÄ o€BíõSjl‡< ‡‡ÎÄza fÆrÿÆ2Bʉ²¯t°€˜æy>=>î.Aaü½L‹mé5y|ëfšž}Ø P$1e°)/T‘•Þçæ`x‚ ÒϬÓï(Êäìò@Kš.2s-bñîÕ{opóF6›V#³rÌta1V[ žØ17D,N7öRö°ó7¿¦3ÃÄŽ±ý~ªÁ£«—éå(Þô ™Û2`0D¸Œ/)¬&ãó„5ȉ®=›÷ÁoÅK „öxÈÖ¤z FàC7–” Ú’§jYèð}Ä)pá‹eQm³Ø%ËOYqÚÿÿ½}[w¹Žî_é‡~H?õŽ={OÏÊy‘%Ù‘[–|$9ÝíéTšŠéÑôÛÁìé½ü¿Û‡éDþÕɯëãÇ÷óáÇH´›ËÙÇÍî”°%šŽ÷O<¨Nûü4ÏnììψP>\åbös5Ã8?4ŒsóMè ²ÈM‹ hf2{ú4˜>ŒÃÊ^®žî²Ð\ÜsûËé(ýhÀ¸3µlÙ© ÎMŸ[ŠšoÓÔ"ËGƒ#, 3†<$¯"‡LnUfoaÞŒBÆaƒàRç<¬|‘Î4”‹°_Ä/® Z‚ÊJ™êUÛ#eÎý}Fd²î¡d > Ì ŠÁ‚Òð–0N‰µ •Òä¡r[‚ d’KŠƒ[FšÉ…ô.}~©× ÆVi–—s DàC©¬Æ>ZM Wy ¾ 6?žUÅÞžvòW6xt‚$>Ë^ç7^åÏmˆå¿è*o³#óYºd¯·!½nwy^ŒÒo©ìr·Á2Lô$h 6úsþ–OžÕ'»M•¬4\¡ïR%³Óþ‹(འ3MEö¬‚MqèX%¡»‹ax•]¤6XÝ_çÛ:Ú°ü&çkÓûK~Ê6åðE¬¿*ý…]Áø¯_t .`…FÒïq‘¿’ ,|”ãºÕð>ü uõsžu4êQÓœºãà_‹éx€èEGdß#éX˜÷Ð2Ð»Ò æÐh·I…r\v´XÅ^ôPì¥Ø‹xÅ^0ôtÉ·<(…cG‹UÐe]Æëà2Ö¸.©F¸dhTG‰Ô?šO!£'8¸ÀÁápŠBÏIWˆs© [¦àå]©æÞ8õ«xʼnúšNΜ’6OâG´„ 6^ÀÚù²Yx×z=Ö ]›«ÿe[[sÉå79°Ü²AqѼ†7ºZ :sKå¥LQúQ¥N&/ÄñTdb®Þë!\;ñã ?UlîòÍPN†zwÈ/Ž~÷‚7ÕÛCE:§p"ˆY‚‰`J5¢|ÉwP3þ´Ë“͵,-/ êo*àhCn{64ÿfgCù}lÇo›ßýbCÏV‹ Lî¨ø^ƒiœñ5hJ-™¤’D÷0ˆÅgÈÖ\g17F].Î}Õ†§×®\Ã\åyE½Ñ~]WV¿k¤Fu‚WF[E×C;æÜµ{犧Û_YâÕ£_ÙÅP“åžûô]³ÅoÕ·ªNÉ:=ºgZ|øî—k¿DÓ2\ xçíe X¹šçáùŒÎ a—ÿø-ºïßÇWú2æCƒq Vr¬¸÷GOõóýb¼”ÃDB5|kÏâˆb¯’ Î72æþš;ý‡x+€š… 0±PˆÂ¤A “ †)L¨0ég„* 1@O2 aw|“‰°p¸Ø! “ï¼ …))"lá¸0añ¡ ƒ›=þ:<ð2ÞÁ‹x ¢Í#~´t˜£Æ?‡7bxs8‘áÚ­2F(ìvpÚpSrìPÓ1€ †ª<ªòPT¨Ê¯ªòk‡D ü bZ~ñdgp‡j°EÝó öà1n‡‹¤GS»¨^e°ÆÑßE¬¯ª9¨Æ©!}üTÍÚÇKÕ¬¤·¨1=üXÍíÅšIïÄPX/ߤÚnõµ­ K šÝÅöiWFCpeá‚{˜†'‚lë-õitðêXbø#ä5#¯Èx”¼¢cqòŠŠ3W(8ž^ѰˆzE…cê ŠªW8®^ÑÈz]{½G€°à{!$6 @ƒÚº‘ˆEDPÚ¶ã]c1sûÅ´áØ®ÜcÀæãîT\½÷*vt' "¿á^@S^ÿÝ€¶J¬ý€Z©”\겯ëY­cؘ¼Ÿ: ÷7][p{ÁöuLxÜvG]Dä";¸¼>#ÞØ˜a¿ˆcÅï+Ô+†ˆ¶Â÷êI¢šï?P>w§Â ‘"ÿéïV°ªráïX°øþûédÈ—Í D$£Bœ˜ã'ůƒ£t_Ô­ëŸgÉž~õÂg‰ýØ„iúMw7˜M®ÇËÕ“z2n2Ÿ…ðËÉÍl°zXŒ¹ Ãùl%'5O«¿îÇAìt°\>Ýì[_pµ'³' Vx<˜ŽG!ÔøOYIõ9ÞË{4z6¸ ~U‡žÌ–«Át:X1ô6¹»ŸŽï¤æ4úi5YMƒ%9<Ìò¸f£ù¢ÓÓ$¨h‡ïa1 6àýx8¹ž #ô`³p-ÛaâhùêÄšªYaºx¹¼Ct°;¼$<è(}N(s§“3 CPî$ ljd°"ü¯»¹íPÁeŒ™p@S @ÚW¿…€/Ã[µ4öÓ® ¬Á"¥¾ÑjÄ—Š}ô¹jè»ÚqÄÄ­(fβÒ×Lp©å–¬·°òwðòß19éâ0²–H.OgÉó“¼e«Ã£WLÝbg”b¥1ß%í «ÑÔzËõwI–nEyüùZg{ë$}¾ÂÜ÷mR›öúç¿Óïéaìî\YðDÖ%®Eq,QjÄ`óxµŒã4ɧº-ÛêÛ2Tg¡$ ¥*ª'Ý”ŒzYŠõI¶ÿë¯JQ¿` »h?¬b©zXÅcCÇT· Rµë9 „!¥×øY½…ˆ#üý ›Ž6ª¢›ñy3"~z-Þl´±Ñ§ƒLöúO·Ï™fƒ•l±Ò² le…»”/üœNJ{«£„ú}EýŠÔDÎI¡Ô¨¦QôižlìÍ{«"ßpÊD6OZ½‚¾‰"Ý¢¥·±hÝ€â¼.ÍòÈ䑃š¶±Hx¬øG`Ð0èWªQѳΆ€Ù¦fÇd’muë«ùuig¤C&¬†€¦Wã P"ÄqdYý“¥f`©àmÞ˜|ik­Ÿ”Q¦š›¾zUõ2Ÿ¯^c ƒKhmÁœð`Básð¦?¥ùPÜÙEû>Ç Õ2Yad"tÒŽô5V1"„p»Âd†»¶É혌[8h/¯ïÈP1쪯Åô,@HÛÿcz»)GOô?_¹/Vȵ~r¦©_œ“@ Û\ø–mRºYÌ·ƒÅÓÝàf2 µ‰c£­…t ÍZù>è÷ûÅúœÁäPüÃïÐK¨ÀÁl0k¢ Ohƒ“Á ¢Œì”< €´V1sûŒ`Mù–¨lQUªÙÞÚ¹Ì_“6b›œvÇê_=-ói]™¬Í^Ž·e)6(å uÍÓ°(¿ýBt—Ò“‘²†a0zÖŸó‹ã‰¢%‚üÒSŽªF±'™UŽOОZ1h6Ò«ŸºãýªL‡m oXl­D°µ<:ÎÂNøFË ] ï8šRÙ ŸªŽÈdàÞR·4yÿŠ+úSFiyØ%¯ñ¥¹Œ€eFŠê[wÛhΩA\»ú|ç×@ïí÷bê[6/ÚÚ 3PP¡¢rÈöª(”ñî\Žç¶*µÎ]ÿ`~bªIŽ9y)´ÜŠá(׿ÞÉaHZÿµ.”ΫuÏPrÅÜ+ŒÜø&}.d˜”=rhe<gÊØ¦Ù¦¢Þ%Çõ˻πÚX.³1³o¢8Îw=Ôm¨£FQä™K^j»ØTnñiÜÞ"…[tú6$u £v ø:ž_)6KR|.¦Þ9•Þ0eÒ9é’¸©’°4I̬GqØÙŽ4m‚ãKKuÅ iœ·´à…œ\¤{¾E€²ërfÎ+l(ÚIâÞp)ƒ–¡¦ÃMåCJˆëÇZv· fùò´~©ƒr± €0ƒa4 +Ì­ìü‹\Ûëž=F|–[¿Hˆ}úΠæ_J„~‚AO6›ê_¢0;qóÛ”q#vBM5úðfù1ݾ687¹= ÅØÑúeÈ¡lX)ÇhïDIÑb1Ij‘aÔ p& •aÝ-OÿÆCÜ¡-†û"?¨;'|˜Û,Õ@RÁ)V‡J„,]–+—âè XÊδVÞ€ ?ˆµ¬Þ2ù&d“ °ï/rº¼<$kõ"~èë2ØÅ|ú"~@¹¤YÖÿ‚ÂÑzC²ŠsNŒ,j^“f'¡/ne?E «IrüÌØT†jGTÎcœ ò>4>ÔYÆØ~:CŒ^¬íŒ®ªÓþbó‡"1¢žIká뇖sŽäC-¶~#„±9dÚQ·\–jº—åM`©Õвˆº"–7År?|Çü£øñnòËsÔÚ®Q÷½(öjÔÌYÚ;WI™®;*P†É» WlBþXLVãf0³ù,$dŸ”_DOà!Çk¢”ö܇,Xï€:Täþ°KÛõ|Ûvz¦æâàDâcRß°*¿B}žÁ:¨´ÿ.tˆæîŬk¬c&¾wÿê|M‘@³ «B@v¿P ˆ6 ÷ý¡“ô†üBº^†¨Cûc §<Én÷$ÿ?ÿn/:Hj&„”Òžƒ»_ÐùýÕÆHÜ5eÔQ”É=®ƒá#;$>¶ƒWÅ;ºƒBщîëáAK§ñ lÑGy`I¬ã<«¤ò/ð"Î>ïƒÈ9󃈀Ïâ ô‹IõÕ]·±òƒó=Ù kµžm!¶/¬ÞËõmª¼O¥ƒÈåLŽêŸ¯&«åÓýxñtõ—=Ikèòç 0±s\×teÎê¨æMr’^Í~.­†¼È5Ð, ¹M»‰r应šB¨úœ¨s}Ø UO›¹o–€‰ê§·"â²§¹Ú<¿ÅJÎóH2Ço€k¹š=:éã ò(?éç ËÉ Uk„g§1ÃèÖÕRÛ±@V/žLûq]ÊÕx†W¥ž¸â”ñ<«ÃÙüS?$ÝKŒN<ÞJ= ±a*ER¬_úò¸šÙ»÷ˆQˆîq&æ*ƒ[i·oØX»þa5·½ò¬¨¨¿ÿÄlô(’Òš°¬ö§u]2™Ì&«‰:Z9~?-'c\¦óÁèéz0\ÙiFìÝàϧ«‡Ùh*‡—åx°œ#.ÿ+Š¡\P‹“·q°£ñõàaºzšÍWO×sYFHîåjSÍ` ÀÎ;¤è–¢šìgEþY‘¶É#£‹ªÉP}P+:^†I2Ï´Äœ ñåõøù’ªƒ ¡£‡_ÙòÅGi *(ß`¹ÓgÐÌ©š«‹+Ÿ]¯¸×6H3 Ô½ú[àiGfO‰è‘®ÿÕ2F9³è‰\çÿ߯‚×ÉsF†'ÍúI¨$²è/ç+œJ_Šü;¶WÎkvÊ&Õ™=LŸ®O©‘L꼕oôÀMþÒ÷‹7ŒìÖ§l°êßÕ¦ClϨÛõù“LO"¦/Qß#×ù=Ë m™×gb4îSÎŽAœ{§Gr{§ÍRÌ‘Ôï:™wh×zÂЗI£ÀW;2ç‰ÃÍß°æÛwO4ÈôcîÇ?kŠûâ~ó;•^¢Áø&cVîƒJhŠìõÞiÃÍyVÕü8¸Ey/§6`æã©6|¡©w˜böUlÖCº OÄöVc?ñזּꦞZÔ¤4T¹'¼˜I SêH7N ±ðî–³lBÔEâ/ÿqû]Šéâ}|Aÿø ãqÏ*)¿þÿ“8Ñ'ô:Ô¿Õa’ëb: 8½ïÈ›lÃ?…¢~ÀÔÍ©4³l½c‚Yª¾ª¹¡…(¥nN;ºÅ`ð~tG‡v-;ê6ýñpp»Eåß³w`Ò]ý‰™Cƒñg ÅwæšâêºFoÓL'q£)®`3úçã‹ ÷`¿/Dr°OrWTØ–LÒ#DkÚ64·µ,^ä5¾Ð7(•18^§?ÄfáÜååÖ ÈίLLñr ²;°a×_Û¯ùKÓ¡> 2ÞeèjjSBíG„Í_£T†^˜¢¶rýΡIŸ&‹›É ¦-ÕÉ䇩}:¹#ÿVu¨ž¢ÌzýóC¬Ojv·ï;˜ìžiî÷_MÃ{©&ëË­iÿGD_µun¬ê -p#é&4ši»—‰ïª˜ò.y½˦, {¶šxÚÖ.¡¯¸0ÕTÔ}’fÓÀ:å¯x­è ¡ Ýù^ŸK'0Ç|œžÉñ;<Ú·hz“^€:¿r`¹D§ˆíîr%=¢"«ÉéQ 8Ö^™5o”dÃû¨˜Û®ù2OŸ;läô ¥“‰4Üîü–7Ùç\p{èw\KΪ“P‘Z³]Äò5û¸N*{wÜz-Cè?I¡=kú/º¦ÿÉùX¦U72;¿Zÿ_-dôd›†û€¨EžC6íûiOïêä<…ë\=å÷ñ_Kè÷OƒéäŒg«Å&-ÆÐLá§«é`ø;¨€ð4CvÉu¡O?/›“?>f#Â8¼iaÏÏeA§ÆÐ1çÖ‰ÁøÄ¹Ïø™˲šeõàâÉ>7ê,ׂìyFKàVéœD¿A>vtÖYÙºŒ¯×ê Œ¶jAC‘îÞLØ}!Öb“fÏo#ñ«x%Œ­×7œ'öNÈÖÚt³¥q¶­€3û‹ÈÐæŽ!,ñÿ³Ê·˜N¾Å<²¹êÏû:ÐOKí±¸'×ÝU¡½ÌHËìAÊ õá+Oz•ÁþǨcåómìØQ…àI¾¸ïR© wÔgÁËn½‘ðvÕÐo(.Wç5§²Š„Dð³*Î…ªN,ë6ý1ØE1ÉJõÆ{ûÎ![@•Î)¢Ë)=Š.¿'‡ærih2ÂÚï±n`‰eÀäU_v—›@nf¨¾ìsPÏ]ª±€+íË)Ým®UxP³ZwˆÚÐèÔÚ+Gþïü¢"½Ü^  ±™ŠobçÞXmõ ¯¨È0‚ox¢ª _jd½‘Sjïý㌯ò±5…ͺÇQÎnûZ:Pá…Ž©†‡£,"0µ 8´òVŸD]¢¦ì©¿­¿G:Î}ö{ÄBÁÛm•Såm*àú)Êýb¼ÛHR\Âà ‰Üp ÆÒ]#e²tcÌ· ‡¼óÚ C7C¢Þ{m8O«6؈ IìmR£Xî•ßV'où M#ôœ7hç¼@Óµ[l ˆýjMÆß¬šŽ¹ôWàþÍʨúM4uW¤Î¢V/íîù´ µÙn)þmKò]Aý¸]ÝO?±Ñ¢UœŒ‡j`µÎ½{bS‡°F~Z'‡d_'MÀPôÒ¼E9tÕR)"Eã8ôæ{òƒü–c>N 1‹t¿Ê˜~£¿¬<bX« ùôQìÂ{P³UfµS›æp†‹†×Hj <ŽØ&À{*½Õ#sèi* ÞiƒøÄ3Ÿ€xåî&qEÐ,p1µ¦á‡8j†*vÆ{9ǨW‡zš´­ô)%UÃûØø •êøJ¼t9â7ßÀìgV}¸VÕ>¡Þ9Y°×p¸¦¿3ºwà=Þº¯%pžuéºÇû1]“Ä©•‹f=(cKf~/4§tüw^ÙÕ5’#î•þ–)&€]7Ö+7?âi®ÑÈaæÖ’y¯Ç6¶È{òÆÒ¢ù0;«ùC$_UNuµâ¥gq6R}T³ºÂQîùe›êMµéþ4ä7§'‹÷ª œö+òR6qNØ«![§õqù,pnFøðp¾ÕŽ*/æÂÈǺtàsö¿xàË:gh^·÷ÉìM‡ãD —*§ùGì/¹@Ù Cæ˜ÙÁ)4æá Ž9΢*œyÕ!n >Óm"Ôßíü«…ØjÄBlE!²µÀªÖ°ª¯aЫLx›7¬rÍê$gb5#j Á:Mme´Š€9‰ªq@ð™ßÓã˜M0Äêm=½e“x{To©=¢„hš`Âàý·sL"t²Ò¤Š\}¿þ w¨µ¡–ë0$ˆì¡·þ€Ã »Þ¨óˆ&_¯£|–Úßæ„—)²ï)/KÀÊ ²&òŒ•ÉïÚZ#°ÓÚI—„$`Üù;=ü:ØìDqyANdM\¢þĈ  ›€Óa£<ñ$ˆø|å†5A)„~b¥wSØÛPe°•¹z=ŠòÝD×…’‘vÔo—г¯iþëuºÓçrZŠ[À»þZž88˭ȲüÓ6·”úÁW+ XmK¼óõ!aíhõØø»[¿Ù¨: [×Ùê”ÖÇ­17¶_œæ0IH],nªA, Û"&1¾I,Ñz£ ê~8î‰þ\mKrÐ µ@Ü“¸âŠp-¦s&`åC†­Pëb P×Y‘‰Ï5éÈ·Ú €¹ÌŠJéɪ"Ô‹ é,k]„\¥Úv«^c?ƒ±¡z'À~,­¨ØªÄÈô{PNv='Ñ¿œ¶(-ßâ´ðuÑѾ‰Uùçó+ÐéÙ;ц…ØJ¥Ùós€l¿o`FãëéÀydÔÌæOÃù:$³œÌg(ìj¼\=-ïÇ„$ áÈ’uÚb&{ó8¹÷–Õ-u’U"‰åµ+˜Å»‘{3"OŠúFoÞã¢Ô¿Ÿî7“ay½ÿ¹ ‚>Ê9v$-AÔl`çšArŠtç^õ¥OsÍÂ}—S1 ÀcØÃÜD´laÆ÷(‘åÿ 7¼ˆWE’îØè‡IvD¾ÖAþåK^`‚JÐÔˆÙW€ øT#.ÞàX·÷G)Ò•@U±ýÜó- Ýcù~±äs¿ÇO¹qŒºp_M„áû哦ïÃiã÷ñÊú9Ÿ§Á•©£6Õ Á} „ô-˜Ð´4`AßÒ€}KÃÔ-@­bÔœÀn ,! .Q0Uò •îBÒò\‘¥3tåg£Œ¢ (±l1iF-"–€&_z(x ØÂ°%` €—€¦‚°% ñåØЂ¼€ˆ± @W×ÔÐW9°bƒtÎ! @GëÀÏR;E.ù2£ b–:åÀ_iÂמ|CHùŸõËx~ÍÁ φÌa#'¿CĦ]ÃM'ÞJôù’y-EJwPž43˜â±MHÔÔ˜ »Mw;´ç=¦‡až•Ç$;–Á ˆžÎ‡ËÉ ‘K¾d8ž¥ÌF!ˆ¬ËÇÑ"T—DÖ%(e6 Ad]œ¼äzþ¢ù!Èjr‚Ks¿½ù‚ ™Ž½Í"Wî!KpÛ(T]mRtu%$T]ÙÒŸÆtu5$h/¡fT&hF 5£„„ô¢û­ aè%ÔŒjFUÝyPÊhù{2X ¬þ Aæ×Þ8ëù—‡«d5Ø®òRÜuѪC\uø‚€Ì;¢E<¦ˆI´4÷%J›‘¤îÅñ%÷fH-Yü8 .:ß»[-ºùžQâ·êÖ+J÷ó[äåjl·¶dl?¹૊ÂLZˆóxd6§Y0·¾â:»M M÷]ÙD®=8Éâl»«Ò …ä¶I5q1úân@Lu“£N&åûƒ\É9\z`ªt….Ö¡ *]äîmPœÊ”S£ü9ª)j¬z&ö0EU¨_>CÎÔT„{u4lèÏ_ŒÉ¤å(-ôÍ6(pÒ¹Bæ•:‹i“—«üVÒj£Ä›Bý¼ÊGB"gôm7ȹ$k÷ÇÐò[!íCOj)5G=Yx4l¡øÇœ$·\ù + Øßð (¸fMË!¸&ï"÷"Ñ¿ñdÓQ÷«èÎ\îvÅ`‹½Ñ.ñ0€½¥ô>uØ!SœD«Jfªÿ”‹Às66úÍ“½þŠI1Œâþ[çà8ø;¾º1µA&jü%É6»ÚÚ$n£MÔÁ qEq`¡‚%!¢E[çSævii¡Ò“`Œ-'4í¨"É=k*1yÖôùýxö´hÀh<¯¼£ ¤Ž±Xw¢'è7?÷YªP¶€b¦ >WÑZ¿€ nImŠà“ÕÀk=¾ô“’šS hîa˺„¡µ-Dýäë-< nd=_ãp”P@|qõüšh]feŸÞ%‡v‚€1b'’R´¢'‘k1͢ƱTð"r‹RCrÕ¶Ü€‹†&90#¢6úl„y(J ··ÈÝ㻇õ²Â„ ð“°æhßúð“±ÖªÏÁ‹¶0|½Ðñƒ•VïiRV¿åjÕoóÆÓ­”W2^b ·äo,Ôé"&ÆYäu`ÑáǦ²3¢hJpÇýØ«u@è4óð^.¤`׃[±6nCÓa¶ÜkÌXí}y-"T``ÒÊŸz3'Ïœ-P Üé|Ø[R§«ëßê‘þ–ϰûz,¢)ñÌy•ûqãlv\Ÿv;ìü“¯Œ÷ÿRÐ`#Jäå…FÞ¢îh~ÞAJWæ‘›{ÖŠÜ…í‡!”ðÓ~áÊS÷ÿX-büçê\ÃñììZÌFØ4Ñ„huö˜+Ù8Td¨G:óX¼ÕÔ¶Îÿ9ž™=asm-3.3.2/src/org/objectweb/asm/optimizer/Constant.java0000644000175000017500000001752110701747173023032 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.optimizer; import org.objectweb.asm.ClassWriter; /** * A constant pool item. * * @author Eric Bruneton */ class Constant { /** * Type of this constant pool item. A single class is used to represent all * constant pool item types, in order to minimize the bytecode size of this * package. The value of this field is I, J, F, D, S, s, C, T, G, M, or N * (for Constant Integer, Long, Float, Double, STR, UTF8, Class, NameType, * Fieldref, Methodref, or InterfaceMethodref constant pool items * respectively). */ char type; /** * Value of this item, for an integer item. */ int intVal; /** * Value of this item, for a long item. */ long longVal; /** * Value of this item, for a float item. */ float floatVal; /** * Value of this item, for a double item. */ double doubleVal; /** * First part of the value of this item, for items that do not hold a * primitive value. */ String strVal1; /** * Second part of the value of this item, for items that do not hold a * primitive value. */ String strVal2; /** * Third part of the value of this item, for items that do not hold a * primitive value. */ String strVal3; /** * The hash code value of this constant pool item. */ int hashCode; Constant() { } Constant(final Constant i) { type = i.type; intVal = i.intVal; longVal = i.longVal; floatVal = i.floatVal; doubleVal = i.doubleVal; strVal1 = i.strVal1; strVal2 = i.strVal2; strVal3 = i.strVal3; hashCode = i.hashCode; } /** * Sets this item to an integer item. * * @param intVal the value of this item. */ void set(final int intVal) { this.type = 'I'; this.intVal = intVal; this.hashCode = 0x7FFFFFFF & (type + intVal); } /** * Sets this item to a long item. * * @param longVal the value of this item. */ void set(final long longVal) { this.type = 'J'; this.longVal = longVal; this.hashCode = 0x7FFFFFFF & (type + (int) longVal); } /** * Sets this item to a float item. * * @param floatVal the value of this item. */ void set(final float floatVal) { this.type = 'F'; this.floatVal = floatVal; this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); } /** * Sets this item to a double item. * * @param doubleVal the value of this item. */ void set(final double doubleVal) { this.type = 'D'; this.doubleVal = doubleVal; this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); } /** * Sets this item to an item that do not hold a primitive value. * * @param type the type of this item. * @param strVal1 first part of the value of this item. * @param strVal2 second part of the value of this item. * @param strVal3 third part of the value of this item. */ void set( final char type, final String strVal1, final String strVal2, final String strVal3) { this.type = type; this.strVal1 = strVal1; this.strVal2 = strVal2; this.strVal3 = strVal3; switch (type) { case 's': case 'S': case 'C': hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); return; case 'T': hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode()); return; // case 'G': // case 'M': // case 'N': default: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode()); } } void write(final ClassWriter cw) { switch (type) { case 'I': cw.newConst(new Integer(intVal)); break; case 'J': cw.newConst(new Long(longVal)); break; case 'F': cw.newConst(new Float(floatVal)); break; case 'D': cw.newConst(new Double(doubleVal)); break; case 'S': cw.newConst(strVal1); break; case 's': cw.newUTF8(strVal1); break; case 'C': cw.newClass(strVal1); break; case 'T': cw.newNameType(strVal1, strVal2); break; case 'G': cw.newField(strVal1, strVal2, strVal3); break; case 'M': cw.newMethod(strVal1, strVal2, strVal3, false); break; case 'N': cw.newMethod(strVal1, strVal2, strVal3, true); break; } } public boolean equals(final Object o) { if (!(o instanceof Constant)) { return false; } Constant c = (Constant) o; if (c.type == type) { switch (type) { case 'I': return c.intVal == intVal; case 'J': return c.longVal == longVal; case 'F': return Float.compare(c.floatVal, floatVal) == 0; case 'D': return Double.compare(c.doubleVal, doubleVal) == 0; case 's': case 'S': case 'C': return c.strVal1.equals(strVal1); case 'T': return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2); // case 'G': // case 'M': // case 'N': default: return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2) && c.strVal3.equals(strVal3); } } return false; } public int hashCode() { return hashCode; } } asm-3.3.2/src/org/objectweb/asm/ClassWriter.java0000644000175000017500000013336611541415063021460 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * A {@link ClassVisitor} that generates classes in bytecode form. More * precisely this visitor generates a byte array conforming to the Java class * file format. It can be used alone, to generate a Java class "from scratch", * or with one or more {@link ClassReader ClassReader} and adapter class visitor * to generate a modified class from one or more existing Java classes. * * @author Eric Bruneton */ public class ClassWriter implements ClassVisitor { /** * Flag to automatically compute the maximum stack size and the maximum * number of local variables of methods. If this flag is set, then the * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} * method will be ignored, and computed automatically from the signature and * the bytecode of each method. * * @see #ClassWriter(int) */ public static final int COMPUTE_MAXS = 1; /** * Flag to automatically compute the stack map frames of methods from * scratch. If this flag is set, then the calls to the * {@link MethodVisitor#visitFrame} method are ignored, and the stack map * frames are recomputed from the methods bytecode. The arguments of the * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and * recomputed from the bytecode. In other words, computeFrames implies * computeMaxs. * * @see #ClassWriter(int) */ public static final int COMPUTE_FRAMES = 2; /** * Pseudo access flag to distinguish between the synthetic attribute and * the synthetic access flag. */ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; /** * The type of instructions without any argument. */ static final int NOARG_INSN = 0; /** * The type of instructions with an signed byte argument. */ static final int SBYTE_INSN = 1; /** * The type of instructions with an signed short argument. */ static final int SHORT_INSN = 2; /** * The type of instructions with a local variable index argument. */ static final int VAR_INSN = 3; /** * The type of instructions with an implicit local variable index argument. */ static final int IMPLVAR_INSN = 4; /** * The type of instructions with a type descriptor argument. */ static final int TYPE_INSN = 5; /** * The type of field and method invocations instructions. */ static final int FIELDORMETH_INSN = 6; /** * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. */ static final int ITFDYNMETH_INSN = 7; /** * The type of instructions with a 2 bytes bytecode offset label. */ static final int LABEL_INSN = 8; /** * The type of instructions with a 4 bytes bytecode offset label. */ static final int LABELW_INSN = 9; /** * The type of the LDC instruction. */ static final int LDC_INSN = 10; /** * The type of the LDC_W and LDC2_W instructions. */ static final int LDCW_INSN = 11; /** * The type of the IINC instruction. */ static final int IINC_INSN = 12; /** * The type of the TABLESWITCH instruction. */ static final int TABL_INSN = 13; /** * The type of the LOOKUPSWITCH instruction. */ static final int LOOK_INSN = 14; /** * The type of the MULTIANEWARRAY instruction. */ static final int MANA_INSN = 15; /** * The type of the WIDE instruction. */ static final int WIDE_INSN = 16; /** * The instruction types of all JVM opcodes. */ static final byte[] TYPE; /** * The type of CONSTANT_Class constant pool items. */ static final int CLASS = 7; /** * The type of CONSTANT_Fieldref constant pool items. */ static final int FIELD = 9; /** * The type of CONSTANT_Methodref constant pool items. */ static final int METH = 10; /** * The type of CONSTANT_InterfaceMethodref constant pool items. */ static final int IMETH = 11; /** * The type of CONSTANT_String constant pool items. */ static final int STR = 8; /** * The type of CONSTANT_Integer constant pool items. */ static final int INT = 3; /** * The type of CONSTANT_Float constant pool items. */ static final int FLOAT = 4; /** * The type of CONSTANT_Long constant pool items. */ static final int LONG = 5; /** * The type of CONSTANT_Double constant pool items. */ static final int DOUBLE = 6; /** * The type of CONSTANT_NameAndType constant pool items. */ static final int NAME_TYPE = 12; /** * The type of CONSTANT_Utf8 constant pool items. */ static final int UTF8 = 1; /** * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, * instead of the constant pool, in order to avoid clashes with normal * constant pool items in the ClassWriter constant pool's hash table. */ static final int TYPE_NORMAL = 13; /** * Uninitialized type Item stored in the ClassWriter * {@link ClassWriter#typeTable}, instead of the constant pool, in order to * avoid clashes with normal constant pool items in the ClassWriter constant * pool's hash table. */ static final int TYPE_UNINIT = 14; /** * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, * instead of the constant pool, in order to avoid clashes with normal * constant pool items in the ClassWriter constant pool's hash table. */ static final int TYPE_MERGED = 15; /** * The class reader from which this class writer was constructed, if any. */ ClassReader cr; /** * Minor and major version numbers of the class to be generated. */ int version; /** * Index of the next item to be added in the constant pool. */ int index; /** * The constant pool of this class. */ final ByteVector pool; /** * The constant pool's hash table data. */ Item[] items; /** * The threshold of the constant pool's hash table. */ int threshold; /** * A reusable key used to look for items in the {@link #items} hash table. */ final Item key; /** * A reusable key used to look for items in the {@link #items} hash table. */ final Item key2; /** * A reusable key used to look for items in the {@link #items} hash table. */ final Item key3; /** * A type table used to temporarily store internal names that will not * necessarily be stored in the constant pool. This type table is used by * the control flow and data flow analysis algorithm used to compute stack * map frames from scratch. This array associates to each index i * the Item whose index is i. All Item objects stored in this * array are also stored in the {@link #items} hash table. These two arrays * allow to retrieve an Item from its index or, conversely, to get the index * of an Item from its value. Each Item stores an internal name in its * {@link Item#strVal1} field. */ Item[] typeTable; /** * Number of elements in the {@link #typeTable} array. */ private short typeCount; /** * 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 internal name of this class. */ String thisName; /** * The constant pool item that contains the signature of this class. */ private int signature; /** * The constant pool item that contains the internal name of the super class * of this class. */ private int superName; /** * Number of interfaces implemented or extended by this class or interface. */ private int interfaceCount; /** * The interfaces implemented or extended by this class or interface. More * precisely, this array contains the indexes of the constant pool items * that contain the internal names of these interfaces. */ private int[] interfaces; /** * The index of the constant pool item that contains the name of the source * file from which this class was compiled. */ private int sourceFile; /** * The SourceDebug attribute of this class. */ private ByteVector sourceDebug; /** * The constant pool item that contains the name of the enclosing class of * this class. */ private int enclosingMethodOwner; /** * The constant pool item that contains the name and descriptor of the * enclosing method of this class. */ private int enclosingMethod; /** * The runtime visible annotations of this class. */ private AnnotationWriter anns; /** * The runtime invisible annotations of this class. */ private AnnotationWriter ianns; /** * The non standard attributes of this class. */ private Attribute attrs; /** * The number of entries in the InnerClasses attribute. */ private int innerClassesCount; /** * The InnerClasses attribute. */ private ByteVector innerClasses; /** * The fields of this class. These fields are stored in a linked list of * {@link FieldWriter} objects, linked to each other by their * {@link FieldWriter#next} field. This field stores the first element of * this list. */ FieldWriter firstField; /** * The fields of this class. These fields are stored in a linked list of * {@link FieldWriter} objects, linked to each other by their * {@link FieldWriter#next} field. This field stores the last element of * this list. */ FieldWriter lastField; /** * The methods of this class. These methods are stored in a linked list of * {@link MethodWriter} objects, linked to each other by their * {@link MethodWriter#next} field. This field stores the first element of * this list. */ MethodWriter firstMethod; /** * The methods of this class. These methods are stored in a linked list of * {@link MethodWriter} objects, linked to each other by their * {@link MethodWriter#next} field. This field stores the last element of * this list. */ MethodWriter lastMethod; /** * true if the maximum stack size and number of local variables * must be automatically computed. */ private final boolean computeMaxs; /** * true if the stack map frames must be recomputed from scratch. */ private final boolean computeFrames; /** * true if the stack map tables of this class are invalid. The * {@link MethodWriter#resizeInstructions} method cannot transform existing * stack map tables, and so produces potentially invalid classes when it is * executed. In this case the class is reread and rewritten with the * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize * stack map tables when this option is used). */ boolean invalidFrames; // ------------------------------------------------------------------------ // Static initializer // ------------------------------------------------------------------------ /** * Computes the instruction types of JVM opcodes. */ static { int i; byte[] b = new byte[220]; String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA" + "AAAAGGGGGGGHHFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII"; 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] = ITFDYNMETH_INSN; // b[Constants.INVOKEDYNAMIC] = ITFDYNMETH_INSN; // // // LABEL(W)_INSN instructions // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { // b[i] = LABEL_INSN; // } // b[Constants.IFNULL] = LABEL_INSN; // b[Constants.IFNONNULL] = LABEL_INSN; // b[200] = LABELW_INSN; // GOTO_W // b[201] = LABELW_INSN; // JSR_W // // temporary opcodes used internally by ASM - see Label and // MethodWriter // for (i = 202; i < 220; ++i) { // b[i] = LABEL_INSN; // } // // // LDC(_W) instructions // b[Constants.LDC] = LDC_INSN; // b[19] = LDCW_INSN; // LDC_W // b[20] = LDCW_INSN; // LDC2_W // // // special instructions // b[Constants.IINC] = IINC_INSN; // b[Constants.TABLESWITCH] = TABL_INSN; // b[Constants.LOOKUPSWITCH] = LOOK_INSN; // b[Constants.MULTIANEWARRAY] = MANA_INSN; // b[196] = WIDE_INSN; // WIDE // // for (i = 0; i < b.length; ++i) { // System.err.print((char)('A' + b[i])); // } // System.err.println(); } // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructs a new {@link ClassWriter} object. * * @param flags option flags that can be used to modify the default behavior * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. */ public ClassWriter(final int flags) { index = 1; pool = new ByteVector(); items = new Item[256]; threshold = (int) (0.75d * items.length); key = new Item(); key2 = new Item(); key3 = new Item(); this.computeMaxs = (flags & COMPUTE_MAXS) != 0; this.computeFrames = (flags & COMPUTE_FRAMES) != 0; } /** * Constructs a new {@link ClassWriter} object and enables optimizations for * "mostly add" bytecode transformations. These optimizations are the * following: * *

  • The constant pool from the original class is copied as is in * the new class, which saves time. New constant pool entries will be added * at the end if necessary, but unused constant pool entries won't be * removed.
  • Methods that are not transformed are copied as * is in the new class, directly from the original class bytecode (i.e. * without emitting visit events for all the method instructions), which * saves a lot of time. Untransformed methods are detected by the * fact that the {@link ClassReader} receives {@link MethodVisitor} objects * that come from a {@link ClassWriter} (and not from a custom * {@link ClassAdapter} or any other {@link ClassVisitor} instance).
  • *
* * @param classReader the {@link ClassReader} used to read the original * class. It will be used to copy the entire constant pool from the * original class and also to copy other fragments of original * bytecode where applicable. * @param flags option flags that can be used to modify the default behavior * of this class. These option flags do not affect methods that * are copied as is in the new class. This means that the maximum * stack size nor the stack frames will be computed for these * methods. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { this(flags); classReader.copyPool(this); this.cr = classReader; } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { this.version = version; this.access = access; this.name = newClass(name); thisName = name; if (ClassReader.SIGNATURES && signature != null) { this.signature = newUTF8(signature); } this.superName = superName == null ? 0 : newClass(superName); if (interfaces != null && interfaces.length > 0) { interfaceCount = interfaces.length; this.interfaces = new int[interfaceCount]; for (int i = 0; i < interfaceCount; ++i) { this.interfaces[i] = newClass(interfaces[i]); } } } public void visitSource(final String file, final String debug) { if (file != null) { sourceFile = newUTF8(file); } if (debug != null) { sourceDebug = new ByteVector().putUTF8(debug); } } public void visitOuterClass( final String owner, final String name, final String desc) { enclosingMethodOwner = newClass(owner); if (name != null && desc != null) { enclosingMethod = newNameType(name, desc); } } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(newUTF8(desc)).putShort(0); AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); if (visible) { aw.next = anns; anns = aw; } else { aw.next = ianns; ianns = aw; } return aw; } public void visitAttribute(final Attribute attr) { attr.next = attrs; attrs = attr; } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { if (innerClasses == null) { innerClasses = new ByteVector(); } ++innerClassesCount; innerClasses.putShort(name == null ? 0 : newClass(name)); innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); innerClasses.putShort(access); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { return new FieldWriter(this, access, name, desc, signature, value); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodWriter(this, access, name, desc, signature, exceptions, computeMaxs, computeFrames); } 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() { if (index > Short.MAX_VALUE) { throw new RuntimeException("Class file too large!"); } // computes the real size of the bytecode of this class int size = 24 + 2 * interfaceCount; int nbFields = 0; FieldWriter fb = firstField; while (fb != null) { ++nbFields; size += fb.getSize(); fb = fb.next; } int nbMethods = 0; MethodWriter mb = firstMethod; while (mb != null) { ++nbMethods; size += mb.getSize(); mb = mb.next; } int attributeCount = 0; if (ClassReader.SIGNATURES && signature != 0) { ++attributeCount; size += 8; newUTF8("Signature"); } if (sourceFile != 0) { ++attributeCount; size += 8; newUTF8("SourceFile"); } if (sourceDebug != null) { ++attributeCount; size += sourceDebug.length + 4; newUTF8("SourceDebugExtension"); } if (enclosingMethodOwner != 0) { ++attributeCount; size += 10; newUTF8("EnclosingMethod"); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; size += 6; newUTF8("Deprecated"); } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) { ++attributeCount; size += 6; newUTF8("Synthetic"); } if (innerClasses != null) { ++attributeCount; size += 8 + innerClasses.length; newUTF8("InnerClasses"); } if (ClassReader.ANNOTATIONS && anns != null) { ++attributeCount; size += 8 + anns.getSize(); newUTF8("RuntimeVisibleAnnotations"); } if (ClassReader.ANNOTATIONS && ianns != null) { ++attributeCount; size += 8 + ianns.getSize(); newUTF8("RuntimeInvisibleAnnotations"); } if (attrs != null) { attributeCount += attrs.getCount(); size += attrs.getSize(this, null, 0, -1, -1); } size += pool.length; // allocates a byte vector of this size, in order to avoid unnecessary // arraycopy operations in the ByteVector.enlarge() method ByteVector out = new ByteVector(size); out.putInt(0xCAFEBABE).putInt(version); out.putShort(index).putByteArray(pool.data, 0, pool.length); int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); out.putShort(access & ~mask).putShort(name).putShort(superName); out.putShort(interfaceCount); for (int i = 0; i < interfaceCount; ++i) { out.putShort(interfaces[i]); } out.putShort(nbFields); fb = firstField; while (fb != null) { fb.put(out); fb = fb.next; } out.putShort(nbMethods); mb = firstMethod; while (mb != null) { mb.put(out); mb = mb.next; } out.putShort(attributeCount); if (ClassReader.SIGNATURES && signature != 0) { out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); } if (sourceFile != 0) { out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); } if (sourceDebug != null) { int len = sourceDebug.length - 2; out.putShort(newUTF8("SourceDebugExtension")).putInt(len); out.putByteArray(sourceDebug.data, 2, len); } if (enclosingMethodOwner != 0) { out.putShort(newUTF8("EnclosingMethod")).putInt(4); out.putShort(enclosingMethodOwner).putShort(enclosingMethod); } if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(newUTF8("Deprecated")).putInt(0); } if ((access & Opcodes.ACC_SYNTHETIC) != 0 && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) { out.putShort(newUTF8("Synthetic")).putInt(0); } if (innerClasses != null) { out.putShort(newUTF8("InnerClasses")); out.putInt(innerClasses.length + 2).putShort(innerClassesCount); out.putByteArray(innerClasses.data, 0, innerClasses.length); } if (ClassReader.ANNOTATIONS && anns != null) { out.putShort(newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } if (ClassReader.ANNOTATIONS && ianns != null) { out.putShort(newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } if (attrs != null) { attrs.put(this, null, 0, -1, -1, out); } if (invalidFrames) { ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES); return cw.toByteArray(); } return out.data; } // ------------------------------------------------------------------------ // Utility methods: constant pool management // ------------------------------------------------------------------------ /** * Adds a number or string constant to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * * @param cst the value of the constant to be added to the constant pool. * This parameter must be an {@link Integer}, a {@link Float}, a * {@link Long}, a {@link Double}, a {@link String} or a * {@link Type}. * @return a new or already existing constant item with the given value. */ Item newConstItem(final Object cst) { if (cst instanceof Integer) { int val = ((Integer) cst).intValue(); return newInteger(val); } else if (cst instanceof Byte) { int val = ((Byte) cst).intValue(); return newInteger(val); } else if (cst instanceof Character) { int val = ((Character) cst).charValue(); return newInteger(val); } else if (cst instanceof Short) { int val = ((Short) cst).intValue(); return newInteger(val); } else if (cst instanceof Boolean) { int val = ((Boolean) cst).booleanValue() ? 1 : 0; return newInteger(val); } else if (cst instanceof Float) { float val = ((Float) cst).floatValue(); return newFloat(val); } else if (cst instanceof Long) { long val = ((Long) cst).longValue(); return newLong(val); } else if (cst instanceof Double) { double val = ((Double) cst).doubleValue(); return newDouble(val); } else if (cst instanceof String) { return newString((String) cst); } else if (cst instanceof Type) { Type t = (Type) cst; return newClassItem(t.getSort() == Type.OBJECT ? t.getInternalName() : t.getDescriptor()); } else { throw new IllegalArgumentException("value " + cst); } } /** * Adds a number or string constant to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param cst the value of the constant to be added to the constant pool. * This parameter must be an {@link Integer}, a {@link Float}, a * {@link Long}, a {@link Double} or a {@link String}. * @return the index of a new or already existing constant item with the * given value. */ public int newConst(final Object cst) { return newConstItem(cst).index; } /** * Adds an UTF8 string to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. This * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters. * * @param value the String value. * @return the index of a new or already existing UTF8 item. */ public int newUTF8(final String value) { key.set(UTF8, value, null, null); Item result = get(key); if (result == null) { pool.putByte(UTF8).putUTF8(value); result = new Item(index++, key); put(result); } return result.index; } /** * Adds a class reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param value the internal name of the class. * @return a new or already existing class reference item. */ Item newClassItem(final String value) { key2.set(CLASS, value, null, null); Item result = get(key2); if (result == null) { pool.put12(CLASS, newUTF8(value)); result = new Item(index++, key2); put(result); } return result; } /** * Adds a class reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param value the internal name of the class. * @return the index of a new or already existing class reference item. */ public int newClass(final String value) { return newClassItem(value).index; } /** * Adds a 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 newFieldItem(final String owner, final String name, final String desc) { key3.set(FIELD, owner, name, desc); Item result = get(key3); if (result == null) { put122(FIELD, newClass(owner), newNameType(name, desc)); result = new Item(index++, key3); put(result); } return result; } /** * Adds a field reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param owner the internal name of the field's owner class. * @param name the field's name. * @param desc the field's descriptor. * @return the index of a new or already existing field reference item. */ public int newField(final String owner, final String name, final String desc) { return newFieldItem(owner, name, desc).index; } /** * Adds a method reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * * @param owner the internal name of the method's owner class. * @param name the method's name. * @param desc the method's descriptor. * @param itf true if owner is an interface. * @return a new or already existing method reference item. */ Item newMethodItem( final String owner, final String name, final String desc, final boolean itf) { int type = itf ? IMETH : METH; key3.set(type, owner, name, desc); Item result = get(key3); if (result == null) { put122(type, newClass(owner), newNameType(name, desc)); result = new Item(index++, key3); put(result); } return result; } /** * Adds a method reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param owner the internal name of the method's owner class. * @param name the method's name. * @param desc the method's descriptor. * @param itf true if owner is an interface. * @return the index of a new or already existing method reference item. */ public int newMethod( final String owner, final String name, final String desc, final boolean itf) { return newMethodItem(owner, name, desc, itf).index; } /** * Adds an integer to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param value the int value. * @return a new or already existing int item. */ Item newInteger(final int value) { key.set(value); Item result = get(key); if (result == null) { pool.putByte(INT).putInt(value); result = new Item(index++, key); put(result); } return result; } /** * Adds a float to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the float value. * @return a new or already existing float item. */ Item newFloat(final float value) { key.set(value); Item result = get(key); if (result == null) { pool.putByte(FLOAT).putInt(key.intVal); result = new Item(index++, key); put(result); } return result; } /** * Adds a long to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the long value. * @return a new or already existing long item. */ Item newLong(final long value) { key.set(value); Item result = get(key); if (result == null) { pool.putByte(LONG).putLong(value); result = new Item(index, key); index += 2; put(result); } return result; } /** * Adds a double to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the double value. * @return a new or already existing double item. */ Item newDouble(final double value) { key.set(value); Item result = get(key); if (result == null) { pool.putByte(DOUBLE).putLong(key.longVal); result = new Item(index, key); index += 2; put(result); } return result; } /** * Adds a string to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the String value. * @return a new or already existing string item. */ private Item newString(final String value) { key2.set(STR, value, null, null); Item result = get(key2); if (result == null) { pool.put12(STR, newUTF8(value)); result = new Item(index++, key2); put(result); } return result; } /** * Adds a name and type to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. This * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters. * * @param name a name. * @param desc a type descriptor. * @return the index of a new or already existing name and type item. */ public int newNameType(final String name, final String desc) { return newNameTypeItem(name, desc).index; } /** * 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. */ Item newNameTypeItem(final String name, final String desc) { key2.set(NAME_TYPE, name, desc, null); Item result = get(key2); if (result == null) { put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); result = new Item(index++, key2); put(result); } return result; } /** * Adds the given internal name to {@link #typeTable} and returns its index. * Does nothing if the type table already contains this internal name. * * @param type the internal name to be added to the type table. * @return the index of this internal name in the type table. */ int addType(final String type) { key.set(TYPE_NORMAL, type, null, null); Item result = get(key); if (result == null) { result = addType(key); } return result.index; } /** * Adds the given "uninitialized" type to {@link #typeTable} and returns its * index. This method is used for UNINITIALIZED types, made of an internal * name and a bytecode offset. * * @param type the internal name to be added to the type table. * @param offset the bytecode offset of the NEW instruction that created * this UNINITIALIZED type value. * @return the index of this internal name in the type table. */ int addUninitializedType(final String type, final int offset) { key.type = TYPE_UNINIT; key.intVal = offset; key.strVal1 = type; key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); Item result = get(key); if (result == null) { result = addType(key); } return result.index; } /** * Adds the given Item to {@link #typeTable}. * * @param item the value to be added to the type table. * @return the added Item, which a new Item instance with the same value as * the given Item. */ private Item addType(final Item item) { ++typeCount; Item result = new Item(typeCount, key); put(result); if (typeTable == null) { typeTable = new Item[16]; } if (typeCount == typeTable.length) { Item[] newTable = new Item[2 * typeTable.length]; System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); typeTable = newTable; } typeTable[typeCount] = result; return result; } /** * Returns the index of the common super type of the two given types. This * method calls {@link #getCommonSuperClass} and caches the result in the * {@link #items} hash table to speedup future calls with the same * parameters. * * @param type1 index of an internal name in {@link #typeTable}. * @param type2 index of an internal name in {@link #typeTable}. * @return the index of the common super type of the two given types. */ int getMergedType(final int type1, final int type2) { key2.type = TYPE_MERGED; key2.longVal = type1 | (((long) type2) << 32); key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); Item result = get(key2); if (result == null) { String t = typeTable[type1].strVal1; String u = typeTable[type2].strVal1; key2.intVal = addType(getCommonSuperClass(t, u)); result = new Item((short) 0, key2); put(result); } return result.intVal; } /** * Returns the common super type of the two given types. The default * implementation of this method loads the two given classes and uses * the java.lang.Class methods to find the common super class. It can be * overridden to compute this common super type in other ways, in particular * without actually loading any class, or to take into account the class * that is currently being generated by this ClassWriter, which can of * course not be loaded since it is under construction. * * @param type1 the internal name of a class. * @param type2 the internal name of another class. * @return the internal name of the common super class of the two given * classes. */ protected String getCommonSuperClass(final String type1, final String type2) { Class c, d; try { c = Class.forName(type1.replace('/', '.')); d = Class.forName(type2.replace('/', '.')); } catch (Exception e) { throw new RuntimeException(e.toString()); } if (c.isAssignableFrom(d)) { return type1; } if (d.isAssignableFrom(c)) { return type2; } if (c.isInterface() || d.isInterface()) { return "java/lang/Object"; } else { do { c = c.getSuperclass(); } while (!c.isAssignableFrom(d)); return c.getName().replace('.', '/'); } } /** * 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 i = items[key.hashCode % items.length]; while (i != null && (i.type != key.type || !key.isEqualTo(i))) { i = i.next; } return i; } /** * 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 + typeCount > threshold) { int ll = items.length; int nl = ll * 2 + 1; Item[] newItems = new Item[nl]; for (int l = ll - 1; l >= 0; --l) { Item j = items[l]; while (j != null) { int index = j.hashCode % newItems.length; Item k = j.next; j.next = newItems[index]; newItems[index] = j; j = k; } } items = newItems; threshold = (int) (nl * 0.75); } int index = i.hashCode % items.length; i.next = items[index]; items[index] = i; } /** * Puts one byte and two shorts into the constant pool. * * @param b a byte. * @param s1 a short. * @param s2 another short. */ private void put122(final int b, final int s1, final int s2) { pool.put12(b, s1).putShort(s2); } } asm-3.3.2/src/org/objectweb/asm/attrs/0000755000175000017500000000000011633370220017471 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/attrs/package.html0000644000175000017500000000464710177716604022001 0ustar twernertwerner Provides an implementation for optional class, field and method attributes.

By default ASM strips optional attributes, in order to keep them in the bytecode that is being readed you should pass an array of required attribute instances to {@link org.objectweb.asm.ClassReader#accept(org.objectweb.asm.ClassVisitor, org.objectweb.asm.Attribute[], boolean) ClassReader.accept()} method. In order to add custom attributes to the manually constructed bytecode concrete subclasses of the {@link org.objectweb.asm.Attribute Attribute} can be passed to the visitAttribute methods of the {@link org.objectweb.asm.ClassVisitor ClassVisitor}, {@link org.objectweb.asm.FieldVisitor FieldVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces. @since ASM 1.4.1 asm-3.3.2/src/org/objectweb/asm/signature/0000755000175000017500000000000011633370220020335 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/signature/SignatureVisitor.java0000644000175000017500000001404110635277351024535 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.signature; /** * A visitor to visit a generic signature. The methods of this interface must be * called in one of the three following orders (the last one is the only valid * order for a {@link SignatureVisitor} that is returned by a method of this * interface):

  • ClassSignature = ( * visitFormalTypeParameter * visitClassBound? * visitInterfaceBound* )* ( visitSuperClass * visitInterface* )
  • *
  • MethodSignature = ( visitFormalTypeParameter * visitClassBound? * visitInterfaceBound* )* ( visitParameterType* * visitReturnType * visitExceptionType* )
  • TypeSignature = * visitBaseType | visitTypeVariable | * visitArrayType | ( * visitClassType visitTypeArgument* ( * visitInnerClassType visitTypeArgument* )* * visitEnd ) )
* * @author Thomas Hallgren * @author Eric Bruneton */ public interface SignatureVisitor { /** * Wildcard for an "extends" type argument. */ char EXTENDS = '+'; /** * Wildcard for a "super" type argument. */ char SUPER = '-'; /** * Wildcard for a normal type argument. */ char INSTANCEOF = '='; /** * Visits a formal type parameter. * * @param name the name of the formal parameter. */ void visitFormalTypeParameter(String name); /** * Visits the class bound of the last visited formal type parameter. * * @return a non null visitor to visit the signature of the class bound. */ SignatureVisitor visitClassBound(); /** * Visits an interface bound of the last visited formal type parameter. * * @return a non null visitor to visit the signature of the interface bound. */ SignatureVisitor visitInterfaceBound(); /** * Visits the type of the super class. * * @return a non null visitor to visit the signature of the super class * type. */ SignatureVisitor visitSuperclass(); /** * Visits the type of an interface implemented by the class. * * @return a non null visitor to visit the signature of the interface type. */ SignatureVisitor visitInterface(); /** * Visits the type of a method parameter. * * @return a non null visitor to visit the signature of the parameter type. */ SignatureVisitor visitParameterType(); /** * Visits the return type of the method. * * @return a non null visitor to visit the signature of the return type. */ SignatureVisitor visitReturnType(); /** * Visits the type of a method exception. * * @return a non null visitor to visit the signature of the exception type. */ SignatureVisitor visitExceptionType(); /** * Visits a signature corresponding to a primitive type. * * @param descriptor the descriptor of the primitive type, or 'V' for * void. */ void visitBaseType(char descriptor); /** * Visits a signature corresponding to a type variable. * * @param name the name of the type variable. */ void visitTypeVariable(String name); /** * Visits a signature corresponding to an array type. * * @return a non null visitor to visit the signature of the array element * type. */ SignatureVisitor visitArrayType(); /** * Starts the visit of a signature corresponding to a class or interface * type. * * @param name the internal name of the class or interface. */ void visitClassType(String name); /** * Visits an inner class. * * @param name the local name of the inner class in its enclosing class. */ void visitInnerClassType(String name); /** * Visits an unbounded type argument of the last visited class or inner * class type. */ void visitTypeArgument(); /** * Visits a type argument of the last visited class or inner class type. * * @param wildcard '+', '-' or '='. * @return a non null visitor to visit the signature of the type argument. */ SignatureVisitor visitTypeArgument(char wildcard); /** * Ends the visit of a signature corresponding to a class or interface type. */ void visitEnd(); } asm-3.3.2/src/org/objectweb/asm/signature/package.html0000644000175000017500000000332010177716604022630 0ustar twernertwerner Provides support for type signatures. @since ASM 2.0 asm-3.3.2/src/org/objectweb/asm/signature/SignatureWriter.java0000644000175000017500000001353010635277351024354 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.signature; /** * A signature visitor that generates signatures in string format. * * @author Thomas Hallgren * @author Eric Bruneton */ public class SignatureWriter implements SignatureVisitor { /** * Buffer used to construct the signature. */ private final StringBuffer buf = new StringBuffer(); /** * Indicates if the signature contains formal type parameters. */ private boolean hasFormals; /** * Indicates if the signature contains method parameter types. */ private boolean hasParameters; /** * Stack used to keep track of class types that have arguments. Each element * of this stack is a boolean encoded in one bit. The top of the stack is * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = * /2. */ private int argumentStack; /** * Constructs a new {@link SignatureWriter} object. */ public SignatureWriter() { } // ------------------------------------------------------------------------ // Implementation of the SignatureVisitor interface // ------------------------------------------------------------------------ public void visitFormalTypeParameter(final String name) { if (!hasFormals) { hasFormals = true; buf.append('<'); } buf.append(name); buf.append(':'); } public SignatureVisitor visitClassBound() { return this; } public SignatureVisitor visitInterfaceBound() { buf.append(':'); return this; } public SignatureVisitor visitSuperclass() { endFormals(); return this; } public SignatureVisitor visitInterface() { return this; } public SignatureVisitor visitParameterType() { endFormals(); if (!hasParameters) { hasParameters = true; buf.append('('); } return this; } public SignatureVisitor visitReturnType() { endFormals(); if (!hasParameters) { buf.append('('); } buf.append(')'); return this; } public SignatureVisitor visitExceptionType() { buf.append('^'); return this; } public void visitBaseType(final char descriptor) { buf.append(descriptor); } public void visitTypeVariable(final String name) { buf.append('T'); buf.append(name); buf.append(';'); } public SignatureVisitor visitArrayType() { buf.append('['); return this; } public void visitClassType(final String name) { buf.append('L'); buf.append(name); argumentStack *= 2; } public void visitInnerClassType(final String name) { endArguments(); buf.append('.'); buf.append(name); argumentStack *= 2; } public void visitTypeArgument() { if (argumentStack % 2 == 0) { ++argumentStack; buf.append('<'); } buf.append('*'); } public SignatureVisitor visitTypeArgument(final char wildcard) { if (argumentStack % 2 == 0) { ++argumentStack; buf.append('<'); } if (wildcard != '=') { buf.append(wildcard); } return this; } public void visitEnd() { endArguments(); buf.append(';'); } /** * Returns the signature that was built by this signature writer. * * @return the signature that was built by this signature writer. */ public String toString() { return buf.toString(); } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Ends the formal type parameters section of the signature. */ private void endFormals() { if (hasFormals) { hasFormals = false; buf.append('>'); } } /** * Ends the type arguments of a class or inner class type. */ private void endArguments() { if (argumentStack % 2 != 0) { buf.append('>'); } argumentStack /= 2; } }asm-3.3.2/src/org/objectweb/asm/signature/SignatureReader.java0000644000175000017500000002145210701747173024302 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.signature; /** * A type signature parser to make a signature visitor visit an existing * signature. * * @author Thomas Hallgren * @author Eric Bruneton */ public class SignatureReader { /** * The signature to be read. */ private final String signature; /** * Constructs a {@link SignatureReader} for the given signature. * * @param signature A ClassSignature, MethodTypeSignature, * or FieldTypeSignature. */ public SignatureReader(final String signature) { this.signature = signature; } /** * Makes the given visitor visit the signature of this * {@link SignatureReader}. This signature is the one specified in the * constructor (see {@link #SignatureReader(String) SignatureReader}). This * method is intended to be called on a {@link SignatureReader} that was * created using a ClassSignature (such as the * signature parameter of the * {@link org.objectweb.asm.ClassVisitor#visit ClassVisitor.visit} method) * or a MethodTypeSignature (such as the signature * parameter of the * {@link org.objectweb.asm.ClassVisitor#visitMethod ClassVisitor.visitMethod} * method). * * @param v the visitor that must visit this signature. */ public void accept(final SignatureVisitor v) { String signature = this.signature; int len = signature.length(); int pos; char c; if (signature.charAt(0) == '<') { pos = 2; do { int end = signature.indexOf(':', pos); v.visitFormalTypeParameter(signature.substring(pos - 1, end)); pos = end + 1; c = signature.charAt(pos); if (c == 'L' || c == '[' || c == 'T') { pos = parseType(signature, pos, v.visitClassBound()); } while ((c = signature.charAt(pos++)) == ':') { pos = parseType(signature, pos, v.visitInterfaceBound()); } } while (c != '>'); } else { pos = 0; } if (signature.charAt(pos) == '(') { pos++; while (signature.charAt(pos) != ')') { pos = parseType(signature, pos, v.visitParameterType()); } pos = parseType(signature, pos + 1, v.visitReturnType()); while (pos < len) { pos = parseType(signature, pos + 1, v.visitExceptionType()); } } else { pos = parseType(signature, pos, v.visitSuperclass()); while (pos < len) { pos = parseType(signature, pos, v.visitInterface()); } } } /** * Makes the given visitor visit the signature of this * {@link SignatureReader}. This signature is the one specified in the * constructor (see {@link #SignatureReader(String) SignatureReader}). This * method is intended to be called on a {@link SignatureReader} that was * created using a FieldTypeSignature, such as the * signature parameter of the * {@link org.objectweb.asm.ClassVisitor#visitField * ClassVisitor.visitField} or {@link * org.objectweb.asm.MethodVisitor#visitLocalVariable * MethodVisitor.visitLocalVariable} methods. * * @param v the visitor that must visit this signature. */ public void acceptType(final SignatureVisitor v) { parseType(this.signature, 0, v); } /** * Parses a field type signature and makes the given visitor visit it. * * @param signature a string containing the signature that must be parsed. * @param pos index of the first character of the signature to parsed. * @param v the visitor that must visit this signature. * @return the index of the first character after the parsed signature. */ private static int parseType( final String signature, int pos, final SignatureVisitor v) { char c; int start, end; boolean visited, inner; String name; switch (c = signature.charAt(pos++)) { case 'Z': case 'C': case 'B': case 'S': case 'I': case 'F': case 'J': case 'D': case 'V': v.visitBaseType(c); return pos; case '[': return parseType(signature, pos, v.visitArrayType()); case 'T': end = signature.indexOf(';', pos); v.visitTypeVariable(signature.substring(pos, end)); return end + 1; default: // case 'L': start = pos; visited = false; inner = false; for (;;) { switch (c = signature.charAt(pos++)) { case '.': case ';': if (!visited) { name = signature.substring(start, pos - 1); if (inner) { v.visitInnerClassType(name); } else { v.visitClassType(name); } } if (c == ';') { v.visitEnd(); return pos; } start = pos; visited = false; inner = true; break; case '<': name = signature.substring(start, pos - 1); if (inner) { v.visitInnerClassType(name); } else { v.visitClassType(name); } visited = true; top: for (;;) { switch (c = signature.charAt(pos)) { case '>': break top; case '*': ++pos; v.visitTypeArgument(); break; case '+': case '-': pos = parseType(signature, pos + 1, v.visitTypeArgument(c)); break; default: pos = parseType(signature, pos, v.visitTypeArgument('=')); break; } } } } } } } asm-3.3.2/src/org/objectweb/asm/AnnotationWriter.java0000644000175000017500000002534010710602357022516 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; /** * An {@link AnnotationVisitor} that generates annotations in bytecode form. * * @author Eric Bruneton * @author Eugene Kuleshov */ final class AnnotationWriter implements AnnotationVisitor { /** * The class writer to which this annotation must be added. */ private final ClassWriter cw; /** * The number of values in this annotation. */ private int size; /** * true if values are named, false otherwise. Annotation * writers used for annotation default and annotation arrays use unnamed * values. */ private final boolean named; /** * The annotation values in bytecode form. This byte vector only contains * the values themselves, i.e. the number of values must be stored as a * unsigned short just before these bytes. */ private final ByteVector bv; /** * The byte vector to be used to store the number of values of this * annotation. See {@link #bv}. */ private final ByteVector parent; /** * Where the number of values of this annotation must be stored in * {@link #parent}. */ private final int offset; /** * Next annotation writer. This field is used to store annotation lists. */ AnnotationWriter next; /** * Previous annotation writer. This field is used to store annotation lists. */ AnnotationWriter prev; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructs a new {@link AnnotationWriter}. * * @param cw the class writer to which this annotation must be added. * @param named true if values are named, false otherwise. * @param bv where the annotation values must be stored. * @param parent where the number of annotation values must be stored. * @param offset where in parent the number of annotation values must * be stored. */ AnnotationWriter( final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) { this.cw = cw; this.named = named; this.bv = bv; this.parent = parent; this.offset = offset; } // ------------------------------------------------------------------------ // Implementation of the AnnotationVisitor interface // ------------------------------------------------------------------------ public void visit(final String name, final Object value) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); } if (value instanceof String) { bv.put12('s', cw.newUTF8((String) value)); } else if (value instanceof Byte) { bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); } else if (value instanceof Boolean) { int v = ((Boolean) value).booleanValue() ? 1 : 0; bv.put12('Z', cw.newInteger(v).index); } else if (value instanceof Character) { bv.put12('C', cw.newInteger(((Character) value).charValue()).index); } else if (value instanceof Short) { bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); } else if (value instanceof Type) { bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); } else if (value instanceof byte[]) { byte[] v = (byte[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('B', cw.newInteger(v[i]).index); } } else if (value instanceof boolean[]) { boolean[] v = (boolean[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); } } else if (value instanceof short[]) { short[] v = (short[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('S', cw.newInteger(v[i]).index); } } else if (value instanceof char[]) { char[] v = (char[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('C', cw.newInteger(v[i]).index); } } else if (value instanceof int[]) { int[] v = (int[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('I', cw.newInteger(v[i]).index); } } else if (value instanceof long[]) { long[] v = (long[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('J', cw.newLong(v[i]).index); } } else if (value instanceof float[]) { float[] v = (float[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('F', cw.newFloat(v[i]).index); } } else if (value instanceof double[]) { double[] v = (double[]) value; bv.put12('[', v.length); for (int i = 0; i < v.length; i++) { bv.put12('D', cw.newDouble(v[i]).index); } } else { Item i = cw.newConstItem(value); bv.put12(".s.IFJDCS".charAt(i.type), i.index); } } public void visitEnum( final String name, final String desc, final String value) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); } bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); } // write tag and type, and reserve space for values count bv.put12('@', cw.newUTF8(desc)).putShort(0); return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); } public AnnotationVisitor visitArray(final String name) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); } // write tag, and reserve space for array size bv.put12('[', 0); return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); } public void visitEnd() { if (parent != null) { byte[] data = parent.data; data[offset] = (byte) (size >>> 8); data[offset + 1] = (byte) size; } } // ------------------------------------------------------------------------ // Utility methods // ------------------------------------------------------------------------ /** * Returns the size of this annotation writer list. * * @return the size of this annotation writer list. */ int getSize() { int size = 0; AnnotationWriter aw = this; while (aw != null) { size += aw.bv.length; aw = aw.next; } return size; } /** * Puts the annotations of this annotation writer list into the given byte * vector. * * @param out where the annotations must be put. */ void put(final ByteVector out) { int n = 0; int size = 2; AnnotationWriter aw = this; AnnotationWriter last = null; while (aw != null) { ++n; size += aw.bv.length; aw.visitEnd(); // in case user forgot to call visitEnd aw.prev = last; last = aw; aw = aw.next; } out.putInt(size); out.putShort(n); aw = last; while (aw != null) { out.putByteArray(aw.bv.data, 0, aw.bv.length); aw = aw.prev; } } /** * Puts the given annotation lists into the given byte vector. * * @param panns an array of annotation writer lists. * @param off index of the first annotation to be written. * @param out where the annotations must be put. */ static void put( final AnnotationWriter[] panns, final int off, final ByteVector out) { int size = 1 + 2 * (panns.length - off); for (int i = off; i < panns.length; ++i) { size += panns[i] == null ? 0 : panns[i].getSize(); } out.putInt(size).putByte(panns.length - off); for (int i = off; i < panns.length; ++i) { AnnotationWriter aw = panns[i]; AnnotationWriter last = null; int n = 0; while (aw != null) { ++n; aw.visitEnd(); // in case user forgot to call visitEnd aw.prev = last; last = aw; aw = aw.next; } out.putShort(n); aw = last; while (aw != null) { out.putByteArray(aw.bv.data, 0, aw.bv.length); aw = aw.prev; } } } } asm-3.3.2/src/org/objectweb/asm/ClassReader.java0000644000175000017500000024711011525262537021407 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.InputStream; import java.io.IOException; /** * A Java class parser to make a {@link ClassVisitor} visit an existing class. * This class parses a byte array conforming to the Java class file format and * calls the appropriate visit methods of a given class visitor for each field, * method and bytecode instruction encountered. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class ClassReader { /** * True to enable signatures support. */ static final boolean SIGNATURES = true; /** * True to enable annotations support. */ static final boolean ANNOTATIONS = true; /** * True to enable stack map frames support. */ static final boolean FRAMES = true; /** * True to enable bytecode writing support. */ static final boolean WRITER = true; /** * True to enable JSR_W and GOTO_W support. */ static final boolean RESIZE = true; /** * Flag to skip method code. If this class is set CODE * attribute won't be visited. This can be used, for example, to retrieve * annotations for methods and method parameters. */ public static final int SKIP_CODE = 1; /** * Flag to skip the debug information in the class. If this flag is set the * debug information of the class is not visited, i.e. the * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be * called. */ public static final int SKIP_DEBUG = 2; /** * Flag to skip the stack map frames in the class. If this flag is set the * stack map frames of the class is not visited, i.e. the * {@link MethodVisitor#visitFrame visitFrame} method will not be called. * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is * used: it avoids visiting frames that will be ignored and recomputed from * scratch in the class writer. */ public static final int SKIP_FRAMES = 4; /** * Flag to expand the stack map frames. By default stack map frames are * visited in their original format (i.e. "expanded" for classes whose * version is less than V1_6, and "compressed" for the other classes). If * this flag is set, stack map frames are always visited in expanded format * (this option adds a decompression/recompression step in ClassReader and * ClassWriter which degrades performances quite a lot). */ public static final int EXPAND_FRAMES = 8; /** * The class to be parsed. The content of this array must not be * modified. This field is intended for {@link Attribute} sub classes, and * is normally not needed by class generators or adapters. */ public final byte[] b; /** * The start index of each constant pool item in {@link #b b}, plus one. * The one byte offset skips the constant pool item tag that indicates its * type. */ private final int[] items; /** * The String objects corresponding to the CONSTANT_Utf8 items. This cache * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, * which GREATLY improves performances (by a factor 2 to 3). This caching * strategy could be extended to all constant pool items, but its benefit * would not be so great for these items (because they are much less * expensive to parse than CONSTANT_Utf8 items). */ private final String[] strings; /** * Maximum length of the strings contained in the constant pool of the * class. */ private final int maxStringLength; /** * Start index of the class header information (access, name...) in * {@link #b b}. */ public final int header; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Constructs a new {@link ClassReader} object. * * @param b the bytecode of the class to be read. */ public ClassReader(final byte[] b) { this(b, 0, b.length); } /** * Constructs a new {@link ClassReader} object. * * @param b the bytecode of the class to be read. * @param off the start offset of the class data. * @param len the length of the class data. */ public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // parses the constant pool items = new int[readUnsignedShort(off + 8)]; int n = items.length; strings = new String[n]; int max = 0; int index = off + 10; for (int i = 1; i < n; ++i) { items[i] = index + 1; int size; switch (b[index]) { case ClassWriter.FIELD: case ClassWriter.METH: case ClassWriter.IMETH: case ClassWriter.INT: case ClassWriter.FLOAT: case ClassWriter.NAME_TYPE: size = 5; break; case ClassWriter.LONG: case ClassWriter.DOUBLE: size = 9; ++i; break; case ClassWriter.UTF8: size = 3 + readUnsignedShort(index + 1); if (size > max) { max = size; } break; // case ClassWriter.CLASS: // case ClassWriter.STR: default: size = 3; break; } index += size; } maxStringLength = max; // the class header information starts just after the constant pool header = index; } /** * Returns the class's access flags (see {@link Opcodes}). This value may * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 * and those flags are represented by attributes. * * @return the class access flags * * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public int getAccess() { return readUnsignedShort(header); } /** * Returns the internal name of the class (see * {@link Type#getInternalName() getInternalName}). * * @return the internal class name * * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public String getClassName() { return readClass(header + 2, new char[maxStringLength]); } /** * Returns the internal of name of the super class (see * {@link Type#getInternalName() getInternalName}). For interfaces, the * super class is {@link Object}. * * @return the internal name of super class, or null for * {@link Object} class. * * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public String getSuperName() { int n = items[readUnsignedShort(header + 4)]; return n == 0 ? null : readUTF8(n, new char[maxStringLength]); } /** * Returns the internal names of the class's interfaces (see * {@link Type#getInternalName() getInternalName}). * * @return the array of internal names for all implemented interfaces or * null. * * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public String[] getInterfaces() { int index = header + 6; int n = readUnsignedShort(index); String[] interfaces = new String[n]; if (n > 0) { char[] buf = new char[maxStringLength]; for (int i = 0; i < n; ++i) { index += 2; interfaces[i] = readClass(index, buf); } } return interfaces; } /** * Copies the constant pool data into the given {@link ClassWriter}. Should * be called before the {@link #accept(ClassVisitor,int)} method. * * @param classWriter the {@link ClassWriter} to copy constant pool into. */ void copyPool(final ClassWriter classWriter) { char[] buf = new char[maxStringLength]; int ll = items.length; Item[] items2 = new Item[ll]; for (int i = 1; i < ll; i++) { int index = items[i]; int tag = b[index - 1]; Item item = new Item(i); int nameType; switch (tag) { case ClassWriter.FIELD: case ClassWriter.METH: case ClassWriter.IMETH: nameType = items[readUnsignedShort(index + 2)]; item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); break; case ClassWriter.INT: item.set(readInt(index)); break; case ClassWriter.FLOAT: item.set(Float.intBitsToFloat(readInt(index))); break; case ClassWriter.NAME_TYPE: item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null); break; case ClassWriter.LONG: item.set(readLong(index)); ++i; break; case ClassWriter.DOUBLE: item.set(Double.longBitsToDouble(readLong(index))); ++i; break; case ClassWriter.UTF8: { String s = strings[i]; if (s == null) { index = items[i]; s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf); } item.set(tag, s, null, null); } break; // case ClassWriter.STR: // case ClassWriter.CLASS: default: item.set(tag, readUTF8(index, buf), null, null); break; } int index2 = item.hashCode % items2.length; item.next = items2[index2]; items2[index2] = item; } int off = items[1] - 1; classWriter.pool.putByteArray(b, off, header - off); classWriter.items = items2; classWriter.threshold = (int) (0.75d * ll); classWriter.index = ll; } /** * Constructs a new {@link ClassReader} object. * * @param is an input stream from which to read the class. * @throws IOException if a problem occurs during reading. */ public ClassReader(final InputStream is) throws IOException { this(readClass(is)); } /** * Constructs a new {@link ClassReader} object. * * @param name the binary qualified name of the class to be read. * @throws IOException if an exception occurs during reading. */ public ClassReader(final String name) throws IOException { this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class")); } /** * Reads the bytecode of a class. * * @param is an input stream from which to read the class. * @return the bytecode read from the given input stream. * @throws IOException if a problem occurs during reading. */ private static byte[] readClass(final InputStream is) throws IOException { if (is == null) { throw new IOException("Class not found"); } byte[] b = new byte[is.available()]; int len = 0; while (true) { int n = is.read(b, len, b.length - len); if (n == -1) { if (len < b.length) { byte[] c = new byte[len]; System.arraycopy(b, 0, c, 0, len); b = c; } return b; } len += n; if (len == b.length) { int last = is.read(); if (last < 0) { return b; } byte[] c = new byte[b.length + 1000]; System.arraycopy(b, 0, c, 0, len); c[len++] = (byte) last; b = c; } } } // ------------------------------------------------------------------------ // Public methods // ------------------------------------------------------------------------ /** * Makes the given visitor visit the Java class of this {@link ClassReader}. * This class is the one specified in the constructor (see * {@link #ClassReader(byte[]) ClassReader}). * * @param classVisitor the visitor that must visit this class. * @param flags option flags that can be used to modify the default behavior * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. */ public void accept(final ClassVisitor classVisitor, final int flags) { accept(classVisitor, new Attribute[0], flags); } /** * Makes the given visitor visit the Java class of this {@link ClassReader}. * This class is the one specified in the constructor (see * {@link #ClassReader(byte[]) ClassReader}). * * @param classVisitor the visitor that must visit this class. * @param attrs prototypes of the attributes that must be parsed during the * visit of the class. Any attribute whose type is not equal to the * type of one the prototypes will not be parsed: its byte array * value will be passed unchanged to the ClassWriter. This may * corrupt it if this value contains references to the constant pool, * or has syntactic or semantic links with a class element that has * been transformed by a class adapter between the reader and the * writer. * @param flags option flags that can be used to modify the default behavior * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. */ public void accept( final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) { byte[] b = this.b; // the bytecode array char[] c = new char[maxStringLength]; // buffer used to read strings int i, j, k; // loop variables int u, v, w; // indexes in b Attribute attr; int access; String name; String desc; String attrName; String signature; int anns = 0; int ianns = 0; Attribute cattrs = null; // visits the header u = header; access = readUnsignedShort(u); name = readClass(u + 2, c); v = items[readUnsignedShort(u + 4)]; String superClassName = v == 0 ? null : readUTF8(v, c); String[] implementedItfs = new String[readUnsignedShort(u + 6)]; w = 0; u += 8; for (i = 0; i < implementedItfs.length; ++i) { implementedItfs[i] = readClass(u, c); u += 2; } boolean skipCode = (flags & SKIP_CODE) != 0; boolean skipDebug = (flags & SKIP_DEBUG) != 0; boolean unzip = (flags & EXPAND_FRAMES) != 0; // skips fields and methods v = u; i = readUnsignedShort(v); v += 2; for (; i > 0; --i) { j = readUnsignedShort(v + 6); v += 8; for (; j > 0; --j) { v += 6 + readInt(v + 2); } } i = readUnsignedShort(v); v += 2; for (; i > 0; --i) { j = readUnsignedShort(v + 6); v += 8; for (; j > 0; --j) { v += 6 + readInt(v + 2); } } // reads the class's attributes signature = null; String sourceFile = null; String sourceDebug = null; String enclosingOwner = null; String enclosingName = null; String enclosingDesc = null; i = readUnsignedShort(v); v += 2; for (; i > 0; --i) { attrName = readUTF8(v, c); // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("SourceFile".equals(attrName)) { sourceFile = readUTF8(v + 6, c); } else if ("InnerClasses".equals(attrName)) { w = v + 6; } else if ("EnclosingMethod".equals(attrName)) { enclosingOwner = readClass(v + 6, c); int item = readUnsignedShort(v + 8); if (item != 0) { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); } } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(v + 6, c); } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { anns = v + 6; } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if ("SourceDebugExtension".equals(attrName)) { int len = readInt(v + 2); sourceDebug = readUTF(v + 6, len, new char[len]); } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = v + 6; } else { attr = readAttribute(attrs, attrName, v + 6, readInt(v + 2), c, -1, null); if (attr != null) { attr.next = cattrs; cattrs = attr; } } v += 6 + readInt(v + 2); } // calls the visit method classVisitor.visit(readInt(4), access, name, signature, superClassName, implementedItfs); // calls the visitSource method if (!skipDebug && (sourceFile != null || sourceDebug != null)) { classVisitor.visitSource(sourceFile, sourceDebug); } // calls the visitOuterClass method if (enclosingOwner != null) { classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc); } // visits the class annotations if (ANNOTATIONS) { for (i = 1; i >= 0; --i) { v = i == 0 ? ianns : anns; if (v != 0) { j = readUnsignedShort(v); v += 2; for (; j > 0; --j) { v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), i != 0)); } } } } // visits the class attributes while (cattrs != null) { attr = cattrs.next; cattrs.next = null; classVisitor.visitAttribute(cattrs); cattrs = attr; } // calls the visitInnerClass method if (w != 0) { i = readUnsignedShort(w); w += 2; for (; i > 0; --i) { classVisitor.visitInnerClass(readUnsignedShort(w) == 0 ? null : readClass(w, c), readUnsignedShort(w + 2) == 0 ? null : readClass(w + 2, c), readUnsignedShort(w + 4) == 0 ? null : readUTF8(w + 4, c), readUnsignedShort(w + 6)); w += 8; } } // visits the fields i = readUnsignedShort(u); u += 2; for (; i > 0; --i) { access = readUnsignedShort(u); name = readUTF8(u + 2, c); desc = readUTF8(u + 4, c); // visits the field's attributes and looks for a ConstantValue // attribute int fieldValueItem = 0; signature = null; anns = 0; ianns = 0; cattrs = null; j = readUnsignedShort(u + 6); u += 8; for (; j > 0; --j) { attrName = readUTF8(u, c); // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("ConstantValue".equals(attrName)) { fieldValueItem = readUnsignedShort(u + 6); } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(u + 6, c); } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 6; } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 6; } else { attr = readAttribute(attrs, attrName, u + 6, readInt(u + 2), c, -1, null); if (attr != null) { attr.next = cattrs; cattrs = attr; } } u += 6 + readInt(u + 2); } // visits the field FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, fieldValueItem == 0 ? null : readConst(fieldValueItem, c)); // visits the field annotations and attributes if (fv != null) { if (ANNOTATIONS) { for (j = 1; j >= 0; --j) { v = j == 0 ? ianns : anns; if (v != 0) { k = readUnsignedShort(v); v += 2; for (; k > 0; --k) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), j != 0)); } } } } while (cattrs != null) { attr = cattrs.next; cattrs.next = null; fv.visitAttribute(cattrs); cattrs = attr; } fv.visitEnd(); } } // visits the methods i = readUnsignedShort(u); u += 2; for (; i > 0; --i) { int u0 = u + 6; access = readUnsignedShort(u); name = readUTF8(u + 2, c); desc = readUTF8(u + 4, c); signature = null; anns = 0; ianns = 0; int dann = 0; int mpanns = 0; int impanns = 0; cattrs = null; v = 0; w = 0; // looks for Code and Exceptions attributes j = readUnsignedShort(u + 6); u += 8; for (; j > 0; --j) { attrName = readUTF8(u, c); int attrSize = readInt(u + 2); u += 6; // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("Code".equals(attrName)) { if (!skipCode) { v = u; } } else if ("Exceptions".equals(attrName)) { w = u; } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(u, c); } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { anns = u; } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { dann = u; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u; } else if (ANNOTATIONS && "RuntimeVisibleParameterAnnotations".equals(attrName)) { mpanns = u; } else if (ANNOTATIONS && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { impanns = u; } else { attr = readAttribute(attrs, attrName, u, attrSize, c, -1, null); if (attr != null) { attr.next = cattrs; cattrs = attr; } } u += attrSize; } // reads declared exceptions String[] exceptions; if (w == 0) { exceptions = null; } else { exceptions = new String[readUnsignedShort(w)]; w += 2; for (j = 0; j < exceptions.length; ++j) { exceptions[j] = readClass(w, c); w += 2; } } // visits the method's code, if any MethodVisitor mv = classVisitor.visitMethod(access, name, desc, signature, exceptions); if (mv != null) { /* * if the returned MethodVisitor is in fact a MethodWriter, it * means there is no method adapter between the reader and the * writer. If, in addition, the writer's constant pool was * copied from this reader (mw.cw.cr == this), and the signature * and exceptions of the method have not been changed, then it * is possible to skip all visit events and just copy the * original code of the method to the writer (the access, name * and descriptor can have been changed, this is not important * since they are not copied as is from the reader). */ if (WRITER && mv instanceof MethodWriter) { MethodWriter mw = (MethodWriter) mv; if (mw.cw.cr == this) { if (signature == mw.signature) { boolean sameExceptions = false; if (exceptions == null) { sameExceptions = mw.exceptionCount == 0; } else { if (exceptions.length == mw.exceptionCount) { sameExceptions = true; for (j = exceptions.length - 1; j >= 0; --j) { w -= 2; if (mw.exceptions[j] != readUnsignedShort(w)) { sameExceptions = false; break; } } } } if (sameExceptions) { /* * we do not copy directly the code into * MethodWriter to save a byte array copy * operation. The real copy will be done in * ClassWriter.toByteArray(). */ mw.classReaderOffset = u0; mw.classReaderLength = u - u0; continue; } } } } if (ANNOTATIONS && dann != 0) { AnnotationVisitor dv = mv.visitAnnotationDefault(); readAnnotationValue(dann, c, null, dv); if (dv != null) { dv.visitEnd(); } } if (ANNOTATIONS) { for (j = 1; j >= 0; --j) { w = j == 0 ? ianns : anns; if (w != 0) { k = readUnsignedShort(w); w += 2; for (; k > 0; --k) { w = readAnnotationValues(w + 2, c, true, mv.visitAnnotation(readUTF8(w, c), j != 0)); } } } } if (ANNOTATIONS && mpanns != 0) { readParameterAnnotations(mpanns, desc, c, true, mv); } if (ANNOTATIONS && impanns != 0) { readParameterAnnotations(impanns, desc, c, false, mv); } while (cattrs != null) { attr = cattrs.next; cattrs.next = null; mv.visitAttribute(cattrs); cattrs = attr; } } if (mv != null && v != 0) { int maxStack = readUnsignedShort(v); int maxLocals = readUnsignedShort(v + 2); int codeLength = readInt(v + 4); v += 8; int codeStart = v; int codeEnd = v + codeLength; mv.visitCode(); // 1st phase: finds the labels int label; Label[] labels = new Label[codeLength + 2]; readLabel(codeLength + 1, labels); while (v < codeEnd) { w = v - codeStart; int opcode = b[v] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: v += 1; break; case ClassWriter.LABEL_INSN: readLabel(w + readShort(v + 1), labels); v += 3; break; case ClassWriter.LABELW_INSN: readLabel(w + readInt(v + 1), labels); v += 5; break; case ClassWriter.WIDE_INSN: opcode = b[v + 1] & 0xFF; if (opcode == Opcodes.IINC) { v += 6; } else { v += 4; } break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes* v = v + 4 - (w & 3); // reads instruction readLabel(w + readInt(v), labels); j = readInt(v + 8) - readInt(v + 4) + 1; v += 12; for (; j > 0; --j) { readLabel(w + readInt(v), labels); v += 4; } break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes* v = v + 4 - (w & 3); // reads instruction readLabel(w + readInt(v), labels); j = readInt(v + 4); v += 8; for (; j > 0; --j) { readLabel(w + readInt(v + 4), labels); v += 8; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: v += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: v += 3; break; case ClassWriter.ITFDYNMETH_INSN: v += 5; break; // case MANA_INSN: default: v += 4; break; } } // parses the try catch entries j = readUnsignedShort(v); v += 2; for (; j > 0; --j) { Label start = readLabel(readUnsignedShort(v), labels); Label end = readLabel(readUnsignedShort(v + 2), labels); Label handler = readLabel(readUnsignedShort(v + 4), labels); int type = readUnsignedShort(v + 6); if (type == 0) { mv.visitTryCatchBlock(start, end, handler, null); } else { mv.visitTryCatchBlock(start, end, handler, readUTF8(items[type], c)); } v += 8; } // parses the local variable, line number tables, and code // attributes int varTable = 0; int varTypeTable = 0; int stackMap = 0; int stackMapSize = 0; int frameCount = 0; int frameMode = 0; int frameOffset = 0; int frameLocalCount = 0; int frameLocalDiff = 0; int frameStackCount = 0; Object[] frameLocal = null; Object[] frameStack = null; boolean zip = true; cattrs = null; j = readUnsignedShort(v); v += 2; for (; j > 0; --j) { attrName = readUTF8(v, c); if ("LocalVariableTable".equals(attrName)) { if (!skipDebug) { varTable = v + 6; k = readUnsignedShort(v + 6); w = v + 8; for (; k > 0; --k) { label = readUnsignedShort(w); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } label += readUnsignedShort(w + 2); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } w += 10; } } } else if ("LocalVariableTypeTable".equals(attrName)) { varTypeTable = v + 6; } else if ("LineNumberTable".equals(attrName)) { if (!skipDebug) { k = readUnsignedShort(v + 6); w = v + 8; for (; k > 0; --k) { label = readUnsignedShort(w); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } labels[label].line = readUnsignedShort(w + 2); w += 4; } } } else if (FRAMES && "StackMapTable".equals(attrName)) { if ((flags & SKIP_FRAMES) == 0) { stackMap = v + 8; stackMapSize = readInt(v + 2); frameCount = readUnsignedShort(v + 6); } /* * here we do not extract the labels corresponding to * the attribute content. This would require a full * parsing of the attribute, which would need to be * repeated in the second phase (see below). Instead the * content of the attribute is read one frame at a time * (i.e. after a frame has been visited, the next frame * is read), and the labels it contains are also * extracted one frame at a time. Thanks to the ordering * of frames, having only a "one frame lookahead" is not * a problem, i.e. it is not possible to see an offset * smaller than the offset of the current insn and for * which no Label exist. */ /* * This is not true for UNINITIALIZED type offsets. We * solve this by parsing the stack map table without a * full decoding (see below). */ } else if (FRAMES && "StackMap".equals(attrName)) { if ((flags & SKIP_FRAMES) == 0) { stackMap = v + 8; stackMapSize = readInt(v + 2); frameCount = readUnsignedShort(v + 6); zip = false; } /* * IMPORTANT! here we assume that the frames are * ordered, as in the StackMapTable attribute, although * this is not guaranteed by the attribute format. */ } else { for (k = 0; k < attrs.length; ++k) { if (attrs[k].type.equals(attrName)) { attr = attrs[k].read(this, v + 6, readInt(v + 2), c, codeStart - 8, labels); if (attr != null) { attr.next = cattrs; cattrs = attr; } } } } v += 6 + readInt(v + 2); } // 2nd phase: visits each instruction if (FRAMES && stackMap != 0) { // creates the very first (implicit) frame from the method // descriptor frameLocal = new Object[maxLocals]; frameStack = new Object[maxStack]; if (unzip) { int local = 0; if ((access & Opcodes.ACC_STATIC) == 0) { if ("".equals(name)) { frameLocal[local++] = Opcodes.UNINITIALIZED_THIS; } else { frameLocal[local++] = readClass(header + 2, c); } } j = 1; loop: while (true) { k = j; switch (desc.charAt(j++)) { case 'Z': case 'C': case 'B': case 'S': case 'I': frameLocal[local++] = Opcodes.INTEGER; break; case 'F': frameLocal[local++] = Opcodes.FLOAT; break; case 'J': frameLocal[local++] = Opcodes.LONG; break; case 'D': frameLocal[local++] = Opcodes.DOUBLE; break; case '[': while (desc.charAt(j) == '[') { ++j; } if (desc.charAt(j) == 'L') { ++j; while (desc.charAt(j) != ';') { ++j; } } frameLocal[local++] = desc.substring(k, ++j); break; case 'L': while (desc.charAt(j) != ';') { ++j; } frameLocal[local++] = desc.substring(k + 1, j++); break; default: break loop; } } frameLocalCount = local; } /* * for the first explicit frame the offset is not * offset_delta + 1 but only offset_delta; setting the * implicit frame offset to -1 allow the use of the * "offset_delta + 1" rule in all cases */ frameOffset = -1; /* * Finds labels for UNINITIALIZED frame types. Instead of * decoding each element of the stack map table, we look * for 3 consecutive bytes that "look like" an UNINITIALIZED * type (tag 8, offset within code bounds, NEW instruction * at this offset). We may find false positives (i.e. not * real UNINITIALIZED types), but this should be rare, and * the only consequence will be the creation of an unneeded * label. This is better than creating a label for each NEW * instruction, and faster than fully decoding the whole * stack map table. */ for (j = stackMap; j < stackMap + stackMapSize - 2; ++j) { if (b[j] == 8) { // UNINITIALIZED FRAME TYPE k = readUnsignedShort(j + 1); if (k >= 0 && k < codeLength) { // potential offset if ((b[codeStart + k] & 0xFF) == Opcodes.NEW) { // NEW at this offset readLabel(k, labels); } } } } } v = codeStart; Label l; while (v < codeEnd) { w = v - codeStart; l = labels[w]; if (l != null) { mv.visitLabel(l); if (!skipDebug && l.line > 0) { mv.visitLineNumber(l.line, l); } } while (FRAMES && frameLocal != null && (frameOffset == w || frameOffset == -1)) { // if there is a frame for this offset, // makes the visitor visit it, // and reads the next frame if there is one. if (!zip || unzip) { mv.visitFrame(Opcodes.F_NEW, frameLocalCount, frameLocal, frameStackCount, frameStack); } else if (frameOffset != -1) { mv.visitFrame(frameMode, frameLocalDiff, frameLocal, frameStackCount, frameStack); } if (frameCount > 0) { int tag, delta, n; if (zip) { tag = b[stackMap++] & 0xFF; } else { tag = MethodWriter.FULL_FRAME; frameOffset = -1; } frameLocalDiff = 0; if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { delta = tag; frameMode = Opcodes.F_SAME; frameStackCount = 0; } else if (tag < MethodWriter.RESERVED) { delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; stackMap = readFrameType(frameStack, 0, stackMap, c, labels); frameMode = Opcodes.F_SAME1; frameStackCount = 1; } else { delta = readUnsignedShort(stackMap); stackMap += 2; if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { stackMap = readFrameType(frameStack, 0, stackMap, c, labels); frameMode = Opcodes.F_SAME1; frameStackCount = 1; } else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED) { frameMode = Opcodes.F_CHOP; frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; frameLocalCount -= frameLocalDiff; frameStackCount = 0; } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { frameMode = Opcodes.F_SAME; frameStackCount = 0; } else if (tag < MethodWriter.FULL_FRAME) { j = unzip ? frameLocalCount : 0; for (k = tag - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--) { stackMap = readFrameType(frameLocal, j++, stackMap, c, labels); } frameMode = Opcodes.F_APPEND; frameLocalDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; frameLocalCount += frameLocalDiff; frameStackCount = 0; } else { // if (tag == FULL_FRAME) { frameMode = Opcodes.F_FULL; n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap); stackMap += 2; for (j = 0; n > 0; n--) { stackMap = readFrameType(frameLocal, j++, stackMap, c, labels); } n = frameStackCount = readUnsignedShort(stackMap); stackMap += 2; for (j = 0; n > 0; n--) { stackMap = readFrameType(frameStack, j++, stackMap, c, labels); } } } frameOffset += delta + 1; readLabel(frameOffset, labels); --frameCount; } else { frameLocal = null; } } int opcode = b[v] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: mv.visitInsn(opcode); v += 1; break; case ClassWriter.IMPLVAR_INSN: if (opcode > Opcodes.ISTORE) { opcode -= 59; // ISTORE_0 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); } else { opcode -= 26; // ILOAD_0 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); } v += 1; break; case ClassWriter.LABEL_INSN: mv.visitJumpInsn(opcode, labels[w + readShort(v + 1)]); v += 3; break; case ClassWriter.LABELW_INSN: mv.visitJumpInsn(opcode - 33, labels[w + readInt(v + 1)]); v += 5; break; case ClassWriter.WIDE_INSN: opcode = b[v + 1] & 0xFF; if (opcode == Opcodes.IINC) { mv.visitIincInsn(readUnsignedShort(v + 2), readShort(v + 4)); v += 6; } else { mv.visitVarInsn(opcode, readUnsignedShort(v + 2)); v += 4; } break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes v = v + 4 - (w & 3); // reads instruction label = w + readInt(v); int min = readInt(v + 4); int max = readInt(v + 8); v += 12; Label[] table = new Label[max - min + 1]; for (j = 0; j < table.length; ++j) { table[j] = labels[w + readInt(v)]; v += 4; } mv.visitTableSwitchInsn(min, max, labels[label], table); break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes v = v + 4 - (w & 3); // reads instruction label = w + readInt(v); j = readInt(v + 4); v += 8; int[] keys = new int[j]; Label[] values = new Label[j]; for (j = 0; j < keys.length; ++j) { keys[j] = readInt(v); values[j] = labels[w + readInt(v + 4)]; v += 8; } mv.visitLookupSwitchInsn(labels[label], keys, values); break; case ClassWriter.VAR_INSN: mv.visitVarInsn(opcode, b[v + 1] & 0xFF); v += 2; break; case ClassWriter.SBYTE_INSN: mv.visitIntInsn(opcode, b[v + 1]); v += 2; break; case ClassWriter.SHORT_INSN: mv.visitIntInsn(opcode, readShort(v + 1)); v += 3; break; case ClassWriter.LDC_INSN: mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c)); v += 2; break; case ClassWriter.LDCW_INSN: mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), c)); v += 3; break; case ClassWriter.FIELDORMETH_INSN: case ClassWriter.ITFDYNMETH_INSN: int cpIndex = items[readUnsignedShort(v + 1)]; String iowner; // INVOKEDYNAMIC is receiverless if (opcode == Opcodes.INVOKEDYNAMIC) { iowner = Opcodes.INVOKEDYNAMIC_OWNER; } else { iowner = readClass(cpIndex, c); cpIndex = items[readUnsignedShort(cpIndex + 2)]; } String iname = readUTF8(cpIndex, c); String idesc = readUTF8(cpIndex + 2, c); if (opcode < Opcodes.INVOKEVIRTUAL) { mv.visitFieldInsn(opcode, iowner, iname, idesc); } else { mv.visitMethodInsn(opcode, iowner, iname, idesc); } if (opcode == Opcodes.INVOKEINTERFACE || opcode == Opcodes.INVOKEDYNAMIC) { v += 5; } else { v += 3; } break; case ClassWriter.TYPE_INSN: mv.visitTypeInsn(opcode, readClass(v + 1, c)); v += 3; break; case ClassWriter.IINC_INSN: mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]); v += 3; break; // case MANA_INSN: default: mv.visitMultiANewArrayInsn(readClass(v + 1, c), b[v + 3] & 0xFF); v += 4; break; } } l = labels[codeEnd - codeStart]; if (l != null) { mv.visitLabel(l); } // visits the local variable tables if (!skipDebug && varTable != 0) { int[] typeTable = null; if (varTypeTable != 0) { k = readUnsignedShort(varTypeTable) * 3; w = varTypeTable + 2; typeTable = new int[k]; while (k > 0) { typeTable[--k] = w + 6; // signature typeTable[--k] = readUnsignedShort(w + 8); // index typeTable[--k] = readUnsignedShort(w); // start w += 10; } } k = readUnsignedShort(varTable); w = varTable + 2; for (; k > 0; --k) { int start = readUnsignedShort(w); int length = readUnsignedShort(w + 2); int index = readUnsignedShort(w + 8); String vsignature = null; if (typeTable != null) { for (int a = 0; a < typeTable.length; a += 3) { if (typeTable[a] == start && typeTable[a + 1] == index) { vsignature = readUTF8(typeTable[a + 2], c); break; } } } mv.visitLocalVariable(readUTF8(w + 4, c), readUTF8(w + 6, c), vsignature, labels[start], labels[start + length], index); w += 10; } } // visits the other attributes while (cattrs != null) { attr = cattrs.next; cattrs.next = null; mv.visitAttribute(cattrs); cattrs = attr; } // visits the max stack and max locals values mv.visitMaxs(maxStack, maxLocals); } if (mv != null) { mv.visitEnd(); } } // visits the end of the class classVisitor.visitEnd(); } /** * Reads parameter annotations and makes the given visitor visit them. * * @param v start offset in {@link #b b} of the annotations to be read. * @param desc the method descriptor. * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, * {@link #readClass(int,char[]) readClass} or * {@link #readConst readConst}. * @param visible true if the annotations to be read are visible * at runtime. * @param mv the visitor that must visit the annotations. */ private void readParameterAnnotations( int v, final String desc, final char[] buf, final boolean visible, final MethodVisitor mv) { int i; int n = b[v++] & 0xFF; // workaround for a bug in javac (javac compiler generates a parameter // annotation array whose size is equal to the number of parameters in // the Java source file, while it should generate an array whose size is // equal to the number of parameters in the method descriptor - which // includes the synthetic parameters added by the compiler). This work- // around supposes that the synthetic parameters are the first ones. int synthetics = Type.getArgumentTypes(desc).length - n; AnnotationVisitor av; for (i = 0; i < synthetics; ++i) { // virtual annotation to detect synthetic parameters in MethodWriter av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); if (av != null) { av.visitEnd(); } } for (; i < n + synthetics; ++i) { int j = readUnsignedShort(v); v += 2; for (; j > 0; --j) { av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible); v = readAnnotationValues(v + 2, buf, true, av); } } } /** * Reads the values of an annotation and makes the given visitor visit them. * * @param v the start offset in {@link #b b} of the values to be read * (including the unsigned short that gives the number of values). * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, * {@link #readClass(int,char[]) readClass} or * {@link #readConst readConst}. * @param named if the annotation values are named or not. * @param av the visitor that must visit the values. * @return the end offset of the annotation values. */ private int readAnnotationValues( int v, final char[] buf, final boolean named, final AnnotationVisitor av) { int i = readUnsignedShort(v); v += 2; if (named) { for (; i > 0; --i) { v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); } } else { for (; i > 0; --i) { v = readAnnotationValue(v, buf, null, av); } } if (av != null) { av.visitEnd(); } return v; } /** * Reads a value of an annotation and makes the given visitor visit it. * * @param v the start offset in {@link #b b} of the value to be read (not * including the value name constant pool index). * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, * {@link #readClass(int,char[]) readClass} or * {@link #readConst readConst}. * @param name the name of the value to be read. * @param av the visitor that must visit the value. * @return the end offset of the annotation value. */ private int readAnnotationValue( int v, final char[] buf, final String name, final AnnotationVisitor av) { int i; if (av == null) { switch (b[v] & 0xFF) { case 'e': // enum_const_value return v + 5; case '@': // annotation_value return readAnnotationValues(v + 3, buf, true, null); case '[': // array_value return readAnnotationValues(v + 1, buf, false, null); default: return v + 3; } } switch (b[v++] & 0xFF) { case 'I': // pointer to CONSTANT_Integer case 'J': // pointer to CONSTANT_Long case 'F': // pointer to CONSTANT_Float case 'D': // pointer to CONSTANT_Double av.visit(name, readConst(readUnsignedShort(v), buf)); v += 2; break; case 'B': // pointer to CONSTANT_Byte av.visit(name, new Byte((byte) readInt(items[readUnsignedShort(v)]))); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE); v += 2; break; case 'S': // pointer to CONSTANT_Short av.visit(name, new Short((short) readInt(items[readUnsignedShort(v)]))); v += 2; break; case 'C': // pointer to CONSTANT_Char av.visit(name, new Character((char) readInt(items[readUnsignedShort(v)]))); v += 2; break; case 's': // pointer to CONSTANT_Utf8 av.visit(name, readUTF8(v, buf)); v += 2; break; case 'e': // enum_const_value av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); v += 4; break; case 'c': // class_info av.visit(name, Type.getType(readUTF8(v, buf))); v += 2; break; case '@': // annotation_value v = readAnnotationValues(v + 2, buf, true, av.visitAnnotation(name, readUTF8(v, buf))); break; case '[': // array_value int size = readUnsignedShort(v); v += 2; if (size == 0) { return readAnnotationValues(v - 2, buf, false, av.visitArray(name)); } switch (this.b[v++] & 0xFF) { case 'B': byte[] bv = new byte[size]; for (i = 0; i < size; i++) { bv[i] = (byte) readInt(items[readUnsignedShort(v)]); v += 3; } av.visit(name, bv); --v; break; case 'Z': boolean[] zv = new boolean[size]; for (i = 0; i < size; i++) { zv[i] = readInt(items[readUnsignedShort(v)]) != 0; v += 3; } av.visit(name, zv); --v; break; case 'S': short[] sv = new short[size]; for (i = 0; i < size; i++) { sv[i] = (short) readInt(items[readUnsignedShort(v)]); v += 3; } av.visit(name, sv); --v; break; case 'C': char[] cv = new char[size]; for (i = 0; i < size; i++) { cv[i] = (char) readInt(items[readUnsignedShort(v)]); v += 3; } av.visit(name, cv); --v; break; case 'I': int[] iv = new int[size]; for (i = 0; i < size; i++) { iv[i] = readInt(items[readUnsignedShort(v)]); v += 3; } av.visit(name, iv); --v; break; case 'J': long[] lv = new long[size]; for (i = 0; i < size; i++) { lv[i] = readLong(items[readUnsignedShort(v)]); v += 3; } av.visit(name, lv); --v; break; case 'F': float[] fv = new float[size]; for (i = 0; i < size; i++) { fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); v += 3; } av.visit(name, fv); --v; break; case 'D': double[] dv = new double[size]; for (i = 0; i < size; i++) { dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); v += 3; } av.visit(name, dv); --v; break; default: v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); } } return v; } private int readFrameType( final Object[] frame, final int index, int v, final char[] buf, final Label[] labels) { int type = b[v++] & 0xFF; switch (type) { case 0: frame[index] = Opcodes.TOP; break; case 1: frame[index] = Opcodes.INTEGER; break; case 2: frame[index] = Opcodes.FLOAT; break; case 3: frame[index] = Opcodes.DOUBLE; break; case 4: frame[index] = Opcodes.LONG; break; case 5: frame[index] = Opcodes.NULL; break; case 6: frame[index] = Opcodes.UNINITIALIZED_THIS; break; case 7: // Object frame[index] = readClass(v, buf); v += 2; break; default: // Uninitialized frame[index] = readLabel(readUnsignedShort(v), labels); v += 2; } return v; } /** * Returns the label corresponding to the given offset. The default * implementation of this method creates a label for the given offset if it * has not been already created. * * @param offset a bytecode offset in a method. * @param labels the already created labels, indexed by their offset. If a * label already exists for offset this method must not create a new * one. Otherwise it must store the new label in this array. * @return a non null Label, which must be equal to labels[offset]. */ protected Label readLabel(int offset, Label[] labels) { if (labels[offset] == null) { labels[offset] = new Label(); } return labels[offset]; } /** * Reads an attribute in {@link #b b}. * * @param attrs prototypes of the attributes that must be parsed during the * visit of the class. Any attribute whose type is not equal to the * type of one the prototypes is ignored (i.e. an empty * {@link Attribute} instance is returned). * @param type the type of the attribute. * @param off index of the first byte of the attribute's content in * {@link #b b}. The 6 attribute header bytes, containing the type * and the length of the attribute, are not taken into account here * (they have already been read). * @param len the length of the attribute's content. * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, * {@link #readClass(int,char[]) readClass} or * {@link #readConst readConst}. * @param codeOff index of the first byte of code's attribute content in * {@link #b b}, or -1 if the attribute to be read is not a code * attribute. The 6 attribute header bytes, containing the type and * the length of the attribute, are not taken into account here. * @param labels the labels of the method's code, or null if the * attribute to be read is not a code attribute. * @return the attribute that has been read, or null to skip this * attribute. */ private Attribute readAttribute( final Attribute[] attrs, final String type, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { for (int i = 0; i < attrs.length; ++i) { if (attrs[i].type.equals(type)) { return attrs[i].read(this, off, len, buf, codeOff, labels); } } return new Attribute(type).read(this, off, len, null, -1, null); } // ------------------------------------------------------------------------ // Utility methods: low level parsing // ------------------------------------------------------------------------ /** * Returns the start index of the constant pool item in {@link #b b}, plus * one. This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters. * * @param item the index a constant pool item. * @return the start index of the constant pool item in {@link #b b}, plus * one. */ public int getItem(final int item) { return items[item]; } /** * Reads a byte value in {@link #b b}. This method is intended for * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters. * * @param index the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readByte(final int index) { return b[index] & 0xFF; } /** * Reads an unsigned short value in {@link #b b}. This method is * intended for {@link Attribute} sub classes, and is normally not needed by * class generators or adapters. * * @param index the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readUnsignedShort(final int index) { byte[] b = this.b; return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); } /** * Reads a signed short value in {@link #b b}. This method is intended * for {@link Attribute} sub classes, and is normally not needed by class * generators or adapters. * * @param index the start index of the value to be read in {@link #b b}. * @return the read value. */ public short readShort(final int index) { byte[] b = this.b; return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); } /** * Reads a signed int value in {@link #b b}. This method is intended for * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters. * * @param index the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readInt(final int index) { byte[] b = this.b; return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); } /** * Reads a signed long value in {@link #b b}. This method is intended * for {@link Attribute} sub classes, and is normally not needed by class * generators or adapters. * * @param index the start index of the value to be read in {@link #b b}. * @return the read value. */ public long readLong(final int index) { long l1 = readInt(index); long l0 = readInt(index + 4) & 0xFFFFFFFFL; return (l1 << 32) | l0; } /** * Reads an UTF8 string constant pool item in {@link #b b}. This method * is intended for {@link Attribute} sub classes, and is normally not needed * by class generators or adapters. * * @param index the start index of an unsigned short value in {@link #b b}, * whose value is the index of an UTF8 constant pool item. * @param buf buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified UTF8 item. */ public String readUTF8(int index, final char[] buf) { int item = readUnsignedShort(index); String s = strings[item]; if (s != null) { return s; } index = items[item]; return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); } /** * Reads UTF8 string in {@link #b b}. * * @param index start offset of the UTF8 string to be read. * @param utfLen length of the UTF8 string to be read. * @param buf buffer to be used to read the string. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified UTF8 string. */ private String readUTF(int index, final int utfLen, final char[] buf) { int endIndex = index + utfLen; byte[] b = this.b; int strLen = 0; int c; int st = 0; char cc = 0; while (index < endIndex) { c = b[index++]; switch (st) { case 0: c = c & 0xFF; if (c < 0x80) { // 0xxxxxxx buf[strLen++] = (char) c; } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx cc = (char) (c & 0x1F); st = 1; } else { // 1110 xxxx 10xx xxxx 10xx xxxx cc = (char) (c & 0x0F); st = 2; } break; case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); st = 0; break; case 2: // byte 2 of 3-byte char cc = (char) ((cc << 6) | (c & 0x3F)); st = 1; break; } } return new String(buf, 0, strLen); } /** * Reads a class constant pool item in {@link #b b}. This method is * intended for {@link Attribute} sub classes, and is normally not needed by * class generators or adapters. * * @param index the start index of an unsigned short value in {@link #b b}, * whose value is the index of a class constant pool item. * @param buf buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified class item. */ public String readClass(final int index, final char[] buf) { // computes the start index of the CONSTANT_Class item in b // and reads the CONSTANT_Utf8 item designated by // the first two bytes of this CONSTANT_Class item return readUTF8(items[readUnsignedShort(index)], buf); } /** * Reads a numeric or string constant pool item in {@link #b b}. This * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters. * * @param item the index of a constant pool item. * @param buf buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the {@link Integer}, {@link Float}, {@link Long}, * {@link Double}, {@link String} or {@link Type} corresponding to * the given constant pool item. */ public Object readConst(final int item, final char[] buf) { int index = items[item]; switch (b[index - 1]) { case ClassWriter.INT: return new Integer(readInt(index)); case ClassWriter.FLOAT: return new Float(Float.intBitsToFloat(readInt(index))); case ClassWriter.LONG: return new Long(readLong(index)); case ClassWriter.DOUBLE: return new Double(Double.longBitsToDouble(readLong(index))); case ClassWriter.CLASS: return Type.getObjectType(readUTF8(index, buf)); // case ClassWriter.STR: default: return readUTF8(index, buf); } } } asm-3.3.2/src/org/objectweb/asm/tree/0000755000175000017500000000000011633370220017273 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/tree/MethodNode.java0000644000175000017500000003757111052514643022205 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.util.List; import java.util.ArrayList; import java.util.Arrays; /** * A node that represents a method. * * @author Eric Bruneton */ public class MethodNode extends MemberNode implements MethodVisitor { /** * The method's access flags (see {@link Opcodes}). This field also * indicates if the method is synthetic and/or deprecated. */ public int access; /** * The method's name. */ public String name; /** * The method's descriptor (see {@link Type}). */ public String desc; /** * The method's signature. May be null. */ public String signature; /** * The internal names of the method's exception classes (see * {@link Type#getInternalName() getInternalName}). This list is a list of * {@link String} objects. */ public List exceptions; /** * The default value of this annotation interface method. This field must be * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short}, * {@link Integer}, {@link Long}, {@link Float}, {@link Double}, * {@link String} or {@link Type}, or an two elements String array (for * enumeration values), a {@link AnnotationNode}, or a {@link List} of * values of one of the preceding types. May be null. */ public Object annotationDefault; /** * The runtime visible parameter annotations of this method. These lists are * lists of {@link AnnotationNode} objects. May be null. * * @associates org.objectweb.asm.tree.AnnotationNode * @label invisible parameters */ public List[] visibleParameterAnnotations; /** * The runtime invisible parameter annotations of this method. These lists * are lists of {@link AnnotationNode} objects. May be null. * * @associates org.objectweb.asm.tree.AnnotationNode * @label visible parameters */ public List[] invisibleParameterAnnotations; /** * The instructions of this method. This list is a list of * {@link AbstractInsnNode} objects. * * @associates org.objectweb.asm.tree.AbstractInsnNode * @label instructions */ public InsnList instructions; /** * The try catch blocks of this method. This list is a list of * {@link TryCatchBlockNode} objects. * * @associates org.objectweb.asm.tree.TryCatchBlockNode */ public List tryCatchBlocks; /** * The maximum stack size of this method. */ public int maxStack; /** * The maximum number of local variables of this method. */ public int maxLocals; /** * The local variables of this method. This list is a list of * {@link LocalVariableNode} objects. May be null * * @associates org.objectweb.asm.tree.LocalVariableNode */ public List localVariables; /** * Constructs an unitialized {@link MethodNode}. */ public MethodNode() { this.instructions = new InsnList(); } /** * Constructs a new {@link MethodNode}. * * @param access the method's access flags (see {@link Opcodes}). This * parameter also indicates if the method is synthetic and/or * deprecated. * @param name the method's name. * @param desc the method's descriptor (see {@link Type}). * @param signature the method's signature. May be null. * @param exceptions the internal names of the method's exception classes * (see {@link Type#getInternalName() getInternalName}). May be * null. */ public MethodNode( final int access, final String name, final String desc, final String signature, final String[] exceptions) { this(); this.access = access; this.name = name; this.desc = desc; this.signature = signature; this.exceptions = new ArrayList(exceptions == null ? 0 : exceptions.length); boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; if (!isAbstract) { this.localVariables = new ArrayList(5); } this.tryCatchBlocks = new ArrayList(); if (exceptions != null) { this.exceptions.addAll(Arrays.asList(exceptions)); } } // ------------------------------------------------------------------------ // Implementation of the MethodVisitor interface // ------------------------------------------------------------------------ public AnnotationVisitor visitAnnotationDefault() { return new AnnotationNode(new ArrayList(0) { public boolean add(final Object o) { annotationDefault = o; return super.add(o); } }); } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleParameterAnnotations == null) { int params = Type.getArgumentTypes(this.desc).length; visibleParameterAnnotations = new List[params]; } if (visibleParameterAnnotations[parameter] == null) { visibleParameterAnnotations[parameter] = new ArrayList(1); } visibleParameterAnnotations[parameter].add(an); } else { if (invisibleParameterAnnotations == null) { int params = Type.getArgumentTypes(this.desc).length; invisibleParameterAnnotations = new List[params]; } if (invisibleParameterAnnotations[parameter] == null) { invisibleParameterAnnotations[parameter] = new ArrayList(1); } invisibleParameterAnnotations[parameter].add(an); } return an; } public void visitCode() { } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { instructions.add(new FrameNode(type, nLocal, local == null ? null : getLabelNodes(local), nStack, stack == null ? null : getLabelNodes(stack))); } public void visitInsn(final int opcode) { instructions.add(new InsnNode(opcode)); } public void visitIntInsn(final int opcode, final int operand) { instructions.add(new IntInsnNode(opcode, operand)); } public void visitVarInsn(final int opcode, final int var) { instructions.add(new VarInsnNode(opcode, var)); } public void visitTypeInsn(final int opcode, final String type) { instructions.add(new TypeInsnNode(opcode, type)); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { instructions.add(new FieldInsnNode(opcode, owner, name, desc)); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { instructions.add(new MethodInsnNode(opcode, owner, name, desc)); } public void visitJumpInsn(final int opcode, final Label label) { instructions.add(new JumpInsnNode(opcode, getLabelNode(label))); } public void visitLabel(final Label label) { instructions.add(getLabelNode(label)); } public void visitLdcInsn(final Object cst) { instructions.add(new LdcInsnNode(cst)); } public void visitIincInsn(final int var, final int increment) { instructions.add(new IincInsnNode(var, increment)); } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt), getLabelNodes(labels))); } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys, getLabelNodes(labels))); } public void visitMultiANewArrayInsn(final String desc, final int dims) { instructions.add(new MultiANewArrayInsnNode(desc, dims)); } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type)); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { localVariables.add(new LocalVariableNode(name, desc, signature, getLabelNode(start), getLabelNode(end), index)); } public void visitLineNumber(final int line, final Label start) { instructions.add(new LineNumberNode(line, getLabelNode(start))); } public void visitMaxs(final int maxStack, final int maxLocals) { this.maxStack = maxStack; this.maxLocals = maxLocals; } /** * Returns the LabelNode corresponding to the given Label. Creates a new * LabelNode if necessary. The default implementation of this method uses * the {@link Label#info} field to store associations between labels and * label nodes. * * @param l a Label. * @return the LabelNode corresponding to l. */ protected LabelNode getLabelNode(final Label l) { if (!(l.info instanceof LabelNode)) { l.info = new LabelNode(l); } return (LabelNode) l.info; } private LabelNode[] getLabelNodes(final Label[] l) { LabelNode[] nodes = new LabelNode[l.length]; for (int i = 0; i < l.length; ++i) { nodes[i] = getLabelNode(l[i]); } return nodes; } private Object[] getLabelNodes(final Object[] objs) { Object[] nodes = new Object[objs.length]; for (int i = 0; i < objs.length; ++i) { Object o = objs[i]; if (o instanceof Label) { o = getLabelNode((Label) o); } nodes[i] = o; } return nodes; } // ------------------------------------------------------------------------ // Accept method // ------------------------------------------------------------------------ /** * Makes the given class visitor visit this method. * * @param cv a class visitor. */ public void accept(final ClassVisitor cv) { String[] exceptions = new String[this.exceptions.size()]; this.exceptions.toArray(exceptions); MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv != null) { accept(mv); } } /** * Makes the given method visitor visit this method. * * @param mv a method visitor. */ public void accept(final MethodVisitor mv) { // visits the method attributes int i, j, n; if (annotationDefault != null) { AnnotationVisitor av = mv.visitAnnotationDefault(); AnnotationNode.accept(av, null, annotationDefault); if (av != null) { av.visitEnd(); } } n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); an.accept(mv.visitAnnotation(an.desc, true)); } n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); an.accept(mv.visitAnnotation(an.desc, false)); } n = visibleParameterAnnotations == null ? 0 : visibleParameterAnnotations.length; for (i = 0; i < n; ++i) { List l = visibleParameterAnnotations[i]; if (l == null) { continue; } for (j = 0; j < l.size(); ++j) { AnnotationNode an = (AnnotationNode) l.get(j); an.accept(mv.visitParameterAnnotation(i, an.desc, true)); } } n = invisibleParameterAnnotations == null ? 0 : invisibleParameterAnnotations.length; for (i = 0; i < n; ++i) { List l = invisibleParameterAnnotations[i]; if (l == null) { continue; } for (j = 0; j < l.size(); ++j) { AnnotationNode an = (AnnotationNode) l.get(j); an.accept(mv.visitParameterAnnotation(i, an.desc, false)); } } n = attrs == null ? 0 : attrs.size(); for (i = 0; i < n; ++i) { mv.visitAttribute((Attribute) attrs.get(i)); } // visits the method's code if (instructions.size() > 0) { mv.visitCode(); // visits try catch blocks n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size(); for (i = 0; i < n; ++i) { ((TryCatchBlockNode) tryCatchBlocks.get(i)).accept(mv); } // visits instructions instructions.accept(mv); // visits local variables n = localVariables == null ? 0 : localVariables.size(); for (i = 0; i < n; ++i) { ((LocalVariableNode) localVariables.get(i)).accept(mv); } // visits maxs mv.visitMaxs(maxStack, maxLocals); } mv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/tree/InnerClassNode.java0000644000175000017500000000731510635277351023027 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.ClassVisitor; /** * A node that represents an inner class. * * @author Eric Bruneton */ public class InnerClassNode { /** * The internal name of an inner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). */ public String name; /** * The internal name of the class to which the inner class belongs (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May * be null. */ public String outerName; /** * The (simple) name of the inner class inside its enclosing class. May be * null for anonymous inner classes. */ public String innerName; /** * The access flags of the inner class as originally declared in the * enclosing class. */ public int access; /** * Constructs a new {@link InnerClassNode}. * * @param name the internal name of an inner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). * @param outerName the internal name of the class to which the inner class * belongs (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). * May be 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. */ public InnerClassNode( final String name, final String outerName, final String innerName, final int access) { this.name = name; this.outerName = outerName; this.innerName = innerName; this.access = access; } /** * Makes the given class visitor visit this inner class. * * @param cv a class visitor. */ public void accept(final ClassVisitor cv) { cv.visitInnerClass(name, outerName, innerName, access); } } asm-3.3.2/src/org/objectweb/asm/tree/IntInsnNode.java0000644000175000017500000000555310635277351022352 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents an instruction with a single int operand. * * @author Eric Bruneton */ public class IntInsnNode extends AbstractInsnNode { /** * The operand of this instruction. */ public int operand; /** * Constructs a new {@link IntInsnNode}. * * @param opcode the opcode of the instruction to be constructed. This * opcode must be BIPUSH, SIPUSH or NEWARRAY. * @param operand the operand of the instruction to be constructed. */ public IntInsnNode(final int opcode, final int operand) { super(opcode); this.operand = operand; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be BIPUSH, * SIPUSH or NEWARRAY. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return INT_INSN; } public void accept(final MethodVisitor mv) { mv.visitIntInsn(opcode, operand); } public AbstractInsnNode clone(final Map labels) { return new IntInsnNode(opcode, operand); } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/0000755000175000017500000000000011633370220021116 5ustar twernertwernerasm-3.3.2/src/org/objectweb/asm/tree/analysis/BasicValue.java0000644000175000017500000000734411355572170024020 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import org.objectweb.asm.Type; /** * A {@link Value} that is represented by its type in a seven types type system. * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, * REFERENCE and RETURNADDRESS types. * * @author Eric Bruneton */ public class BasicValue implements Value { public static final Value UNINITIALIZED_VALUE = new BasicValue(null); public static final Value INT_VALUE = new BasicValue(Type.INT_TYPE); public static final Value FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE); public static final Value LONG_VALUE = new BasicValue(Type.LONG_TYPE); public static final Value DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE); public static final Value REFERENCE_VALUE = new BasicValue(Type.getObjectType("java/lang/Object")); public static final Value RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE); private final Type type; public BasicValue(final Type type) { this.type = type; } public Type getType() { return type; } public int getSize() { return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1; } public boolean isReference() { return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY); } public boolean equals(final Object value) { if (value == this) { return true; } else if (value instanceof BasicValue) { if (type == null) { return ((BasicValue) value).type == null; } else { return type.equals(((BasicValue) value).type); } } else { return false; } } public int hashCode() { return type == null ? 0 : type.hashCode(); } public String toString() { if (this == UNINITIALIZED_VALUE) { return "."; } else if (this == RETURNADDRESS_VALUE) { return "A"; } else if (this == REFERENCE_VALUE) { return "R"; } else { return type.getDescriptor(); } } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/SourceInterpreter.java0000644000175000017500000001355411052514571025461 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.HashSet; import java.util.List; import java.util.Set; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; /** * An {@link Interpreter} for {@link SourceValue} values. * * @author Eric Bruneton */ public class SourceInterpreter implements Opcodes, Interpreter { public Value newValue(final Type type) { if (type == Type.VOID_TYPE) { return null; } return new SourceValue(type == null ? 1 : type.getSize()); } public Value newOperation(final AbstractInsnNode insn) { int size; switch (insn.getOpcode()) { case LCONST_0: case LCONST_1: case DCONST_0: case DCONST_1: size = 2; break; case LDC: Object cst = ((LdcInsnNode) insn).cst; size = cst instanceof Long || cst instanceof Double ? 2 : 1; break; case GETSTATIC: size = Type.getType(((FieldInsnNode) insn).desc).getSize(); break; default: size = 1; } return new SourceValue(size, insn); } public Value copyOperation(final AbstractInsnNode insn, final Value value) { return new SourceValue(value.getSize(), insn); } public Value unaryOperation(final AbstractInsnNode insn, final Value value) { int size; switch (insn.getOpcode()) { case LNEG: case DNEG: case I2L: case I2D: case L2D: case F2L: case F2D: case D2L: size = 2; break; case GETFIELD: size = Type.getType(((FieldInsnNode) insn).desc).getSize(); break; default: size = 1; } return new SourceValue(size, insn); } public Value binaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2) { int size; switch (insn.getOpcode()) { case LALOAD: case DALOAD: case LADD: case DADD: case LSUB: case DSUB: case LMUL: case DMUL: case LDIV: case DDIV: case LREM: case DREM: case LSHL: case LSHR: case LUSHR: case LAND: case LOR: case LXOR: size = 2; break; default: size = 1; } return new SourceValue(size, insn); } public Value ternaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2, final Value value3) { return new SourceValue(1, insn); } public Value naryOperation(final AbstractInsnNode insn, final List values) { int size; if (insn.getOpcode() == MULTIANEWARRAY) { size = 1; } else { size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize(); } return new SourceValue(size, insn); } public void returnOperation( final AbstractInsnNode insn, final Value value, final Value expected) { } public Value merge(final Value v, final Value w) { SourceValue dv = (SourceValue) v; SourceValue dw = (SourceValue) w; if (dv.insns instanceof SmallSet && dw.insns instanceof SmallSet) { Set s = ((SmallSet) dv.insns).union((SmallSet) dw.insns); if (s == dv.insns && dv.size == dw.size) { return v; } else { return new SourceValue(Math.min(dv.size, dw.size), s); } } if (dv.size != dw.size || !dv.insns.containsAll(dw.insns)) { Set s = new HashSet(); s.addAll(dv.insns); s.addAll(dw.insns); return new SourceValue(Math.min(dv.size, dw.size), s); } return v; } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/Analyzer.java0000644000175000017500000005135411503351141023553 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.VarInsnNode; /** * A semantic bytecode analyzer. This class does not fully check that JSR and * RET instructions are valid. * * @author Eric Bruneton */ public class Analyzer implements Opcodes { private final Interpreter interpreter; private int n; private InsnList insns; private List[] handlers; private Frame[] frames; private Subroutine[] subroutines; private boolean[] queued; private int[] queue; private int top; /** * Constructs a new {@link Analyzer}. * * @param interpreter the interpreter to be used to symbolically interpret * the bytecode instructions. */ public Analyzer(final Interpreter interpreter) { this.interpreter = interpreter; } /** * Analyzes the given method. * * @param owner the internal name of the class to which the method belongs. * @param m the method to be analyzed. * @return the symbolic state of the execution stack frame at each bytecode * instruction of the method. The size of the returned array is * equal to the number of instructions (and labels) of the method. A * given frame is null if and only if the corresponding * instruction cannot be reached (dead code). * @throws AnalyzerException if a problem occurs during the analysis. */ public Frame[] analyze(final String owner, final MethodNode m) throws AnalyzerException { if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { frames = new Frame[0]; return frames; } n = m.instructions.size(); insns = m.instructions; handlers = new List[n]; frames = new Frame[n]; subroutines = new Subroutine[n]; queued = new boolean[n]; queue = new int[n]; top = 0; // computes exception handlers for each instruction for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); int begin = insns.indexOf(tcb.start); int end = insns.indexOf(tcb.end); for (int j = begin; j < end; ++j) { List insnHandlers = handlers[j]; if (insnHandlers == null) { insnHandlers = new ArrayList(); handlers[j] = insnHandlers; } insnHandlers.add(tcb); } } // computes the subroutine for each instruction: Subroutine main = new Subroutine(null, m.maxLocals, null); List subroutineCalls = new ArrayList(); Map subroutineHeads = new HashMap(); findSubroutine(0, main, subroutineCalls); while (!subroutineCalls.isEmpty()) { JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0); Subroutine sub = (Subroutine) subroutineHeads.get(jsr.label); if (sub == null) { sub = new Subroutine(jsr.label, m.maxLocals, jsr); subroutineHeads.put(jsr.label, sub); findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls); } else { sub.callers.add(jsr); } } for (int i = 0; i < n; ++i) { if (subroutines[i] != null && subroutines[i].start == null) { subroutines[i] = null; } } // initializes the data structures for the control flow analysis Frame current = newFrame(m.maxLocals, m.maxStack); Frame handler = newFrame(m.maxLocals, m.maxStack); current.setReturn(interpreter.newValue(Type.getReturnType(m.desc))); Type[] args = Type.getArgumentTypes(m.desc); int local = 0; if ((m.access & ACC_STATIC) == 0) { Type ctype = Type.getObjectType(owner); current.setLocal(local++, interpreter.newValue(ctype)); } for (int i = 0; i < args.length; ++i) { current.setLocal(local++, interpreter.newValue(args[i])); if (args[i].getSize() == 2) { current.setLocal(local++, interpreter.newValue(null)); } } while (local < m.maxLocals) { current.setLocal(local++, interpreter.newValue(null)); } merge(0, current, null); init(owner, m); // control flow analysis while (top > 0) { int insn = queue[--top]; Frame f = frames[insn]; Subroutine subroutine = subroutines[insn]; queued[insn] = false; AbstractInsnNode insnNode = null; try { insnNode = m.instructions.get(insn); int insnOpcode = insnNode.getOpcode(); int insnType = insnNode.getType(); if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { merge(insn + 1, f, subroutine); newControlFlowEdge(insn, insn + 1); } else { current.init(f).execute(insnNode, interpreter); subroutine = subroutine == null ? null : subroutine.copy(); if (insnNode instanceof JumpInsnNode) { JumpInsnNode j = (JumpInsnNode) insnNode; if (insnOpcode != GOTO && insnOpcode != JSR) { merge(insn + 1, current, subroutine); newControlFlowEdge(insn, insn + 1); } int jump = insns.indexOf(j.label); if (insnOpcode == JSR) { merge(jump, current, new Subroutine(j.label, m.maxLocals, j)); } else { merge(jump, current, subroutine); } newControlFlowEdge(insn, jump); } else if (insnNode instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; int jump = insns.indexOf(lsi.dflt); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); for (int j = 0; j < lsi.labels.size(); ++j) { LabelNode label = (LabelNode) lsi.labels.get(j); jump = insns.indexOf(label); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); } } else if (insnNode instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; int jump = insns.indexOf(tsi.dflt); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); for (int j = 0; j < tsi.labels.size(); ++j) { LabelNode label = (LabelNode) tsi.labels.get(j); jump = insns.indexOf(label); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); } } else if (insnOpcode == RET) { if (subroutine == null) { throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine"); } for (int i = 0; i < subroutine.callers.size(); ++i) { Object caller = subroutine.callers.get(i); int call = insns.indexOf((AbstractInsnNode) caller); if (frames[call] != null) { merge(call + 1, frames[call], current, subroutines[call], subroutine.access); newControlFlowEdge(insn, call + 1); } } } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) { if (subroutine != null) { if (insnNode instanceof VarInsnNode) { int var = ((VarInsnNode) insnNode).var; subroutine.access[var] = true; if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) { subroutine.access[var + 1] = true; } } else if (insnNode instanceof IincInsnNode) { int var = ((IincInsnNode) insnNode).var; subroutine.access[var] = true; } } merge(insn + 1, current, subroutine); newControlFlowEdge(insn, insn + 1); } } List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); Type type; if (tcb.type == null) { type = Type.getObjectType("java/lang/Throwable"); } else { type = Type.getObjectType(tcb.type); } int jump = insns.indexOf(tcb.handler); if (newControlFlowExceptionEdge(insn, jump)) { handler.init(f); handler.clearStack(); handler.push(interpreter.newValue(type)); merge(jump, handler, subroutine); } } } } catch (AnalyzerException e) { throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e); } catch (Exception e) { throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e); } } return frames; } private void findSubroutine(int insn, final Subroutine sub, final List calls) throws AnalyzerException { while (true) { if (insn < 0 || insn >= n) { throw new AnalyzerException(null, "Execution can fall off end of the code"); } if (subroutines[insn] != null) { return; } subroutines[insn] = sub.copy(); AbstractInsnNode node = insns.get(insn); // calls findSubroutine recursively on normal successors if (node instanceof JumpInsnNode) { if (node.getOpcode() == JSR) { // do not follow a JSR, it leads to another subroutine! calls.add(node); } else { JumpInsnNode jnode = (JumpInsnNode) node; findSubroutine(insns.indexOf(jnode.label), sub, calls); } } else if (node instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node; findSubroutine(insns.indexOf(tsnode.dflt), sub, calls); for (int i = tsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) tsnode.labels.get(i); findSubroutine(insns.indexOf(l), sub, calls); } } else if (node instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node; findSubroutine(insns.indexOf(lsnode.dflt), sub, calls); for (int i = lsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) lsnode.labels.get(i); findSubroutine(insns.indexOf(l), sub, calls); } } // calls findSubroutine recursively on exception handler successors List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); findSubroutine(insns.indexOf(tcb.handler), sub, calls); } } // if insn does not falls through to the next instruction, return. switch (node.getOpcode()) { case GOTO: case RET: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: case ATHROW: return; } insn++; } } /** * Returns the symbolic stack frame for each instruction of the last * recently analyzed method. * * @return the symbolic state of the execution stack frame at each bytecode * instruction of the method. The size of the returned array is * equal to the number of instructions (and labels) of the method. A * given frame is null if the corresponding instruction * cannot be reached, or if an error occured during the analysis of * the method. */ public Frame[] getFrames() { return frames; } /** * Returns the exception handlers for the given instruction. * * @param insn the index of an instruction of the last recently analyzed * method. * @return a list of {@link TryCatchBlockNode} objects. */ public List getHandlers(final int insn) { return handlers[insn]; } /** * Initializes this analyzer. This method is called just before the * execution of control flow analysis loop in #analyze. The default * implementation of this method does nothing. * * @param owner the internal name of the class to which the method belongs. * @param m the method to be analyzed. * @throws AnalyzerException if a problem occurs. */ protected void init(String owner, MethodNode m) throws AnalyzerException { } /** * Constructs a new frame with the given size. * * @param nLocals the maximum number of local variables of the frame. * @param nStack the maximum stack size of the frame. * @return the created frame. */ protected Frame newFrame(final int nLocals, final int nStack) { return new Frame(nLocals, nStack); } /** * Constructs a new frame that is identical to the given frame. * * @param src a frame. * @return the created frame. */ protected Frame newFrame(final Frame src) { return new Frame(src); } /** * Creates a control flow graph edge. The default implementation of this * method does nothing. It can be overriden in order to construct the * control flow graph of a method (this method is called by the * {@link #analyze analyze} method during its visit of the method's code). * * @param insn an instruction index. * @param successor index of a successor instruction. */ protected void newControlFlowEdge(final int insn, final int successor) { } /** * Creates a control flow graph edge corresponding to an exception handler. * The default implementation of this method does nothing. It can be * overriden in order to construct the control flow graph of a method (this * method is called by the {@link #analyze analyze} method during its visit * of the method's code). * * @param insn an instruction index. * @param successor index of a successor instruction. * @return true if this edge must be considered in the data flow analysis * performed by this analyzer, or false otherwise. The default * implementation of this method always returns true. */ protected boolean newControlFlowExceptionEdge( final int insn, final int successor) { return true; } // ------------------------------------------------------------------------- private void merge( final int insn, final Frame frame, final Subroutine subroutine) throws AnalyzerException { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; if (oldFrame == null) { frames[insn] = newFrame(frame); changes = true; } else { changes = oldFrame.merge(frame, interpreter); } if (oldSubroutine == null) { if (subroutine != null) { subroutines[insn] = subroutine.copy(); changes = true; } } else { if (subroutine != null) { changes |= oldSubroutine.merge(subroutine); } } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } } private void merge( final int insn, final Frame beforeJSR, final Frame afterRET, final Subroutine subroutineBeforeJSR, final boolean[] access) throws AnalyzerException { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; afterRET.merge(beforeJSR, access); if (oldFrame == null) { frames[insn] = newFrame(afterRET); changes = true; } else { changes = oldFrame.merge(afterRET, access); } if (oldSubroutine != null && subroutineBeforeJSR != null) { changes |= oldSubroutine.merge(subroutineBeforeJSR); } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/BasicInterpreter.java0000644000175000017500000002547611244244744025255 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MultiANewArrayInsnNode; import org.objectweb.asm.tree.TypeInsnNode; /** * An {@link Interpreter} for {@link BasicValue} values. * * @author Eric Bruneton * @author Bing Ran */ public class BasicInterpreter implements Opcodes, Interpreter { public Value newValue(final Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } switch (type.getSort()) { case Type.VOID: return null; case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: return BasicValue.INT_VALUE; case Type.FLOAT: return BasicValue.FLOAT_VALUE; case Type.LONG: return BasicValue.LONG_VALUE; case Type.DOUBLE: return BasicValue.DOUBLE_VALUE; case Type.ARRAY: case Type.OBJECT: return BasicValue.REFERENCE_VALUE; default: throw new Error("Internal error"); } } public Value newOperation(final AbstractInsnNode insn) throws AnalyzerException { switch (insn.getOpcode()) { case ACONST_NULL: return newValue(Type.getObjectType("null")); case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: return BasicValue.INT_VALUE; case LCONST_0: case LCONST_1: return BasicValue.LONG_VALUE; case FCONST_0: case FCONST_1: case FCONST_2: return BasicValue.FLOAT_VALUE; case DCONST_0: case DCONST_1: return BasicValue.DOUBLE_VALUE; case BIPUSH: case SIPUSH: return BasicValue.INT_VALUE; case LDC: Object cst = ((LdcInsnNode) insn).cst; if (cst instanceof Integer) { return BasicValue.INT_VALUE; } else if (cst instanceof Float) { return BasicValue.FLOAT_VALUE; } else if (cst instanceof Long) { return BasicValue.LONG_VALUE; } else if (cst instanceof Double) { return BasicValue.DOUBLE_VALUE; } else if (cst instanceof Type) { return newValue(Type.getObjectType("java/lang/Class")); } else { return newValue(Type.getType(cst.getClass())); } case JSR: return BasicValue.RETURNADDRESS_VALUE; case GETSTATIC: return newValue(Type.getType(((FieldInsnNode) insn).desc)); case NEW: return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); default: throw new Error("Internal error."); } } public Value copyOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException { return value; } public Value unaryOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException { switch (insn.getOpcode()) { case INEG: case IINC: case L2I: case F2I: case D2I: case I2B: case I2C: case I2S: return BasicValue.INT_VALUE; case FNEG: case I2F: case L2F: case D2F: return BasicValue.FLOAT_VALUE; case LNEG: case I2L: case F2L: case D2L: return BasicValue.LONG_VALUE; case DNEG: case I2D: case L2D: case F2D: return BasicValue.DOUBLE_VALUE; case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case PUTSTATIC: return null; case GETFIELD: return newValue(Type.getType(((FieldInsnNode) insn).desc)); case NEWARRAY: switch (((IntInsnNode) insn).operand) { case T_BOOLEAN: return newValue(Type.getType("[Z")); case T_CHAR: return newValue(Type.getType("[C")); case T_BYTE: return newValue(Type.getType("[B")); case T_SHORT: return newValue(Type.getType("[S")); case T_INT: return newValue(Type.getType("[I")); case T_FLOAT: return newValue(Type.getType("[F")); case T_DOUBLE: return newValue(Type.getType("[D")); case T_LONG: return newValue(Type.getType("[J")); default: throw new AnalyzerException(insn, "Invalid array type"); } case ANEWARRAY: String desc = ((TypeInsnNode) insn).desc; return newValue(Type.getType("[" + Type.getObjectType(desc))); case ARRAYLENGTH: return BasicValue.INT_VALUE; case ATHROW: return null; case CHECKCAST: desc = ((TypeInsnNode) insn).desc; return newValue(Type.getObjectType(desc)); case INSTANCEOF: return BasicValue.INT_VALUE; case MONITORENTER: case MONITOREXIT: case IFNULL: case IFNONNULL: return null; default: throw new Error("Internal error."); } } public Value binaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2) throws AnalyzerException { switch (insn.getOpcode()) { case IALOAD: case BALOAD: case CALOAD: case SALOAD: case IADD: case ISUB: case IMUL: case IDIV: case IREM: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case IXOR: return BasicValue.INT_VALUE; case FALOAD: case FADD: case FSUB: case FMUL: case FDIV: case FREM: return BasicValue.FLOAT_VALUE; case LALOAD: case LADD: case LSUB: case LMUL: case LDIV: case LREM: case LSHL: case LSHR: case LUSHR: case LAND: case LOR: case LXOR: return BasicValue.LONG_VALUE; case DALOAD: case DADD: case DSUB: case DMUL: case DDIV: case DREM: return BasicValue.DOUBLE_VALUE; case AALOAD: return BasicValue.REFERENCE_VALUE; case LCMP: case FCMPL: case FCMPG: case DCMPL: case DCMPG: return BasicValue.INT_VALUE; case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE: case PUTFIELD: return null; default: throw new Error("Internal error."); } } public Value ternaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2, final Value value3) throws AnalyzerException { return null; } public Value naryOperation(final AbstractInsnNode insn, final List values) throws AnalyzerException { if (insn.getOpcode() == MULTIANEWARRAY) { return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); } else { return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); } } public void returnOperation( final AbstractInsnNode insn, final Value value, final Value expected) throws AnalyzerException { } public Value merge(final Value v, final Value w) { if (!v.equals(w)) { return BasicValue.UNINITIALIZED_VALUE; } return v; } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/package.html0000644000175000017500000000504210507566514023414 0ustar twernertwerner

Provides a framework for static code analysis based on the asm.tree package.

Basic usage:

ClassReader cr = new ClassReader(bytecode);
ClassNode cn = new ClassNode();
cr.accept(cn, ClassReader.SKIP_DEBUG);

List methods = cn.methods;
for (int i = 0; i < methods.size(); ++i) {
    MethodNode method = (MethodNode) methods.get(i);
    if (method.instructions.size() > 0) {
        Analyzer a = new Analyzer(new BasicInterpreter());
        a.analyze(cn.name, method);
        Frame[] frames = a.getFrames();
        // Elements of the frames arrray now contains info for each instruction 
        // from the analyzed method. BasicInterpreter creates BasicValue, that
        // is using simplified type system that distinguishes the UNINITIALZED, 
        // INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
        ...
    }
}   

@since ASM 1.4.3

asm-3.3.2/src/org/objectweb/asm/tree/analysis/SmallSet.java0000644000175000017500000001055210701747173023522 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.AbstractSet; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * A set of at most two elements. * * @author Eric Bruneton */ class SmallSet extends AbstractSet implements Iterator { // if e1 is null, e2 must be null; otherwise e2 must be different from e1 Object e1, e2; static final Set EMPTY_SET = new SmallSet(null, null); SmallSet(final Object e1, final Object e2) { this.e1 = e1; this.e2 = e2; } // ------------------------------------------------------------------------- // Implementation of inherited abstract methods // ------------------------------------------------------------------------- public Iterator iterator() { return new SmallSet(e1, e2); } public int size() { return e1 == null ? 0 : (e2 == null ? 1 : 2); } // ------------------------------------------------------------------------- // Implementation of the Iterator interface // ------------------------------------------------------------------------- public boolean hasNext() { return e1 != null; } public Object next() { Object e = e1; e1 = e2; e2 = null; return e; } public void remove() { } // ------------------------------------------------------------------------- // Utility methods // ------------------------------------------------------------------------- Set union(final SmallSet s) { if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) { return this; // if the two sets are equal, return this } if (s.e1 == null) { return this; // if s is empty, return this } if (e1 == null) { return s; // if this is empty, return s } if (s.e2 == null) { // s contains exactly one element if (e2 == null) { return new SmallSet(e1, s.e1); // necessarily e1 != s.e1 } else if (s.e1 == e1 || s.e1 == e2) { // s is included in this return this; } } if (e2 == null) { // this contains exactly one element // if (s.e2 == null) { // cannot happen // return new SmallSet(e1, s.e1); // necessarily e1 != s.e1 // } else if (e1 == s.e1 || e1 == s.e2) { // this in included in s return s; } } // here we know that there are at least 3 distinct elements HashSet r = new HashSet(4); r.add(e1); if (e2 != null) { r.add(e2); } r.add(s.e1); if (s.e2 != null) { r.add(s.e2); } return r; } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/Subroutine.java0000644000175000017500000000634610701747173024143 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; /** * A method subroutine (corresponds to a JSR instruction). * * @author Eric Bruneton */ class Subroutine { LabelNode start; boolean[] access; List callers; private Subroutine() { } Subroutine( final LabelNode start, final int maxLocals, final JumpInsnNode caller) { this.start = start; this.access = new boolean[maxLocals]; this.callers = new ArrayList(); callers.add(caller); } public Subroutine copy() { Subroutine result = new Subroutine(); result.start = start; result.access = new boolean[access.length]; System.arraycopy(access, 0, result.access, 0, access.length); result.callers = new ArrayList(callers); return result; } public boolean merge(final Subroutine subroutine) throws AnalyzerException { boolean changes = false; for (int i = 0; i < access.length; ++i) { if (subroutine.access[i] && !access[i]) { access[i] = true; changes = true; } } if (subroutine.start == start) { for (int i = 0; i < subroutine.callers.size(); ++i) { Object caller = subroutine.callers.get(i); if (!callers.contains(caller)) { callers.add(caller); changes = true; } } } return changes; } }asm-3.3.2/src/org/objectweb/asm/tree/analysis/Frame.java0000644000175000017500000006117311244244744023034 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MultiANewArrayInsnNode; import org.objectweb.asm.tree.VarInsnNode; /** * A symbolic execution stack frame. A stack frame contains a set of local * variable slots, and an operand stack. Warning: long and double values are * represented by two slots in local variables, and by one slot * in the operand stack. * * @author Eric Bruneton */ public class Frame { /** * The expected return type of the analyzed method, or null if the * method returns void. */ private Value returnValue; /** * The local variables and operand stack of this frame. */ private Value[] values; /** * The number of local variables of this frame. */ private int locals; /** * The number of elements in the operand stack. */ private int top; /** * Constructs a new frame with the given size. * * @param nLocals the maximum number of local variables of the frame. * @param nStack the maximum stack size of the frame. */ public Frame(final int nLocals, final int nStack) { this.values = new Value[nLocals + nStack]; this.locals = nLocals; } /** * Constructs a new frame that is identical to the given frame. * * @param src a frame. */ public Frame(final Frame src) { this(src.locals, src.values.length - src.locals); init(src); } /** * Copies the state of the given frame into this frame. * * @param src a frame. * @return this frame. */ public Frame init(final Frame src) { returnValue = src.returnValue; System.arraycopy(src.values, 0, values, 0, values.length); top = src.top; return this; } /** * Sets the expected return type of the analyzed method. * * @param v the expected return type of the analyzed method, or * null if the method returns void. */ public void setReturn(final Value v) { returnValue = v; } /** * Returns the maximum number of local variables of this frame. * * @return the maximum number of local variables of this frame. */ public int getLocals() { return locals; } /** * Returns the value of the given local variable. * * @param i a local variable index. * @return the value of the given local variable. * @throws IndexOutOfBoundsException if the variable does not exist. */ public Value getLocal(final int i) throws IndexOutOfBoundsException { if (i >= locals) { throw new IndexOutOfBoundsException("Trying to access an inexistant local variable"); } return values[i]; } /** * Sets the value of the given local variable. * * @param i a local variable index. * @param value the new value of this local variable. * @throws IndexOutOfBoundsException if the variable does not exist. */ public void setLocal(final int i, final Value value) throws IndexOutOfBoundsException { if (i >= locals) { throw new IndexOutOfBoundsException("Trying to access an inexistant local variable "+i); } values[i] = value; } /** * Returns the number of values in the operand stack of this frame. Long and * double values are treated as single values. * * @return the number of values in the operand stack of this frame. */ public int getStackSize() { return top; } /** * Returns the value of the given operand stack slot. * * @param i the index of an operand stack slot. * @return the value of the given operand stack slot. * @throws IndexOutOfBoundsException if the operand stack slot does not * exist. */ public Value getStack(final int i) throws IndexOutOfBoundsException { return values[i + locals]; } /** * Clears the operand stack of this frame. */ public void clearStack() { top = 0; } /** * Pops a value from the operand stack of this frame. * * @return the value that has been popped from the stack. * @throws IndexOutOfBoundsException if the operand stack is empty. */ public Value pop() throws IndexOutOfBoundsException { if (top == 0) { throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack."); } return values[--top + locals]; } /** * Pushes a value into the operand stack of this frame. * * @param value the value that must be pushed into the stack. * @throws IndexOutOfBoundsException if the operand stack is full. */ public void push(final Value value) throws IndexOutOfBoundsException { if (top + locals >= values.length) { throw new IndexOutOfBoundsException("Insufficient maximum stack size."); } values[top++ + locals] = value; } public void execute( final AbstractInsnNode insn, final Interpreter interpreter) throws AnalyzerException { Value value1, value2, value3, value4; List values; int var; switch (insn.getOpcode()) { case Opcodes.NOP: break; case Opcodes.ACONST_NULL: case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.BIPUSH: case Opcodes.SIPUSH: case Opcodes.LDC: push(interpreter.newOperation(insn)); break; case Opcodes.ILOAD: case Opcodes.LLOAD: case Opcodes.FLOAD: case Opcodes.DLOAD: case Opcodes.ALOAD: push(interpreter.copyOperation(insn, getLocal(((VarInsnNode) insn).var))); break; case Opcodes.IALOAD: case Opcodes.LALOAD: case Opcodes.FALOAD: case Opcodes.DALOAD: case Opcodes.AALOAD: case Opcodes.BALOAD: case Opcodes.CALOAD: case Opcodes.SALOAD: value2 = pop(); value1 = pop(); push(interpreter.binaryOperation(insn, value1, value2)); break; case Opcodes.ISTORE: case Opcodes.LSTORE: case Opcodes.FSTORE: case Opcodes.DSTORE: case Opcodes.ASTORE: value1 = interpreter.copyOperation(insn, pop()); var = ((VarInsnNode) insn).var; setLocal(var, value1); if (value1.getSize() == 2) { setLocal(var + 1, interpreter.newValue(null)); } if (var > 0) { Value local = getLocal(var - 1); if (local != null && local.getSize() == 2) { setLocal(var - 1, interpreter.newValue(null)); } } break; case Opcodes.IASTORE: case Opcodes.LASTORE: case Opcodes.FASTORE: case Opcodes.DASTORE: case Opcodes.AASTORE: case Opcodes.BASTORE: case Opcodes.CASTORE: case Opcodes.SASTORE: value3 = pop(); value2 = pop(); value1 = pop(); interpreter.ternaryOperation(insn, value1, value2, value3); break; case Opcodes.POP: if (pop().getSize() == 2) { throw new AnalyzerException(insn, "Illegal use of POP"); } break; case Opcodes.POP2: if (pop().getSize() == 1) { if (pop().getSize() != 1) { throw new AnalyzerException(insn, "Illegal use of POP2"); } } break; case Opcodes.DUP: value1 = pop(); if (value1.getSize() != 1) { throw new AnalyzerException(insn, "Illegal use of DUP"); } push(value1); push(interpreter.copyOperation(insn, value1)); break; case Opcodes.DUP_X1: value1 = pop(); value2 = pop(); if (value1.getSize() != 1 || value2.getSize() != 1) { throw new AnalyzerException(insn, "Illegal use of DUP_X1"); } push(interpreter.copyOperation(insn, value1)); push(value2); push(value1); break; case Opcodes.DUP_X2: value1 = pop(); if (value1.getSize() == 1) { value2 = pop(); if (value2.getSize() == 1) { value3 = pop(); if (value3.getSize() == 1) { push(interpreter.copyOperation(insn, value1)); push(value3); push(value2); push(value1); break; } } else { push(interpreter.copyOperation(insn, value1)); push(value2); push(value1); break; } } throw new AnalyzerException(insn, "Illegal use of DUP_X2"); case Opcodes.DUP2: value1 = pop(); if (value1.getSize() == 1) { value2 = pop(); if (value2.getSize() == 1) { push(value2); push(value1); push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); break; } } else { push(value1); push(interpreter.copyOperation(insn, value1)); break; } throw new AnalyzerException(insn, "Illegal use of DUP2"); case Opcodes.DUP2_X1: value1 = pop(); if (value1.getSize() == 1) { value2 = pop(); if (value2.getSize() == 1) { value3 = pop(); if (value3.getSize() == 1) { push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); push(value3); push(value2); push(value1); break; } } } else { value2 = pop(); if (value2.getSize() == 1) { push(interpreter.copyOperation(insn, value1)); push(value2); push(value1); break; } } throw new AnalyzerException(insn, "Illegal use of DUP2_X1"); case Opcodes.DUP2_X2: value1 = pop(); if (value1.getSize() == 1) { value2 = pop(); if (value2.getSize() == 1) { value3 = pop(); if (value3.getSize() == 1) { value4 = pop(); if (value4.getSize() == 1) { push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); push(value4); push(value3); push(value2); push(value1); break; } } else { push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); push(value3); push(value2); push(value1); break; } } } else { value2 = pop(); if (value2.getSize() == 1) { value3 = pop(); if (value3.getSize() == 1) { push(interpreter.copyOperation(insn, value1)); push(value3); push(value2); push(value1); break; } } else { push(interpreter.copyOperation(insn, value1)); push(value2); push(value1); break; } } throw new AnalyzerException(insn, "Illegal use of DUP2_X2"); case Opcodes.SWAP: value2 = pop(); value1 = pop(); if (value1.getSize() != 1 || value2.getSize() != 1) { throw new AnalyzerException(insn, "Illegal use of SWAP"); } push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); break; case Opcodes.IADD: case Opcodes.LADD: case Opcodes.FADD: case Opcodes.DADD: case Opcodes.ISUB: case Opcodes.LSUB: case Opcodes.FSUB: case Opcodes.DSUB: case Opcodes.IMUL: case Opcodes.LMUL: case Opcodes.FMUL: case Opcodes.DMUL: case Opcodes.IDIV: case Opcodes.LDIV: case Opcodes.FDIV: case Opcodes.DDIV: case Opcodes.IREM: case Opcodes.LREM: case Opcodes.FREM: case Opcodes.DREM: value2 = pop(); value1 = pop(); push(interpreter.binaryOperation(insn, value1, value2)); break; case Opcodes.INEG: case Opcodes.LNEG: case Opcodes.FNEG: case Opcodes.DNEG: push(interpreter.unaryOperation(insn, pop())); break; case Opcodes.ISHL: case Opcodes.LSHL: case Opcodes.ISHR: case Opcodes.LSHR: case Opcodes.IUSHR: case Opcodes.LUSHR: case Opcodes.IAND: case Opcodes.LAND: case Opcodes.IOR: case Opcodes.LOR: case Opcodes.IXOR: case Opcodes.LXOR: value2 = pop(); value1 = pop(); push(interpreter.binaryOperation(insn, value1, value2)); break; case Opcodes.IINC: var = ((IincInsnNode) insn).var; setLocal(var, interpreter.unaryOperation(insn, getLocal(var))); break; case Opcodes.I2L: case Opcodes.I2F: case Opcodes.I2D: case Opcodes.L2I: case Opcodes.L2F: case Opcodes.L2D: case Opcodes.F2I: case Opcodes.F2L: case Opcodes.F2D: case Opcodes.D2I: case Opcodes.D2L: case Opcodes.D2F: case Opcodes.I2B: case Opcodes.I2C: case Opcodes.I2S: push(interpreter.unaryOperation(insn, pop())); break; case Opcodes.LCMP: case Opcodes.FCMPL: case Opcodes.FCMPG: case Opcodes.DCMPL: case Opcodes.DCMPG: value2 = pop(); value1 = pop(); push(interpreter.binaryOperation(insn, value1, value2)); break; case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IFLE: interpreter.unaryOperation(insn, pop()); break; case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ICMPLE: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: value2 = pop(); value1 = pop(); interpreter.binaryOperation(insn, value1, value2); break; case Opcodes.GOTO: break; case Opcodes.JSR: push(interpreter.newOperation(insn)); break; case Opcodes.RET: break; case Opcodes.TABLESWITCH: case Opcodes.LOOKUPSWITCH: interpreter.unaryOperation(insn, pop()); break; case Opcodes.IRETURN: case Opcodes.LRETURN: case Opcodes.FRETURN: case Opcodes.DRETURN: case Opcodes.ARETURN: value1 = pop(); interpreter.unaryOperation(insn, value1); interpreter.returnOperation(insn, value1, returnValue); break; case Opcodes.RETURN: if (returnValue != null) { throw new AnalyzerException(insn, "Incompatible return type"); } break; case Opcodes.GETSTATIC: push(interpreter.newOperation(insn)); break; case Opcodes.PUTSTATIC: interpreter.unaryOperation(insn, pop()); break; case Opcodes.GETFIELD: push(interpreter.unaryOperation(insn, pop())); break; case Opcodes.PUTFIELD: value2 = pop(); value1 = pop(); interpreter.binaryOperation(insn, value1, value2); break; case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESTATIC: case Opcodes.INVOKEINTERFACE: case Opcodes.INVOKEDYNAMIC: values = new ArrayList(); String desc = ((MethodInsnNode) insn).desc; for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) { values.add(0, pop()); } if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) { values.add(0, pop()); } if (Type.getReturnType(desc) == Type.VOID_TYPE) { interpreter.naryOperation(insn, values); } else { push(interpreter.naryOperation(insn, values)); } break; case Opcodes.NEW: push(interpreter.newOperation(insn)); break; case Opcodes.NEWARRAY: case Opcodes.ANEWARRAY: case Opcodes.ARRAYLENGTH: push(interpreter.unaryOperation(insn, pop())); break; case Opcodes.ATHROW: interpreter.unaryOperation(insn, pop()); break; case Opcodes.CHECKCAST: case Opcodes.INSTANCEOF: push(interpreter.unaryOperation(insn, pop())); break; case Opcodes.MONITORENTER: case Opcodes.MONITOREXIT: interpreter.unaryOperation(insn, pop()); break; case Opcodes.MULTIANEWARRAY: values = new ArrayList(); for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) { values.add(0, pop()); } push(interpreter.naryOperation(insn, values)); break; case Opcodes.IFNULL: case Opcodes.IFNONNULL: interpreter.unaryOperation(insn, pop()); break; default: throw new RuntimeException("Illegal opcode "+insn.getOpcode()); } } /** * Merges this frame with the given frame. * * @param frame a frame. * @param interpreter the interpreter used to merge values. * @return true if this frame has been changed as a result of the * merge operation, or false otherwise. * @throws AnalyzerException if the frames have incompatible sizes. */ public boolean merge(final Frame frame, final Interpreter interpreter) throws AnalyzerException { if (top != frame.top) { throw new AnalyzerException(null, "Incompatible stack heights"); } boolean changes = false; for (int i = 0; i < locals + top; ++i) { Value v = interpreter.merge(values[i], frame.values[i]); if (v != values[i]) { values[i] = v; changes |= true; } } return changes; } /** * Merges this frame with the given frame (case of a RET instruction). * * @param frame a frame * @param access the local variables that have been accessed by the * subroutine to which the RET instruction corresponds. * @return true if this frame has been changed as a result of the * merge operation, or false otherwise. */ public boolean merge(final Frame frame, final boolean[] access) { boolean changes = false; for (int i = 0; i < locals; ++i) { if (!access[i] && !values[i].equals(frame.values[i])) { values[i] = frame.values[i]; changes = true; } } return changes; } /** * Returns a string representation of this frame. * * @return a string representation of this frame. */ public String toString() { StringBuffer b = new StringBuffer(); for (int i = 0; i < getLocals(); ++i) { b.append(getLocal(i)); } b.append(' '); for (int i = 0; i < getStackSize(); ++i) { b.append(getStack(i).toString()); } return b.toString(); } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/AnalyzerException.java0000644000175000017500000000503611244244744025442 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import org.objectweb.asm.tree.AbstractInsnNode; /** * Thrown if a problem occurs during the analysis of a method. * * @author Bing Ran * @author Eric Bruneton */ public class AnalyzerException extends Exception { public final AbstractInsnNode node; public AnalyzerException(final AbstractInsnNode node, final String msg) { super(msg); this.node = node; } public AnalyzerException(final AbstractInsnNode node, final String msg, final Throwable exception) { super(msg, exception); this.node = node; } public AnalyzerException( final AbstractInsnNode node, final String msg, final Object expected, final Value encountered) { super((msg == null ? "Expected " : msg + ": expected ") + expected + ", but found " + encountered); this.node = node; } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/Value.java0000644000175000017500000000365010635277351023055 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; /** * An immutable symbolic value for semantic interpretation of bytecode. * * @author Eric Bruneton */ public interface Value { /** * Returns the size of this value in words. * * @return either 1 or 2. */ int getSize(); } asm-3.3.2/src/org/objectweb/asm/tree/analysis/BasicVerifier.java0000644000175000017500000003654711355572170024526 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.MethodInsnNode; /** * An extended {@link BasicInterpreter} that checks that bytecode instructions * are correctly used. * * @author Eric Bruneton * @author Bing Ran */ public class BasicVerifier extends BasicInterpreter { public Value copyOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException { Value expected; switch (insn.getOpcode()) { case ILOAD: case ISTORE: expected = BasicValue.INT_VALUE; break; case FLOAD: case FSTORE: expected = BasicValue.FLOAT_VALUE; break; case LLOAD: case LSTORE: expected = BasicValue.LONG_VALUE; break; case DLOAD: case DSTORE: expected = BasicValue.DOUBLE_VALUE; break; case ALOAD: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(insn, null, "an object reference", value); } return value; case ASTORE: if (!((BasicValue) value).isReference() && !BasicValue.RETURNADDRESS_VALUE.equals(value)) { throw new AnalyzerException(insn, null, "an object reference or a return address", value); } return value; default: return value; } if (!expected.equals(value)) { throw new AnalyzerException(insn, null, expected, value); } return value; } public Value unaryOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException { Value expected; switch (insn.getOpcode()) { case INEG: case IINC: case I2F: case I2L: case I2D: case I2B: case I2C: case I2S: case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case NEWARRAY: case ANEWARRAY: expected = BasicValue.INT_VALUE; break; case FNEG: case F2I: case F2L: case F2D: case FRETURN: expected = BasicValue.FLOAT_VALUE; break; case LNEG: case L2I: case L2F: case L2D: case LRETURN: expected = BasicValue.LONG_VALUE; break; case DNEG: case D2I: case D2F: case D2L: case DRETURN: expected = BasicValue.DOUBLE_VALUE; break; case GETFIELD: expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner)); break; case CHECKCAST: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(insn, null, "an object reference", value); } return super.unaryOperation(insn, value); case ARRAYLENGTH: if (!isArrayValue(value)) { throw new AnalyzerException(insn, null, "an array reference", value); } return super.unaryOperation(insn, value); case ARETURN: case ATHROW: case INSTANCEOF: case MONITORENTER: case MONITOREXIT: case IFNULL: case IFNONNULL: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(insn, null, "an object reference", value); } return super.unaryOperation(insn, value); case PUTSTATIC: expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); break; default: throw new Error("Internal error."); } if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, null, expected, value); } return super.unaryOperation(insn, value); } public Value binaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2) throws AnalyzerException { Value expected1; Value expected2; switch (insn.getOpcode()) { case IALOAD: expected1 = newValue(Type.getType("[I")); expected2 = BasicValue.INT_VALUE; break; case BALOAD: if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { expected1 = newValue(Type.getType("[Z")); } else { expected1 = newValue(Type.getType("[B")); } expected2 = BasicValue.INT_VALUE; break; case CALOAD: expected1 = newValue(Type.getType("[C")); expected2 = BasicValue.INT_VALUE; break; case SALOAD: expected1 = newValue(Type.getType("[S")); expected2 = BasicValue.INT_VALUE; break; case LALOAD: expected1 = newValue(Type.getType("[J")); expected2 = BasicValue.INT_VALUE; break; case FALOAD: expected1 = newValue(Type.getType("[F")); expected2 = BasicValue.INT_VALUE; break; case DALOAD: expected1 = newValue(Type.getType("[D")); expected2 = BasicValue.INT_VALUE; break; case AALOAD: expected1 = newValue(Type.getType("[Ljava/lang/Object;")); expected2 = BasicValue.INT_VALUE; break; case IADD: case ISUB: case IMUL: case IDIV: case IREM: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case IXOR: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: expected1 = BasicValue.INT_VALUE; expected2 = BasicValue.INT_VALUE; break; case FADD: case FSUB: case FMUL: case FDIV: case FREM: case FCMPL: case FCMPG: expected1 = BasicValue.FLOAT_VALUE; expected2 = BasicValue.FLOAT_VALUE; break; case LADD: case LSUB: case LMUL: case LDIV: case LREM: case LAND: case LOR: case LXOR: case LCMP: expected1 = BasicValue.LONG_VALUE; expected2 = BasicValue.LONG_VALUE; break; case LSHL: case LSHR: case LUSHR: expected1 = BasicValue.LONG_VALUE; expected2 = BasicValue.INT_VALUE; break; case DADD: case DSUB: case DMUL: case DDIV: case DREM: case DCMPL: case DCMPG: expected1 = BasicValue.DOUBLE_VALUE; expected2 = BasicValue.DOUBLE_VALUE; break; case IF_ACMPEQ: case IF_ACMPNE: expected1 = BasicValue.REFERENCE_VALUE; expected2 = BasicValue.REFERENCE_VALUE; break; case PUTFIELD: FieldInsnNode fin = (FieldInsnNode) insn; expected1 = newValue(Type.getObjectType(fin.owner)); expected2 = newValue(Type.getType(fin.desc)); break; default: throw new Error("Internal error."); } if (!isSubTypeOf(value1, expected1)) { throw new AnalyzerException(insn, "First argument", expected1, value1); } else if (!isSubTypeOf(value2, expected2)) { throw new AnalyzerException(insn, "Second argument", expected2, value2); } if (insn.getOpcode() == AALOAD) { return getElementValue(value1); } else { return super.binaryOperation(insn, value1, value2); } } public Value ternaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2, final Value value3) throws AnalyzerException { Value expected1; Value expected3; switch (insn.getOpcode()) { case IASTORE: expected1 = newValue(Type.getType("[I")); expected3 = BasicValue.INT_VALUE; break; case BASTORE: if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { expected1 = newValue(Type.getType("[Z")); } else { expected1 = newValue(Type.getType("[B")); } expected3 = BasicValue.INT_VALUE; break; case CASTORE: expected1 = newValue(Type.getType("[C")); expected3 = BasicValue.INT_VALUE; break; case SASTORE: expected1 = newValue(Type.getType("[S")); expected3 = BasicValue.INT_VALUE; break; case LASTORE: expected1 = newValue(Type.getType("[J")); expected3 = BasicValue.LONG_VALUE; break; case FASTORE: expected1 = newValue(Type.getType("[F")); expected3 = BasicValue.FLOAT_VALUE; break; case DASTORE: expected1 = newValue(Type.getType("[D")); expected3 = BasicValue.DOUBLE_VALUE; break; case AASTORE: expected1 = value1; expected3 = BasicValue.REFERENCE_VALUE; break; default: throw new Error("Internal error."); } if (!isSubTypeOf(value1, expected1)) { throw new AnalyzerException(insn, "First argument", "a " + expected1 + " array reference", value1); } else if (!BasicValue.INT_VALUE.equals(value2)) { throw new AnalyzerException(insn, "Second argument", BasicValue.INT_VALUE, value2); } else if (!isSubTypeOf(value3, expected3)) { throw new AnalyzerException(insn, "Third argument", expected3, value3); } return null; } public Value naryOperation(final AbstractInsnNode insn, final List values) throws AnalyzerException { int opcode = insn.getOpcode(); if (opcode == MULTIANEWARRAY) { for (int i = 0; i < values.size(); ++i) { if (!BasicValue.INT_VALUE.equals(values.get(i))) { throw new AnalyzerException(insn, null, BasicValue.INT_VALUE, (Value) values.get(i)); } } } else { int i = 0; int j = 0; if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { Type owner = Type.getObjectType(((MethodInsnNode) insn).owner); if (!isSubTypeOf((Value) values.get(i++), newValue(owner))) { throw new AnalyzerException(insn, "Method owner", newValue(owner), (Value) values.get(0)); } } Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc); while (i < values.size()) { Value expected = newValue(args[j++]); Value encountered = (Value) values.get(i++); if (!isSubTypeOf(encountered, expected)) { throw new AnalyzerException(insn, "Argument " + j, expected, encountered); } } } return super.naryOperation(insn, values); } public void returnOperation( final AbstractInsnNode insn, final Value value, final Value expected) throws AnalyzerException { if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, "Incompatible return type", expected, value); } } protected boolean isArrayValue(final Value value) { return ((BasicValue) value).isReference(); } protected Value getElementValue(final Value objectArrayValue) throws AnalyzerException { return BasicValue.REFERENCE_VALUE; } protected boolean isSubTypeOf(final Value value, final Value expected) { return value.equals(expected); } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/SourceValue.java0000644000175000017500000000627010701747173024235 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.Set; import org.objectweb.asm.tree.AbstractInsnNode; /** * A {@link Value} that is represented by its type in a two types type system. * This type system distinguishes the ONEWORD and TWOWORDS types. * * @author Eric Bruneton */ public class SourceValue implements Value { /** * The size of this value. */ public final int size; /** * The instructions that can produce this value. For example, for the Java * code below, the instructions that can produce the value of i * at line 5 are the txo ISTORE instructions at line 1 and 3: * *
     * 1: i = 0;
     * 2: if (...) {
     * 3:   i = 1;
     * 4: }
     * 5: return i;
     * 
* * This field is a set of {@link AbstractInsnNode} objects. */ public final Set insns; public SourceValue(final int size) { this(size, SmallSet.EMPTY_SET); } public SourceValue(final int size, final AbstractInsnNode insn) { this.size = size; this.insns = new SmallSet(insn, null); } public SourceValue(final int size, final Set insns) { this.size = size; this.insns = insns; } public int getSize() { return size; } public boolean equals(final Object value) { if (!(value instanceof SourceValue)) { return false; } SourceValue v = (SourceValue) value; return size == v.size && insns.equals(v.insns); } public int hashCode() { return insns.hashCode(); } } asm-3.3.2/src/org/objectweb/asm/tree/analysis/Interpreter.java0000644000175000017500000002146411052514571024277 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; /** * A semantic bytecode interpreter. More precisely, this interpreter only * manages the computation of values from other values: it does not manage the * transfer of values to or from the stack, and to or from the local variables. * This separation allows a generic bytecode {@link Analyzer} to work with * various semantic interpreters, without needing to duplicate the code to * simulate the transfer of values. * * @author Eric Bruneton */ public interface Interpreter { /** * Creates a new value that represents the given type. * * Called for method parameters (including this), * exception handler variable and with null type * for variables reserved by long and double types. * * @param type a primitive or reference type, or null to * represent an uninitialized value. * @return a value that represents the given type. The size of the returned * value must be equal to the size of the given type. */ Value newValue(Type type); /** * Interprets a bytecode instruction without arguments. This method is * called for the following opcodes: * * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, * ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, * DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW * * @param insn the bytecode instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException if an error occured during the interpretation. */ Value newOperation(AbstractInsnNode insn) throws AnalyzerException; /** * Interprets a bytecode instruction that moves a value on the stack or to * or from local variables. This method is called for the following opcodes: * * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, * ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP * * @param insn the bytecode instruction to be interpreted. * @param value the value that must be moved by the instruction. * @return the result of the interpretation of the given instruction. The * returned value must be equal to the given value. * @throws AnalyzerException if an error occured during the interpretation. */ Value copyOperation(AbstractInsnNode insn, Value value) throws AnalyzerException; /** * Interprets a bytecode instruction with a single argument. This method is * called for the following opcodes: * * INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, * F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, * TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, * PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST, * INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL * * @param insn the bytecode instruction to be interpreted. * @param value the argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException if an error occured during the interpretation. */ Value unaryOperation(AbstractInsnNode insn, Value value) throws AnalyzerException; /** * Interprets a bytecode instruction with two arguments. This method is * called for the following opcodes: * * IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD, * LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR, * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL, * DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, * IF_ACMPEQ, IF_ACMPNE, PUTFIELD * * @param insn the bytecode instruction to be interpreted. * @param value1 the first argument of the instruction to be interpreted. * @param value2 the second argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException if an error occured during the interpretation. */ Value binaryOperation(AbstractInsnNode insn, Value value1, Value value2) throws AnalyzerException; /** * Interprets a bytecode instruction with three arguments. This method is * called for the following opcodes: * * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE * * @param insn the bytecode instruction to be interpreted. * @param value1 the first argument of the instruction to be interpreted. * @param value2 the second argument of the instruction to be interpreted. * @param value3 the third argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException if an error occured during the interpretation. */ Value ternaryOperation( AbstractInsnNode insn, Value value1, Value value2, Value value3) throws AnalyzerException; /** * Interprets a bytecode instruction with a variable number of arguments. * This method is called for the following opcodes: * * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, * MULTIANEWARRAY * * @param insn the bytecode instruction to be interpreted. * @param values the arguments of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException if an error occured during the interpretation. */ Value naryOperation(AbstractInsnNode insn, List values) throws AnalyzerException; /** * Interprets a bytecode return instruction. This method is called for the * following opcodes: * * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN * * @param insn the bytecode instruction to be interpreted. * @param value the argument of the instruction to be interpreted. * @param expected the expected return type of the analyzed method. * @throws AnalyzerException if an error occured during the interpretation. */ void returnOperation(AbstractInsnNode insn, Value value, Value expected) throws AnalyzerException; /** * Merges two values. The merge operation must return a value that * represents both values (for instance, if the two values are two types, * the merged value must be a common super type of the two types. If the two * values are integer intervals, the merged value must be an interval that * contains the previous ones. Likewise for other types of values). * * @param v a value. * @param w another value. * @return the merged value. If the merged value is equal to v, * this method must return v. */ Value merge(Value v, Value w); } asm-3.3.2/src/org/objectweb/asm/tree/analysis/SimpleVerifier.java0000644000175000017500000002547311434755347024741 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import org.objectweb.asm.Type; /** * An extended {@link BasicVerifier} that performs more precise verifications. * This verifier computes exact class types, instead of using a single "object * reference" type (as done in the {@link BasicVerifier}). * * @author Eric Bruneton * @author Bing Ran */ public class SimpleVerifier extends BasicVerifier { /** * The class that is verified. */ private final Type currentClass; /** * The super class of the class that is verified. */ private final Type currentSuperClass; /** * The interfaces implemented by the class that is verified. */ private final List currentClassInterfaces; /** * If the class that is verified is an interface. */ private final boolean isInterface; /** * The loader to use for referenced classes. */ private ClassLoader loader = getClass().getClassLoader(); /** * Constructs a new {@link SimpleVerifier}. */ public SimpleVerifier() { this(null, null, false); } /** * Constructs a new {@link SimpleVerifier} to verify a specific class. This * class will not be loaded into the JVM since it may be incorrect. * * @param currentClass the class that is verified. * @param currentSuperClass the super class of the class that is verified. * @param isInterface if the class that is verified is an interface. */ public SimpleVerifier( final Type currentClass, final Type currentSuperClass, final boolean isInterface) { this(currentClass, currentSuperClass, null, isInterface); } /** * Constructs a new {@link SimpleVerifier} to verify a specific class. This * class will not be loaded into the JVM since it may be incorrect. * * @param currentClass the class that is verified. * @param currentSuperClass the super class of the class that is verified. * @param currentClassInterfaces the interfaces implemented by the class * that is verified. * @param isInterface if the class that is verified is an interface. */ public SimpleVerifier( final Type currentClass, final Type currentSuperClass, final List currentClassInterfaces, final boolean isInterface) { this.currentClass = currentClass; this.currentSuperClass = currentSuperClass; this.currentClassInterfaces = currentClassInterfaces; this.isInterface = isInterface; } /** * Set the ClassLoader which will be used to load referenced * classes. This is useful if you are verifying multiple interdependent * classes. * * @param loader a ClassLoader to use */ public void setClassLoader(final ClassLoader loader) { this.loader = loader; } public Value newValue(final Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } boolean isArray = type.getSort() == Type.ARRAY; if (isArray) { switch (type.getElementType().getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: return new BasicValue(type); } } Value v = super.newValue(type); if (BasicValue.REFERENCE_VALUE.equals(v)) { if (isArray) { v = newValue(type.getElementType()); String desc = ((BasicValue) v).getType().getDescriptor(); for (int i = 0; i < type.getDimensions(); ++i) { desc = '[' + desc; } v = new BasicValue(Type.getType(desc)); } else { v = new BasicValue(type); } } return v; } protected boolean isArrayValue(final Value value) { Type t = ((BasicValue) value).getType(); return t != null && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY); } protected Value getElementValue(final Value objectArrayValue) throws AnalyzerException { Type arrayType = ((BasicValue) objectArrayValue).getType(); if (arrayType != null) { if (arrayType.getSort() == Type.ARRAY) { return newValue(Type.getType(arrayType.getDescriptor() .substring(1))); } else if ("Lnull;".equals(arrayType.getDescriptor())) { return objectArrayValue; } } throw new Error("Internal error"); } protected boolean isSubTypeOf(final Value value, final Value expected) { Type expectedType = ((BasicValue) expected).getType(); Type type = ((BasicValue) value).getType(); switch (expectedType.getSort()) { case Type.INT: case Type.FLOAT: case Type.LONG: case Type.DOUBLE: return type.equals(expectedType); case Type.ARRAY: case Type.OBJECT: if ("Lnull;".equals(type.getDescriptor())) { return true; } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { return isAssignableFrom(expectedType, type); } else { return false; } default: throw new Error("Internal error"); } } public Value merge(final Value v, final Value w) { if (!v.equals(w)) { Type t = ((BasicValue) v).getType(); Type u = ((BasicValue) w).getType(); if (t != null && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) { if (u != null && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) { if ("Lnull;".equals(t.getDescriptor())) { return w; } if ("Lnull;".equals(u.getDescriptor())) { return v; } if (isAssignableFrom(t, u)) { return v; } if (isAssignableFrom(u, t)) { return w; } // TODO case of array classes of the same dimension // TODO should we look also for a common super interface? // problem: there may be several possible common super // interfaces do { if (t == null || isInterface(t)) { return BasicValue.REFERENCE_VALUE; } t = getSuperClass(t); if (isAssignableFrom(t, u)) { return newValue(t); } } while (true); } } return BasicValue.UNINITIALIZED_VALUE; } return v; } protected boolean isInterface(final Type t) { if (currentClass != null && t.equals(currentClass)) { return isInterface; } return getClass(t).isInterface(); } protected Type getSuperClass(final Type t) { if (currentClass != null && t.equals(currentClass)) { return currentSuperClass; } Class c = getClass(t).getSuperclass(); return c == null ? null : Type.getType(c); } protected boolean isAssignableFrom(final Type t, final Type u) { if (t.equals(u)) { return true; } if (currentClass != null && t.equals(currentClass)) { if (getSuperClass(u) == null) { return false; } else { if (isInterface) { return u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY; } return isAssignableFrom(t, getSuperClass(u)); } } if (currentClass != null && u.equals(currentClass)) { if (isAssignableFrom(t, currentSuperClass)) { return true; } if (currentClassInterfaces != null) { for (int i = 0; i < currentClassInterfaces.size(); ++i) { Type v = (Type) currentClassInterfaces.get(i); if (isAssignableFrom(t, v)) { return true; } } } return false; } Class tc = getClass(t); if (tc.isInterface()) { tc = Object.class; } return tc.isAssignableFrom(getClass(u)); } protected Class getClass(final Type t) { try { if (t.getSort() == Type.ARRAY) { return Class.forName(t.getDescriptor().replace('/', '.'), false, loader); } return Class.forName(t.getClassName(), false, loader); } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } } } asm-3.3.2/src/org/objectweb/asm/tree/VarInsnNode.java0000644000175000017500000000626510635277351022351 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a local variable instruction. A local variable * instruction is an instruction that loads or stores the value of a local * variable. * * @author Eric Bruneton */ public class VarInsnNode extends AbstractInsnNode { /** * The operand of this instruction. This operand is the index of a local * variable. */ public int var; /** * Constructs a new {@link VarInsnNode}. * * @param opcode the opcode of the local variable instruction to be * constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD, * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. * @param var the operand of the instruction to be constructed. This operand * is the index of a local variable. */ public VarInsnNode(final int opcode, final int var) { super(opcode); this.var = var; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be ILOAD, * LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE * or RET. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return VAR_INSN; } public void accept(final MethodVisitor mv) { mv.visitVarInsn(opcode, var); } public AbstractInsnNode clone(final Map labels) { return new VarInsnNode(opcode, var); } }asm-3.3.2/src/org/objectweb/asm/tree/LineNumberNode.java0000644000175000017500000000560510635277351023026 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a line number declaration. These nodes are pseudo * instruction nodes in order to be inserted in an instruction list. * * @author Eric Bruneton */ public class LineNumberNode extends AbstractInsnNode { /** * A line number. This number refers to the source file from which the class * was compiled. */ public int line; /** * The first instruction corresponding to this line number. */ public LabelNode start; /** * Constructs a new {@link LineNumberNode}. * * @param line a line number. This number refers to the source file from * which the class was compiled. * @param start the first instruction corresponding to this line number. */ public LineNumberNode(final int line, final LabelNode start) { super(-1); this.line = line; this.start = start; } public int getType() { return LINE; } public void accept(final MethodVisitor mv) { mv.visitLineNumber(line, start.getLabel()); } public AbstractInsnNode clone(final Map labels) { return new LineNumberNode(line, clone(start, labels)); } } asm-3.3.2/src/org/objectweb/asm/tree/LabelNode.java0000644000175000017500000000474310635277351022007 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * An {@link AbstractInsnNode} that encapsulates a {@link Label}. */ public class LabelNode extends AbstractInsnNode { private Label label; public LabelNode() { super(-1); } public LabelNode(final Label label) { super(-1); this.label = label; } public int getType() { return LABEL; } public Label getLabel() { if (label == null) { label = new Label(); } return label; } public void accept(final MethodVisitor cv) { cv.visitLabel(getLabel()); } public AbstractInsnNode clone(final Map labels) { return (LabelNode) labels.get(this); } public void resetLabel() { label = null; } }asm-3.3.2/src/org/objectweb/asm/tree/IincInsnNode.java0000644000175000017500000000523410635277351022476 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A node that represents an IINC instruction. * * @author Eric Bruneton */ public class IincInsnNode extends AbstractInsnNode { /** * Index of the local variable to be incremented. */ public int var; /** * Amount to increment the local variable by. */ public int incr; /** * Constructs a new {@link IincInsnNode}. * * @param var index of the local variable to be incremented. * @param incr increment amount to increment the local variable by. */ public IincInsnNode(final int var, final int incr) { super(Opcodes.IINC); this.var = var; this.incr = incr; } public int getType() { return IINC_INSN; } public void accept(final MethodVisitor mv) { mv.visitIincInsn(var, incr); } public AbstractInsnNode clone(final Map labels) { return new IincInsnNode(var, incr); } }asm-3.3.2/src/org/objectweb/asm/tree/InsnList.java0000644000175000017500000005035511224532001021702 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.ListIterator; import java.util.NoSuchElementException; import org.objectweb.asm.MethodVisitor; /** * A doubly linked list of {@link AbstractInsnNode} objects. This * implementation is not thread safe. */ public class InsnList { /** * Indicates if preconditions of methods of this class must be checked. * Checking preconditions causes the {@link #indexOf indexOf}, * {@link #set set}, {@link #insert(AbstractInsnNode, AbstractInsnNode)}, * {@link #insert(AbstractInsnNode, InsnList)}, {@link #remove remove} and * {@link #clear} methods to execute in O(n) time instead of O(1). */ public static boolean check; /** * The number of instructions in this list. */ private int size; /** * The first instruction in this list. May be null. */ private AbstractInsnNode first; /** * The last instruction in this list. May be null. */ private AbstractInsnNode last; /** * A cache of the instructions of this list. This cache is used to improve * the performance of the {@link #get} method. */ AbstractInsnNode[] cache; /** * Returns the number of instructions in this list. * * @return the number of instructions in this list. */ public int size() { return size; } /** * Returns the first instruction in this list. * * @return the first instruction in this list, or null if the * list is empty. */ public AbstractInsnNode getFirst() { return first; } /** * Returns the last instruction in this list. * * @return the last instruction in this list, or null if the list * is empty. */ public AbstractInsnNode getLast() { return last; } /** * Returns the instruction whose index is given. This method builds a cache * of the instructions in this list to avoid scanning the whole list each * time it is called. Once the cache is built, this method run in constant * time. This cache is invalidated by all the methods that modify the list. * * @param index the index of the instruction that must be returned. * @return the instruction whose index is given. * @throws IndexOutOfBoundsException if (index < 0 || index >= size()). */ public AbstractInsnNode get(final int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); } if (cache == null) { cache = toArray(); } return cache[index]; } /** * Returns true if the given instruction belongs to this list. * This method always scans the instructions of this list until it finds the * given instruction or reaches the end of the list. * * @param insn an instruction. * @return true if the given instruction belongs to this list. */ public boolean contains(final AbstractInsnNode insn) { AbstractInsnNode i = first; while (i != null && i != insn) { i = i.next; } return i != null; } /** * Returns the index of the given instruction in this list. This method * builds a cache of the instruction indexes to avoid scanning the whole * list each time it is called. Once the cache is built, this method run in * constant time. The cache is invalidated by all the methods that modify * the list. * * @param insn an instruction of this list. * @return the index of the given instruction in this list. The result of * this method is undefined if the given instruction does not belong * to this list. Use {@link #contains contains} to test if an * instruction belongs to an instruction list or not. * @throws IllegalArgumentException if {@link #check} is true and * if insn does not belong to this list. */ public int indexOf(final AbstractInsnNode insn) { if (check && !contains(insn)) { throw new IllegalArgumentException(); } if (cache == null) { cache = toArray(); } return insn.index; } /** * Makes the given visitor visit all of the instructions in this list. * * @param mv the method visitor that must visit the instructions. */ public void accept(final MethodVisitor mv) { AbstractInsnNode insn = first; while (insn != null) { insn.accept(mv); insn = insn.next; } } /** * Returns an iterator over the instructions in this list. * * @return an iterator over the instructions in this list. */ public ListIterator iterator() { return iterator(0); } /** * Returns an iterator over the instructions in this list. * * @return an iterator over the instructions in this list. */ public ListIterator iterator(int index) { return new InsnListIterator(index); } /** * Returns an array containing all of the instructions in this list. * * @return an array containing all of the instructions in this list. */ public AbstractInsnNode[] toArray() { int i = 0; AbstractInsnNode elem = first; AbstractInsnNode[] insns = new AbstractInsnNode[size]; while (elem != null) { insns[i] = elem; elem.index = i++; elem = elem.next; } return insns; } /** * Replaces an instruction of this list with another instruction. * * @param location an instruction of this list. * @param insn another instruction, which must not belong to any * {@link InsnList}. * @throws IllegalArgumentException if {@link #check} is true, * and if i does not belong to this list or if insn belongs to an * instruction list. */ public void set(final AbstractInsnNode location, final AbstractInsnNode insn) { if (check && !(contains(location) && insn.index == -1)) { throw new IllegalArgumentException(); } AbstractInsnNode next = location.next; insn.next = next; if (next != null) { next.prev = insn; } else { last = insn; } AbstractInsnNode prev = location.prev; insn.prev = prev; if (prev != null) { prev.next = insn; } else { first = insn; } if (cache != null) { int index = location.index; cache[index] = insn; insn.index = index; } else { insn.index = 0; // insn now belongs to an InsnList } location.index = -1; // i no longer belongs to an InsnList location.prev = null; location.next = null; } /** * Adds the given instruction to the end of this list. * * @param insn an instruction, which must not belong to any * {@link InsnList}. * @throws IllegalArgumentException if {@link #check} is true, * and if insn belongs to an instruction list. */ public void add(final AbstractInsnNode insn) { if (check && insn.index != -1) { throw new IllegalArgumentException(); } ++size; if (last == null) { first = insn; last = insn; } else { last.next = insn; insn.prev = last; } last = insn; cache = null; insn.index = 0; // insn now belongs to an InsnList } /** * Adds the given instructions to the end of this list. * * @param insns an instruction list, which is cleared during the process. * @throws IllegalArgumentException if {@link #check} is true, * and if insn == this. */ public void add(final InsnList insns) { if (check && insns == this) { throw new IllegalArgumentException(); } if (insns.size == 0) { return; } size += insns.size; if (last == null) { first = insns.first; last = insns.last; } else { AbstractInsnNode elem = insns.first; last.next = elem; elem.prev = last; last = insns.last; } cache = null; insns.removeAll(false); } /** * Inserts the given instruction at the begining of this list. * * @param insn an instruction, which must not belong to any * {@link InsnList}. * @throws IllegalArgumentException if {@link #check} is true, * and if insn belongs to an instruction list. */ public void insert(final AbstractInsnNode insn) { if (check && insn.index != -1) { throw new IllegalArgumentException(); } ++size; if (first == null) { first = insn; last = insn; } else { first.prev = insn; insn.next = first; } first = insn; cache = null; insn.index = 0; // insn now belongs to an InsnList } /** * Inserts the given instructions at the begining of this list. * * @param insns an instruction list, which is cleared during the process. * @throws IllegalArgumentException if {@link #check} is true, * and if insn == this. */ public void insert(final InsnList insns) { if (check && insns == this) { throw new IllegalArgumentException(); } if (insns.size == 0) { return; } size += insns.size; if (first == null) { first = insns.first; last = insns.last; } else { AbstractInsnNode elem = insns.last; first.prev = elem; elem.next = first; first = insns.first; } cache = null; insns.removeAll(false); } /** * Inserts the given instruction after the specified instruction. * * @param location an instruction of this list after which insn must be * inserted. * @param insn the instruction to be inserted, which must not belong to * any {@link InsnList}. * @throws IllegalArgumentException if {@link #check} is true, * and if i does not belong to this list or if insn belongs to an * instruction list. */ public void insert(final AbstractInsnNode location, final AbstractInsnNode insn) { if (check && !(contains(location) && insn.index == -1)) { throw new IllegalArgumentException(); } ++size; AbstractInsnNode next = location.next; if (next == null) { last = insn; } else { next.prev = insn; } location.next = insn; insn.next = next; insn.prev = location; cache = null; insn.index = 0; // insn now belongs to an InsnList } /** * Inserts the given instructions after the specified instruction. * * @param location an instruction of this list after which the instructions * must be inserted. * @param insns the instruction list to be inserted, which is cleared during * the process. * @throws IllegalArgumentException if {@link #check} is true, * and if i does not belong to this list or if insns == this. */ public void insert(final AbstractInsnNode location, final InsnList insns) { if (check && !(contains(location) && insns != this)) { throw new IllegalArgumentException(); } if (insns.size == 0) { return; } size += insns.size; AbstractInsnNode ifirst = insns.first; AbstractInsnNode ilast = insns.last; AbstractInsnNode next = location.next; if (next == null) { last = ilast; } else { next.prev = ilast; } location.next = ifirst; ilast.next = next; ifirst.prev = location; cache = null; insns.removeAll(false); } /** * Inserts the given instruction before the specified instruction. * * @param location an instruction of this list before which insn must be * inserted. * @param insn the instruction to be inserted, which must not belong to * any {@link InsnList}. * @throws IllegalArgumentException if {@link #check} is true, * and if i does not belong to this list or if insn belongs to an * instruction list. */ public void insertBefore(final AbstractInsnNode location, final AbstractInsnNode insn) { if (check && !(contains(location) && insn.index == -1)) { throw new IllegalArgumentException(); } ++size; AbstractInsnNode prev = location.prev; if (prev == null) { first = insn; } else { prev.next = insn; } location.prev = insn; insn.next = location; insn.prev = prev; cache = null; insn.index = 0; // insn now belongs to an InsnList } /** * Inserts the given instructions before the specified instruction. * * @param location an instruction of this list before which the instructions * must be inserted. * @param insns the instruction list to be inserted, which is cleared during * the process. * @throws IllegalArgumentException if {@link #check} is true, * and if i does not belong to this list or if insns == this. */ public void insertBefore(final AbstractInsnNode location, final InsnList insns) { if (check && !(contains(location ) && insns != this)) { throw new IllegalArgumentException(); } if (insns.size == 0) { return; } size += insns.size; AbstractInsnNode ifirst = insns.first; AbstractInsnNode ilast = insns.last; AbstractInsnNode prev = location .prev; if (prev == null) { first = ifirst; } else { prev.next = ifirst; } location .prev = ilast; ilast.next = location ; ifirst.prev = prev; cache = null; insns.removeAll(false); } /** * Removes the given instruction from this list. * * @param insn the instruction of this list that must be removed. * @throws IllegalArgumentException if {@link #check} is true, * and if insn does not belong to this list. */ public void remove(final AbstractInsnNode insn) { if (check && !contains(insn)) { throw new IllegalArgumentException(); } --size; AbstractInsnNode next = insn.next; AbstractInsnNode prev = insn.prev; if (next == null) { if (prev == null) { first = null; last = null; } else { prev.next = null; last = prev; } } else { if (prev == null) { first = next; next.prev = null; } else { prev.next = next; next.prev = prev; } } cache = null; insn.index = -1; // insn no longer belongs to an InsnList insn.prev = null; insn.next = null; } /** * Removes all of the instructions of this list. * * @param mark if the instructions must be marked as no longer belonging to * any {@link InsnList}. */ private void removeAll(final boolean mark) { if (mark) { AbstractInsnNode insn = first; while (insn != null) { AbstractInsnNode next = insn.next; insn.index = -1; // insn no longer belongs to an InsnList insn.prev = null; insn.next = null; insn = next; } } size = 0; first = null; last = null; cache = null; } /** * Removes all of the instructions of this list. */ public void clear() { removeAll(check); } /** * Reset all labels in the instruction list. This method should be called * before reusing same instructions list between several * ClassWriters. */ public void resetLabels() { AbstractInsnNode insn = first; while (insn != null) { if (insn instanceof LabelNode) { ((LabelNode) insn).resetLabel(); } insn = insn.next; } } private final class InsnListIterator implements ListIterator { AbstractInsnNode next; AbstractInsnNode prev; InsnListIterator(int index) { if(index==size()) { next = null; prev = getLast(); } else { next = get(index); prev = next.prev; } } public boolean hasNext() { return next != null; } public Object next() { if (next == null) { throw new NoSuchElementException(); } AbstractInsnNode result = next; prev = result; next = result.next; return result; } public void remove() { InsnList.this.remove(prev); prev = prev.prev; } public boolean hasPrevious() { return prev != null; } public Object previous() { AbstractInsnNode result = prev; next = result; prev = result.prev; return result; } public int nextIndex() { if (next == null) { return size(); } if (cache == null) { cache = toArray(); } return next.index; } public int previousIndex() { if (prev == null) { return -1; } if (cache == null) { cache = toArray(); } return prev.index; } public void add(Object o) { InsnList.this.insertBefore(next, (AbstractInsnNode) o); prev = (AbstractInsnNode) o; } public void set(Object o) { InsnList.this.set(next.prev, (AbstractInsnNode) o); prev = (AbstractInsnNode) o; } } } asm-3.3.2/src/org/objectweb/asm/tree/package.html0000644000175000017500000001436610507566514021602 0ustar twernertwerner

Provides an ASM visitor that constructs a tree representation of the classes it visits. This class adapter can be useful to implement "complex" class manipulation operations, i.e., operations that would be very hard to implement without using a tree representation (such as optimizing the number of local variables used by a method).

However, this class adapter has a cost: it makes ASM bigger and slower. Indeed it requires more than twenty new classes, and multiplies the time needed to transform a class by almost two (it is almost two times faster to read, "modify" and write a class with a ClassAdapter than with a ClassNode). This is why this package is bundled in an optional asm-tree.jar library that is separated from (but requires) the asm.jar library, which contains the core ASM framework. This is also why it is recommended not to use this class adapter when it is possible.

The root class is the ClassNode, that can be created from existing bytecode. For example:

  ClassReader cr = new ClassReader(source);
  ClassNode cn = new ClassNode();
  cr.accept(cn, true);

Now content of ClassNode can be modified and then serialized back into bytecode:

  ClassWriter cw = new ClassWriter(true);
  cn.accept(cw);

Using simple ClassAdapter it is possible to create MethodNode instances per-method. In this example MethodNode is acting as a buffer that is flushed out at visitEnd() call:

  ClassReader cr = new ClassReader(source);
  ClassWriter cw = new ClassWriter();
  ClassAdapter ca = new ClassAdapter(cw) {
      public MethodVisitor visitMethod(int access, String name, 
          String desc, String signature, String[] exceptions) {
        final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
        MethodNode mn = new MethodNode(access, name, desc, signature, exceptions) {
            public void visitEnd() {
              // transform or analyze method code using tree API
              accept(mv);
            }
          };
      }
    };
  cr.accept(ca, true);

Several strategies can be used to construct method code from scratch. The first option is to create a MethodNode, and then create XXXInsnNode instances and add them to the instructions list:

MethodNode m = new MethodNode(...);
m.instructions.add(new VarInsnNode(ALOAD, 0));
...

Alternatively, you can use the fact that MethodNode is a MethodVisitor, and use that to create the XXXInsnNode and add them to the instructions list through the standard MethodVisitor interface:

MethodNode m = new MethodNode(...);
m.visitVarInsn(ALOAD, 0);
...

If you cannot generate all the instructions in sequential order, i.e. if you need to save some pointer in the instruction list and then insert instructions at that place after other instructions have been generated, you can use InsnList methods insert() and insertBefore() to insert instructions at saved pointer.

MethodNode m = new MethodNode(...);
m.visitVarInsn(ALOAD, 0);
AbstractInsnNode ptr = m.instructions.getLast();
m.visitVarInsn(ALOAD, 1);
// inserts an instruction between ALOAD 0 and ALOAD 1
m.instructions.insert(ptr, new VarInsnNode(ALOAD, 0));
...

If you need to insert instructions while iterating over an existing instruction list, you can also use several strategies. The first one is to use a ListIterator over the instruction list:

ListIterator it = m.instructions.iterator();
while (it.hasNext()) {
    AbstractInsnNode n = (AbstractInsnNode) it.next();
    if (...) {
        it.add(new VarInsnNode(ALOAD, 0));
    }
}

It is also possible to convert instruction list into the array and iterate trough array elements:

AbstractInsnNode[] insns = m.instructions.toArray();
for(int i = 0; i<insns.length; i++) {
    AbstractInsnNode n = insns[i];
    if (...) {
        m.instructions.insert(n, new VarInsnNode(ALOAD, 0));
    }
}

If you want to insert these instructions through the MethodVisitor interface, you can use another instance of MethodNode as a MethodVisitor and then insert instructions collected by that instance into the instruction list. For example:

AbstractInsnNode[] insns = m.instructions.toArray();
for(int i = 0; i<insns.length; i++) {
    AbstractInsnNode n = insns[i];
    if (...) {
        MethodNode mn = new MethodNode();
        mn.visitVarInsn(ALOAD, 0);
        mn.visitVarInsn(ALOAD, 1);
        m.instructions.insert(n, mn.instructions);
    }
}

@since ASM 1.3.3

asm-3.3.2/src/org/objectweb/asm/tree/LookupSwitchInsnNode.java0000644000175000017500000001003110635277351024236 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.MethodVisitor; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; /** * A node that represents a LOOKUPSWITCH instruction. * * @author Eric Bruneton */ public class LookupSwitchInsnNode extends AbstractInsnNode { /** * Beginning of the default handler block. */ public LabelNode dflt; /** * The values of the keys. This list is a list of {@link Integer} objects. */ public List keys; /** * Beginnings of the handler blocks. This list is a list of * {@link LabelNode} objects. */ public List labels; /** * Constructs a new {@link LookupSwitchInsnNode}. * * @param dflt beginning of the default handler block. * @param keys the values of the keys. * @param labels beginnings of the handler blocks. labels[i] is * the beginning of the handler block for the keys[i] key. */ public LookupSwitchInsnNode( final LabelNode dflt, final int[] keys, final LabelNode[] labels) { super(Opcodes.LOOKUPSWITCH); this.dflt = dflt; this.keys = new ArrayList(keys == null ? 0 : keys.length); this.labels = new ArrayList(labels == null ? 0 : labels.length); if (keys != null) { for (int i = 0; i < keys.length; ++i) { this.keys.add(new Integer(keys[i])); } } if (labels != null) { this.labels.addAll(Arrays.asList(labels)); } } public int getType() { return LOOKUPSWITCH_INSN; } public void accept(final MethodVisitor mv) { int[] keys = new int[this.keys.size()]; for (int i = 0; i < keys.length; ++i) { keys[i] = ((Integer) this.keys.get(i)).intValue(); } Label[] labels = new Label[this.labels.size()]; for (int i = 0; i < labels.length; ++i) { labels[i] = ((LabelNode) this.labels.get(i)).getLabel(); } mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels); } public AbstractInsnNode clone(final Map labels) { LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt, labels), null, clone(this.labels, labels)); clone.keys.addAll(keys); return clone; } } asm-3.3.2/src/org/objectweb/asm/tree/FrameNode.java0000644000175000017500000001734111347404066022014 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A node that represents a stack map frame. These nodes are pseudo instruction * nodes in order to be inserted in an instruction list. In fact these nodes * must(*) be inserted just before any instruction node i that * follows an unconditionnal branch instruction such as GOTO or THROW, that is * the target of a jump instruction, or that starts an exception handler block. * The stack map frame types must describe the values of the local variables and * of the operand stack elements just before i is executed.
*
(*) this is mandatory only for classes whose version is greater than or * equal to {@link Opcodes#V1_6 V1_6}. * * @author Eric Bruneton */ public class FrameNode extends AbstractInsnNode { /** * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. */ public int type; /** * The types of the local variables of this stack map frame. Elements of * this list can be Integer, String or LabelNode objects (for primitive, * reference and uninitialized types respectively - see * {@link MethodVisitor}). */ public List local; /** * The types of the operand stack elements of this stack map frame. Elements * of this list can be Integer, String or LabelNode objects (for primitive, * reference and uninitialized types respectively - see * {@link MethodVisitor}). */ public List stack; private FrameNode() { super(-1); } /** * Constructs a new {@link FrameNode}. * * @param type the type of this frame. Must be {@link Opcodes#F_NEW} for * expanded frames, or {@link Opcodes#F_FULL}, * {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, * {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, * {@link Opcodes#F_SAME1} for compressed frames. * @param nLocal number of local variables of this stack map frame. * @param local the types of the local variables of this stack map frame. * Elements of this list can be Integer, String or LabelNode objects * (for primitive, reference and uninitialized types respectively - * see {@link MethodVisitor}). * @param nStack number of operand stack elements of this stack map frame. * @param stack the types of the operand stack elements of this stack map * frame. Elements of this list can be Integer, String or LabelNode * objects (for primitive, reference and uninitialized types * respectively - see {@link MethodVisitor}). */ public FrameNode( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { super(-1); this.type = type; switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: this.local = asList(nLocal, local); this.stack = asList(nStack, stack); break; case Opcodes.F_APPEND: this.local = asList(nLocal, local); break; case Opcodes.F_CHOP: this.local = Arrays.asList(new Object[nLocal]); break; case Opcodes.F_SAME: break; case Opcodes.F_SAME1: this.stack = asList(1, stack); break; } } public int getType() { return FRAME; } /** * Makes the given visitor visit this stack map frame. * * @param mv a method visitor. */ public void accept(final MethodVisitor mv) { switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: mv.visitFrame(type, local.size(), asArray(local), stack.size(), asArray(stack)); break; case Opcodes.F_APPEND: mv.visitFrame(type, local.size(), asArray(local), 0, null); break; case Opcodes.F_CHOP: mv.visitFrame(type, local.size(), null, 0, null); break; case Opcodes.F_SAME: mv.visitFrame(type, 0, null, 0, null); break; case Opcodes.F_SAME1: mv.visitFrame(type, 0, null, 1, asArray(stack)); break; } } public AbstractInsnNode clone(final Map labels) { FrameNode clone = new FrameNode(); clone.type = type; if (local != null) { clone.local = new ArrayList(); for (int i = 0; i < local.size(); ++i) { Object l = local.get(i); if (l instanceof LabelNode) { l = labels.get(l); } clone.local.add(l); } } if (stack != null) { clone.stack = new ArrayList(); for (int i = 0; i < stack.size(); ++i) { Object s = stack.get(i); if (s instanceof LabelNode) { s = labels.get(s); } clone.stack.add(s); } } return clone; } // ------------------------------------------------------------------------ private static List asList(final int n, final Object[] o) { return Arrays.asList(o).subList(0, n); } private static Object[] asArray(final List l) { Object[] objs = new Object[l.size()]; for (int i = 0; i < objs.length; ++i) { Object o = l.get(i); if (o instanceof LabelNode) { o = ((LabelNode) o).getLabel(); } objs[i] = o; } return objs; } } asm-3.3.2/src/org/objectweb/asm/tree/AbstractInsnNode.java0000644000175000017500000001545010701747173023356 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.List; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a bytecode instruction. An instruction can appear * at most once in at most one {@link InsnList} at a time. * * @author Eric Bruneton */ public abstract class AbstractInsnNode { /** * The type of {@link InsnNode} instructions. */ public static final int INSN = 0; /** * The type of {@link IntInsnNode} instructions. */ public static final int INT_INSN = 1; /** * The type of {@link VarInsnNode} instructions. */ public static final int VAR_INSN = 2; /** * The type of {@link TypeInsnNode} instructions. */ public static final int TYPE_INSN = 3; /** * The type of {@link FieldInsnNode} instructions. */ public static final int FIELD_INSN = 4; /** * The type of {@link MethodInsnNode} instructions. */ public static final int METHOD_INSN = 5; /** * The type of {@link JumpInsnNode} instructions. */ public static final int JUMP_INSN = 6; /** * The type of {@link LabelNode} "instructions". */ public static final int LABEL = 7; /** * The type of {@link LdcInsnNode} instructions. */ public static final int LDC_INSN = 8; /** * The type of {@link IincInsnNode} instructions. */ public static final int IINC_INSN = 9; /** * The type of {@link TableSwitchInsnNode} instructions. */ public static final int TABLESWITCH_INSN = 10; /** * The type of {@link LookupSwitchInsnNode} instructions. */ public static final int LOOKUPSWITCH_INSN = 11; /** * The type of {@link MultiANewArrayInsnNode} instructions. */ public static final int MULTIANEWARRAY_INSN = 12; /** * The type of {@link FrameNode} "instructions". */ public static final int FRAME = 13; /** * The type of {@link LineNumberNode} "instructions". */ public static final int LINE = 14; /** * The opcode of this instruction. */ protected int opcode; /** * Previous instruction in the list to which this instruction belongs. */ AbstractInsnNode prev; /** * Next instruction in the list to which this instruction belongs. */ AbstractInsnNode next; /** * Index of this instruction in the list to which it belongs. The value of * this field is correct only when {@link InsnList#cache} is not null. A * value of -1 indicates that this instruction does not belong to any * {@link InsnList}. */ int index; /** * Constructs a new {@link AbstractInsnNode}. * * @param opcode the opcode of the instruction to be constructed. */ protected AbstractInsnNode(final int opcode) { this.opcode = opcode; this.index = -1; } /** * Returns the opcode of this instruction. * * @return the opcode of this instruction. */ public int getOpcode() { return opcode; } /** * Returns the type of this instruction. * * @return the type of this instruction, i.e. one the constants defined in * this class. */ public abstract int getType(); /** * Returns the previous instruction in the list to which this instruction * belongs, if any. * * @return the previous instruction in the list to which this instruction * belongs, if any. May be null. */ public AbstractInsnNode getPrevious() { return prev; } /** * Returns the next instruction in the list to which this instruction * belongs, if any. * * @return the next instruction in the list to which this instruction * belongs, if any. May be null. */ public AbstractInsnNode getNext() { return next; } /** * Makes the given code visitor visit this instruction. * * @param cv a code visitor. */ public abstract void accept(final MethodVisitor cv); /** * Returns a copy of this instruction. * * @param labels a map from LabelNodes to cloned LabelNodes. * @return a copy of this instruction. The returned instruction does not * belong to any {@link InsnList}. */ public abstract AbstractInsnNode clone(final Map labels); /** * Returns the clone of the given label. * * @param label a label. * @param map a map from LabelNodes to cloned LabelNodes. * @return the clone of the given label. */ static LabelNode clone(final LabelNode label, final Map map) { return (LabelNode) map.get(label); } /** * Returns the clones of the given labels. * * @param labels a list of labels. * @param map a map from LabelNodes to cloned LabelNodes. * @return the clones of the given labels. */ static LabelNode[] clone(final List labels, final Map map) { LabelNode[] clones = new LabelNode[labels.size()]; for (int i = 0; i < clones.length; ++i) { clones[i] = (LabelNode) map.get(labels.get(i)); } return clones; } } asm-3.3.2/src/org/objectweb/asm/tree/TableSwitchInsnNode.java0000644000175000017500000000727310635277351024032 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.MethodVisitor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; /** * A node that represents a TABLESWITCH instruction. * * @author Eric Bruneton */ public class TableSwitchInsnNode extends AbstractInsnNode { /** * The minimum key value. */ public int min; /** * The maximum key value. */ public int max; /** * Beginning of the default handler block. */ public LabelNode dflt; /** * Beginnings of the handler blocks. This list is a list of * {@link LabelNode} objects. */ public List labels; /** * Constructs a new {@link TableSwitchInsnNode}. * * @param min the minimum key value. * @param max the maximum key value. * @param dflt beginning of the default handler block. * @param labels beginnings of the handler blocks. labels[i] is * the beginning of the handler block for the min + i key. */ public TableSwitchInsnNode( final int min, final int max, final LabelNode dflt, final LabelNode[] labels) { super(Opcodes.TABLESWITCH); this.min = min; this.max = max; this.dflt = dflt; this.labels = new ArrayList(); if (labels != null) { this.labels.addAll(Arrays.asList(labels)); } } public int getType() { return TABLESWITCH_INSN; } public void accept(final MethodVisitor mv) { Label[] labels = new Label[this.labels.size()]; for (int i = 0; i < labels.length; ++i) { labels[i] = ((LabelNode) this.labels.get(i)).getLabel(); } mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels); } public AbstractInsnNode clone(final Map labels) { return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(this.labels, labels)); } }asm-3.3.2/src/org/objectweb/asm/tree/LdcInsnNode.java0000644000175000017500000000536610635277351022324 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A node that represents an LDC instruction. * * @author Eric Bruneton */ public class LdcInsnNode extends AbstractInsnNode { /** * The constant to be loaded on the stack. This parameter must be a non null * {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a * {@link String} or a {@link org.objectweb.asm.Type}. */ public Object cst; /** * Constructs a new {@link LdcInsnNode}. * * @param cst the constant to be loaded on the stack. This parameter must be * a non null {@link Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String}. */ public LdcInsnNode(final Object cst) { super(Opcodes.LDC); this.cst = cst; } public int getType() { return LDC_INSN; } public void accept(final MethodVisitor mv) { mv.visitLdcInsn(cst); } public AbstractInsnNode clone(final Map labels) { return new LdcInsnNode(cst); } }asm-3.3.2/src/org/objectweb/asm/tree/TypeInsnNode.java0000644000175000017500000000614010635277351022532 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a type instruction. A type instruction is an * instruction that takes a type descriptor as parameter. * * @author Eric Bruneton */ public class TypeInsnNode extends AbstractInsnNode { /** * The operand of this instruction. This operand is an internal name (see * {@link org.objectweb.asm.Type}). */ public String desc; /** * Constructs a new {@link TypeInsnNode}. * * @param opcode the opcode of the type instruction to be constructed. This * opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. * @param desc the operand of the instruction to be constructed. This * operand is an internal name (see {@link org.objectweb.asm.Type}). */ public TypeInsnNode(final int opcode, final String desc) { super(opcode); this.desc = desc; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be NEW, * ANEWARRAY, CHECKCAST or INSTANCEOF. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return TYPE_INSN; } public void accept(final MethodVisitor mv) { mv.visitTypeInsn(opcode, desc); } public AbstractInsnNode clone(final Map labels) { return new TypeInsnNode(opcode, desc); } }asm-3.3.2/src/org/objectweb/asm/tree/FieldNode.java0000644000175000017500000001116210635277351022004 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; /** * A node that represents a field. * * @author Eric Bruneton */ public class FieldNode extends MemberNode implements FieldVisitor { /** * The field's access flags (see {@link org.objectweb.asm.Opcodes}). This * field also indicates if the field is synthetic and/or deprecated. */ public int access; /** * The field's name. */ public String name; /** * The field's descriptor (see {@link org.objectweb.asm.Type}). */ public String desc; /** * The field's signature. May be null. */ public String signature; /** * The field's initial value. This field, which may be null if * the field does not have an initial value, must be an {@link Integer}, a * {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. */ public Object value; /** * Constructs a new {@link FieldNode}. * * @param access the field's access flags (see * {@link org.objectweb.asm.Opcodes}). This parameter also indicates * if the field is synthetic and/or deprecated. * @param name the field's name. * @param desc the field's descriptor (see * {@link org.objectweb.asm.Type Type}). * @param signature the field's signature. * @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 Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String}. */ public FieldNode( final int access, final String name, final String desc, final String signature, final Object value) { this.access = access; this.name = name; this.desc = desc; this.signature = signature; this.value = value; } /** * Makes the given class visitor visit this field. * * @param cv a class visitor. */ public void accept(final ClassVisitor cv) { FieldVisitor fv = cv.visitField(access, name, desc, signature, value); if (fv == null) { return; } int i, n; n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); an.accept(fv.visitAnnotation(an.desc, true)); } n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); an.accept(fv.visitAnnotation(an.desc, false)); } n = attrs == null ? 0 : attrs.size(); for (i = 0; i < n; ++i) { fv.visitAttribute((Attribute) attrs.get(i)); } fv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/tree/InsnNode.java0000644000175000017500000000656610701747173021702 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a zero operand instruction. * * @author Eric Bruneton */ public class InsnNode extends AbstractInsnNode { /** * Constructs a new {@link InsnNode}. * * @param opcode the opcode of the instruction to be constructed. This * opcode must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, * DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, * FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, * ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, * I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, * MONITORENTER, or MONITOREXIT. */ public InsnNode(final int opcode) { super(opcode); } public int getType() { return INSN; } /** * Makes the given visitor visit this instruction. * * @param mv a method visitor. */ public void accept(final MethodVisitor mv) { mv.visitInsn(opcode); } public AbstractInsnNode clone(final Map labels) { return new InsnNode(opcode); } } asm-3.3.2/src/org/objectweb/asm/tree/ClassNode.java0000644000175000017500000002126510701747173022031 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.FieldVisitor; import java.util.List; import java.util.ArrayList; import java.util.Arrays; /** * A node that represents a class. * * @author Eric Bruneton */ public class ClassNode extends MemberNode implements ClassVisitor { /** * The class version. */ public int version; /** * The class's access flags (see {@link org.objectweb.asm.Opcodes}). This * field also indicates if the class is deprecated. */ public int access; /** * The internal name of the class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). */ public String name; /** * The signature of the class. Mayt be null. */ public String signature; /** * The internal of name of the super class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). For * interfaces, the super class is {@link Object}. May be null, * but only for the {@link Object} class. */ public String superName; /** * The internal names of the class's interfaces (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). This * list is a list of {@link String} objects. */ public List interfaces; /** * The name of the source file from which this class was compiled. May be * null. */ public String sourceFile; /** * Debug information to compute the correspondance between source and * compiled elements of the class. May be null. */ public String sourceDebug; /** * The internal name of the enclosing class of the class. May be * null. */ public String outerClass; /** * The name of the method that contains the class, or null if the * class is not enclosed in a method. */ public String outerMethod; /** * The descriptor of the method that contains the class, or null * if the class is not enclosed in a method. */ public String outerMethodDesc; /** * Informations about the inner classes of this class. This list is a list * of {@link InnerClassNode} objects. * * @associates org.objectweb.asm.tree.InnerClassNode */ public List innerClasses; /** * The fields of this class. This list is a list of {@link FieldNode} * objects. * * @associates org.objectweb.asm.tree.FieldNode */ public List fields; /** * The methods of this class. This list is a list of {@link MethodNode} * objects. * * @associates org.objectweb.asm.tree.MethodNode */ public List methods; /** * Constructs a new {@link ClassNode}. */ public ClassNode() { this.interfaces = new ArrayList(); this.innerClasses = new ArrayList(); this.fields = new ArrayList(); this.methods = new ArrayList(); } // ------------------------------------------------------------------------ // Implementation of the ClassVisitor interface // ------------------------------------------------------------------------ public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { this.version = version; this.access = access; this.name = name; this.signature = signature; this.superName = superName; if (interfaces != null) { this.interfaces.addAll(Arrays.asList(interfaces)); } } public void visitSource(final String file, final String debug) { sourceFile = file; sourceDebug = debug; } public void visitOuterClass( final String owner, final String name, final String desc) { outerClass = owner; outerMethod = name; outerMethodDesc = desc; } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { InnerClassNode icn = new InnerClassNode(name, outerName, innerName, access); innerClasses.add(icn); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { FieldNode fn = new FieldNode(access, name, desc, signature, value); fields.add(fn); return fn; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodNode mn = new MethodNode(access, name, desc, signature, exceptions); methods.add(mn); return mn; } // ------------------------------------------------------------------------ // Accept method // ------------------------------------------------------------------------ /** * Makes the given class visitor visit this class. * * @param cv a class visitor. */ public void accept(final ClassVisitor cv) { // visits header String[] interfaces = new String[this.interfaces.size()]; this.interfaces.toArray(interfaces); cv.visit(version, access, name, signature, superName, interfaces); // visits source if (sourceFile != null || sourceDebug != null) { cv.visitSource(sourceFile, sourceDebug); } // visits outer class if (outerClass != null) { cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc); } // visits attributes int i, n; n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); an.accept(cv.visitAnnotation(an.desc, true)); } n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); for (i = 0; i < n; ++i) { AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); an.accept(cv.visitAnnotation(an.desc, false)); } n = attrs == null ? 0 : attrs.size(); for (i = 0; i < n; ++i) { cv.visitAttribute((Attribute) attrs.get(i)); } // visits inner classes for (i = 0; i < innerClasses.size(); ++i) { ((InnerClassNode) innerClasses.get(i)).accept(cv); } // visits fields for (i = 0; i < fields.size(); ++i) { ((FieldNode) fields.get(i)).accept(cv); } // visits methods for (i = 0; i < methods.size(); ++i) { ((MethodNode) methods.get(i)).accept(cv); } // visits end cv.visitEnd(); } } asm-3.3.2/src/org/objectweb/asm/tree/MultiANewArrayInsnNode.java0000644000175000017500000000542710635277351024464 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.Opcodes; import org.objectweb.asm.MethodVisitor; /** * A node that represents a MULTIANEWARRAY instruction. * * @author Eric Bruneton */ public class MultiANewArrayInsnNode extends AbstractInsnNode { /** * An array type descriptor (see {@link org.objectweb.asm.Type}). */ public String desc; /** * Number of dimensions of the array to allocate. */ public int dims; /** * Constructs a new {@link MultiANewArrayInsnNode}. * * @param desc an array type descriptor (see {@link org.objectweb.asm.Type}). * @param dims number of dimensions of the array to allocate. */ public MultiANewArrayInsnNode(final String desc, final int dims) { super(Opcodes.MULTIANEWARRAY); this.desc = desc; this.dims = dims; } public int getType() { return MULTIANEWARRAY_INSN; } public void accept(final MethodVisitor mv) { mv.visitMultiANewArrayInsn(desc, dims); } public AbstractInsnNode clone(final Map labels) { return new MultiANewArrayInsnNode(desc, dims); } }asm-3.3.2/src/org/objectweb/asm/tree/LocalVariableNode.java0000644000175000017500000000734610635277351023472 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.MethodVisitor; /** * A node that represents a local variable declaration. * * @author Eric Bruneton */ public class LocalVariableNode { /** * The name of a local variable. */ public String name; /** * The type descriptor of this local variable. */ public String desc; /** * The signature of this local variable. May be null. */ public String signature; /** * The first instruction corresponding to the scope of this local variable * (inclusive). */ public LabelNode start; /** * The last instruction corresponding to the scope of this local variable * (exclusive). */ public LabelNode end; /** * The local variable's index. */ public int index; /** * Constructs a new {@link LocalVariableNode}. * * @param name the name of a local variable. * @param desc the type descriptor of this local variable. * @param signature the signature of this local variable. May be * null. * @param start the first instruction corresponding to the scope of this * local variable (inclusive). * @param end the last instruction corresponding to the scope of this local * variable (exclusive). * @param index the local variable's index. */ public LocalVariableNode( final String name, final String desc, final String signature, final LabelNode start, final LabelNode end, final int index) { this.name = name; this.desc = desc; this.signature = signature; this.start = start; this.end = end; this.index = index; } /** * Makes the given visitor visit this local variable declaration. * * @param mv a method visitor. */ public void accept(final MethodVisitor mv) { mv.visitLocalVariable(name, desc, signature, start.getLabel(), end.getLabel(), index); } } asm-3.3.2/src/org/objectweb/asm/tree/TryCatchBlockNode.java0000644000175000017500000000650710635277351023464 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.MethodVisitor; /** * A node that represents a try catch block. * * @author Eric Bruneton */ public class TryCatchBlockNode { /** * Beginning of the exception handler's scope (inclusive). */ public LabelNode start; /** * End of the exception handler's scope (exclusive). */ public LabelNode end; /** * Beginning of the exception handler's code. */ public LabelNode handler; /** * Internal name of the type of exceptions handled by the handler. May be * null to catch any exceptions (for "finally" blocks). */ public String type; /** * Constructs a new {@link TryCatchBlockNode}. * * @param start beginning of the exception handler's scope (inclusive). * @param end end of the exception handler's scope (exclusive). * @param handler beginning of the exception handler's code. * @param type internal name of the type of exceptions handled by the * handler, or null to catch any exceptions (for "finally" * blocks). */ public TryCatchBlockNode( final LabelNode start, final LabelNode end, final LabelNode handler, final String type) { this.start = start; this.end = end; this.handler = handler; this.type = type; } /** * Makes the given visitor visit this try catch block. * * @param mv a method visitor. */ public void accept(final MethodVisitor mv) { mv.visitTryCatchBlock(start.getLabel(), end.getLabel(), handler == null ? null : handler.getLabel(), type); } } asm-3.3.2/src/org/objectweb/asm/tree/MethodInsnNode.java0000644000175000017500000000727511213534774023041 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a method instruction. A method instruction is an * instruction that invokes a method. * * @author Eric Bruneton */ public class MethodInsnNode extends AbstractInsnNode { /** * The internal name of the method's owner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). */ public String owner; /** * The method's name. */ public String name; /** * The method's descriptor (see {@link org.objectweb.asm.Type}). */ public String desc; /** * Constructs a new {@link MethodInsnNode}. * * @param opcode the opcode of the type instruction to be constructed. This * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, * INVOKEINTERFACE or INVOKEDYNAMIC. * @param owner the internal name of the method's owner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}) * or {@link org.objectweb.asm.Opcodes#INVOKEDYNAMIC_OWNER}. * @param name the method's name. * @param desc the method's descriptor (see {@link org.objectweb.asm.Type}). */ public MethodInsnNode( final int opcode, final String owner, final String name, final String desc) { super(opcode); this.owner = owner; this.name = name; this.desc = desc; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return METHOD_INSN; } public void accept(final MethodVisitor mv) { mv.visitMethodInsn(opcode, owner, name, desc); } public AbstractInsnNode clone(final Map labels) { return new MethodInsnNode(opcode, owner, name, desc); } }asm-3.3.2/src/org/objectweb/asm/tree/JumpInsnNode.java0000644000175000017500000000673510635277351022536 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a jump instruction. A jump instruction is an * instruction that may jump to another instruction. * * @author Eric Bruneton */ public class JumpInsnNode extends AbstractInsnNode { /** * The operand of this instruction. This operand is a label that designates * the instruction to which this instruction may jump. */ public LabelNode label; /** * Constructs a new {@link JumpInsnNode}. * * @param opcode the opcode of the type instruction to be constructed. This * opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. * @param label the operand of the instruction to be constructed. This * operand is a label that designates the instruction to which the * jump instruction may jump. */ public JumpInsnNode(final int opcode, final LabelNode label) { super(opcode); this.label = label; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be IFEQ, IFNE, * IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, * IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, * IFNULL or IFNONNULL. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return JUMP_INSN; } public void accept(final MethodVisitor mv) { mv.visitJumpInsn(opcode, label.getLabel()); } public AbstractInsnNode clone(final Map labels) { return new JumpInsnNode(opcode, clone(label, labels)); } } asm-3.3.2/src/org/objectweb/asm/tree/MemberNode.java0000644000175000017500000001002210701747173022160 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; /** * An abstract class, field or method node. * * @author Eric Bruneton */ public abstract class MemberNode { /** * The runtime visible annotations of this class, field or method. This list * is a list of {@link AnnotationNode} objects. May be null. * * @associates org.objectweb.asm.tree.AnnotationNode * @label visible */ public List visibleAnnotations; /** * The runtime invisible annotations of this class, field or method. This * list is a list of {@link AnnotationNode} objects. May be null. * * @associates org.objectweb.asm.tree.AnnotationNode * @label invisible */ public List invisibleAnnotations; /** * The non standard attributes of this class, field or method. This list is * a list of {@link Attribute} objects. May be null. * * @associates org.objectweb.asm.Attribute */ public List attrs; /** * Constructs a new {@link MemberNode}. */ protected MemberNode() { } /** * Visits an annotation of this class, field or method. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values. */ public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleAnnotations == null) { visibleAnnotations = new ArrayList(1); } visibleAnnotations.add(an); } else { if (invisibleAnnotations == null) { invisibleAnnotations = new ArrayList(1); } invisibleAnnotations.add(an); } return an; } /** * Visits a non standard attribute of this class, field or method. * * @param attr an attribute. */ public void visitAttribute(final Attribute attr) { if (attrs == null) { attrs = new ArrayList(1); } attrs.add(attr); } /** * Visits the end of this class, field or method. */ public void visitEnd() { } } asm-3.3.2/src/org/objectweb/asm/tree/AnnotationNode.java0000644000175000017500000001471210635277351023077 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.AnnotationVisitor; /** * A node that represents an annotationn. * * @author Eric Bruneton */ public class AnnotationNode implements AnnotationVisitor { /** * The class descriptor of the annotation class. */ public String desc; /** * The name value pairs of this annotation. Each name value pair is stored * as two consecutive elements in the list. The name is a {@link String}, * and the value may be a {@link Byte}, {@link Boolean}, {@link Character}, * {@link Short}, {@link Integer}, {@link Long}, {@link Float}, * {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or an * two elements String array (for enumeration values), a * {@link AnnotationNode}, or a {@link List} of values of one of the * preceding types. The list may be null if there is no name * value pair. */ public List values; /** * Constructs a new {@link AnnotationNode}. * * @param desc the class descriptor of the annotation class. */ public AnnotationNode(final String desc) { this.desc = desc; } /** * Constructs a new {@link AnnotationNode} to visit an array value. * * @param values where the visited values must be stored. */ AnnotationNode(final List values) { this.values = values; } // ------------------------------------------------------------------------ // Implementation of the AnnotationVisitor interface // ------------------------------------------------------------------------ public void visit(final String name, final Object value) { if (values == null) { values = new ArrayList(this.desc != null ? 2 : 1); } if (this.desc != null) { values.add(name); } values.add(value); } public void visitEnum( final String name, final String desc, final String value) { if (values == null) { values = new ArrayList(this.desc != null ? 2 : 1); } if (this.desc != null) { values.add(name); } values.add(new String[] { desc, value }); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { if (values == null) { values = new ArrayList(this.desc != null ? 2 : 1); } if (this.desc != null) { values.add(name); } AnnotationNode annotation = new AnnotationNode(desc); values.add(annotation); return annotation; } public AnnotationVisitor visitArray(final String name) { if (values == null) { values = new ArrayList(this.desc != null ? 2 : 1); } if (this.desc != null) { values.add(name); } List array = new ArrayList(); values.add(array); return new AnnotationNode(array); } public void visitEnd() { } // ------------------------------------------------------------------------ // Accept methods // ------------------------------------------------------------------------ /** * Makes the given visitor visit this annotation. * * @param av an annotation visitor. Maybe null. */ public void accept(final AnnotationVisitor av) { if (av != null) { if (values != null) { for (int i = 0; i < values.size(); i += 2) { String name = (String) values.get(i); Object value = values.get(i + 1); accept(av, name, value); } } av.visitEnd(); } } /** * Makes the given visitor visit a given annotation value. * * @param av an annotation visitor. Maybe null. * @param name the value name. * @param value the actual value. */ static void accept( final AnnotationVisitor av, final String name, final Object value) { if (av != null) { if (value instanceof String[]) { String[] typeconst = (String[]) value; av.visitEnum(name, typeconst[0], typeconst[1]); } else if (value instanceof AnnotationNode) { AnnotationNode an = (AnnotationNode) value; an.accept(av.visitAnnotation(name, an.desc)); } else if (value instanceof List) { AnnotationVisitor v = av.visitArray(name); List array = (List) value; for (int j = 0; j < array.size(); ++j) { accept(v, null, array.get(j)); } v.visitEnd(); } else { av.visit(name, value); } } } } asm-3.3.2/src/org/objectweb/asm/tree/FieldInsnNode.java0000644000175000017500000000710710635277351022640 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.Map; import org.objectweb.asm.MethodVisitor; /** * A node that represents a field instruction. A field instruction is an * instruction that loads or stores the value of a field of an object. * * @author Eric Bruneton */ public class FieldInsnNode extends AbstractInsnNode { /** * The internal name of the field's owner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). */ public String owner; /** * The field's name. */ public String name; /** * The field's descriptor (see {@link org.objectweb.asm.Type}). */ public String desc; /** * Constructs a new {@link FieldInsnNode}. * * @param opcode the opcode of the type instruction to be constructed. This * opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. * @param owner the internal name of the field's owner class (see * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). * @param name the field's name. * @param desc the field's descriptor (see {@link org.objectweb.asm.Type}). */ public FieldInsnNode( final int opcode, final String owner, final String name, final String desc) { super(opcode); this.owner = owner; this.name = name; this.desc = desc; } /** * Sets the opcode of this instruction. * * @param opcode the new instruction opcode. This opcode must be GETSTATIC, * PUTSTATIC, GETFIELD or PUTFIELD. */ public void setOpcode(final int opcode) { this.opcode = opcode; } public int getType() { return FIELD_INSN; } public void accept(final MethodVisitor cv) { cv.visitFieldInsn(opcode, owner, name, desc); } public AbstractInsnNode clone(final Map labels) { return new FieldInsnNode(opcode, owner, name, desc); } } asm-3.3.2/README.txt0000644000175000017500000000136010452754520013737 0ustar twernertwernerThis directory is the base directory of the product. It contains(*) the following items: - archive: ant files to build the jar(s) of the product, - build.properties: properties to configure the build process, - build.xml: main ant file to build the product, - config: external libraries required only for building the product, - doc: documentation of the product, - etc: scripts to run the product, - examples: examples of use of the product, - externals: external libraires required for running the product, - jdoc: ant files to build the javadoc documentation(s) of the product, - sr': sources of the product, - test: tests of the product, - web: source of the web site of the product. (*) some items may not be present, depending on the product. asm-3.3.2/examples/0000755000175000017500000000000011633370220014050 5ustar twernertwernerasm-3.3.2/examples/attributes/0000755000175000017500000000000011633370220016236 5ustar twernertwernerasm-3.3.2/examples/attributes/src/0000755000175000017500000000000011633370220017025 5ustar twernertwernerasm-3.3.2/examples/attributes/src/Attributes.java0000644000175000017500000001211510635277351022032 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Label; import org.objectweb.asm.ByteVector; import org.objectweb.asm.util.TraceClassVisitor; import java.io.FileOutputStream; import java.io.PrintWriter; /** * @author Eric Bruneton */ public class Attributes extends ClassLoader { public static void main(final String args[]) throws Exception { // loads the original class and adapts it ClassReader cr = new ClassReader("CommentAttribute"); ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new AddCommentClassAdapter(cw); cr.accept(cv, new Attribute[] { new CommentAttribute("") }, 0); byte[] b = cw.toByteArray(); // stores the adapted class on disk FileOutputStream fos = new FileOutputStream("CommentAttribute.class.new"); fos.write(b); fos.close(); // "disassembles" the adapted class cr = new ClassReader(b); cv = new TraceClassVisitor(new PrintWriter(System.out)); cr.accept(cv, new Attribute[] { new CommentAttribute("") }, 0); } } class AddCommentClassAdapter extends ClassAdapter implements Opcodes { public AddCommentClassAdapter(final ClassVisitor cv) { super(cv); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); visitAttribute(new CommentAttribute("this is a class comment")); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { FieldVisitor fv = super.visitField(access, name, desc, signature, value); fv.visitAttribute(new CommentAttribute("this is a field comment")); return fv; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv != null) { mv.visitAttribute(new CommentAttribute("this is a method comment")); } return mv; } } class CommentAttribute extends Attribute { private String comment; public CommentAttribute(final String comment) { super("Comment"); this.comment = comment; } public String getComment() { return comment; } public boolean isUnknown() { return false; } protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return new CommentAttribute(cr.readUTF8(off, buf)); } protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { return new ByteVector().putShort(cw.newUTF8(comment)); } } asm-3.3.2/examples/attributes/etc/0000755000175000017500000000000011633370220017011 5ustar twernertwernerasm-3.3.2/examples/attributes/etc/execute.properties0000644000175000017500000000005007754641540022603 0ustar twernertwernerrun.classname Attributes run.parameters asm-3.3.2/examples/analysis/0000755000175000017500000000000011633370220015673 5ustar twernertwernerasm-3.3.2/examples/analysis/src/0000755000175000017500000000000011633370220016462 5ustar twernertwernerasm-3.3.2/examples/analysis/src/Analysis.java0000644000175000017500000001636410635277351021136 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.tree.analysis.Analyzer; import org.objectweb.asm.tree.analysis.BasicVerifier; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.util.TraceMethodVisitor; /** * @author Eric Bruneton */ public class Analysis implements Opcodes { public static void main(final String[] args) throws Exception { ClassReader cr = new ClassReader("Analysis"); ClassNode cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_DEBUG); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); if (method.instructions.size() > 0) { if (!analyze(cn, method)) { Analyzer a = new Analyzer(new BasicVerifier()); try { a.analyze(cn.name, method); } catch (Exception ignored) { } final Frame[] frames = a.getFrames(); TraceMethodVisitor mv = new TraceMethodVisitor() { public void visitMaxs( final int maxStack, final int maxLocals) { for (int i = 0; i < text.size(); ++i) { String s = frames[i] == null ? "null" : frames[i].toString(); while (s.length() < Math.max(20, maxStack + maxLocals + 1)) { s += " "; } System.err.print(Integer.toString(i + 1000) .substring(1) + " " + s + " : " + text.get(i)); } System.err.println(); } }; for (int j = 0; j < method.instructions.size(); ++j) { Object insn = method.instructions.get(j); ((AbstractInsnNode) insn).accept(mv); } mv.visitMaxs(0, 0); } } } } /* * Detects unused xSTORE instructions, i.e. xSTORE instructions without at * least one xLOAD corresponding instruction in their successor instructions * (in the control flow graph). */ public static boolean analyze(final ClassNode c, final MethodNode m) throws Exception { Analyzer a = new Analyzer(new SourceInterpreter()); Frame[] frames = a.analyze(c.name, m); // for each xLOAD instruction, we find the xSTORE instructions that can // produce the value loaded by this instruction, and we put them in // 'stores' Set stores = new HashSet(); for (int i = 0; i < m.instructions.size(); ++i) { Object insn = m.instructions.get(i); int opcode = ((AbstractInsnNode) insn).getOpcode(); if ((opcode >= ILOAD && opcode <= ALOAD) || opcode == IINC) { int var = opcode == IINC ? ((IincInsnNode) insn).var : ((VarInsnNode) insn).var; Frame f = frames[i]; if (f != null) { Set s = ((SourceValue) f.getLocal(var)).insns; Iterator j = s.iterator(); while (j.hasNext()) { insn = j.next(); if (insn instanceof VarInsnNode) { stores.add(insn); } } } } } // we then find all the xSTORE instructions that are not in 'stores' boolean ok = true; for (int i = 0; i < m.instructions.size(); ++i) { Object insn = m.instructions.get(i); if (insn instanceof AbstractInsnNode) { int opcode = ((AbstractInsnNode) insn).getOpcode(); if (opcode >= ISTORE && opcode <= ASTORE) { if (!stores.contains(insn)) { ok = false; System.err.println("method " + m.name + ", instruction " + i + ": useless store instruction"); } } } } return ok; } /* * Test for the above method, with three useless xSTORE instructions. */ public int test(int i, int j) { i = i + 1; // ok, because i can be read after this point if (j == 0) { j = 1; // useless } else { try { j = j - 1; // ok, because j can be accessed in the catch int k = 0; if (i > 0) { k = i - 1; } return k; } catch (Exception e) { // useless ASTORE (e is never used) j = j + 1; // useless } } return 0; } } asm-3.3.2/examples/analysis/etc/0000755000175000017500000000000011633370220016446 5ustar twernertwernerasm-3.3.2/examples/analysis/etc/execute.properties0000644000175000017500000000004610035530140022220 0ustar twernertwernerrun.classname Analysis run.parameters asm-3.3.2/examples/jasmin/0000755000175000017500000000000011633370220015331 5ustar twernertwernerasm-3.3.2/examples/jasmin/src/0000755000175000017500000000000011633370220016120 5ustar twernertwernerasm-3.3.2/examples/jasmin/src/JasminifierClassAdapter.java0000644000175000017500000010476011101041231023505 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2005 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.FileInputStream; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.EmptyVisitor; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MemberNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.util.AbstractVisitor; /** * A {@link ClassVisitor} that prints a disassembled view of the classes it * visits in Jasmin assembler format. This class visitor can be used alone (see * the {@link #main main} method) to disassemble a class. It can also be used in * the middle of class visitor chain to trace the class that is visited at a * given point in this chain. This may be uselful for debugging purposes.

* The trace printed when visiting the Hello class is the following: *

* *
 * .bytecode 45.3
 * .class public Hello
 * .super java/lang/Object
 *
 * .method public ()V
 * aload 0
 * invokespecial java/lang/Object/()V
 * return
 * .limit locals 1
 * .limit stack 1
 * .end method
 *
 * .method public static main([Ljava/lang/String;)V
 * getstatic java/lang/System/out Ljava/io/PrintStream;
 * ldc "hello"
 * invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
 * return
 * .limit locals 2
 * .limit stack 2
 * .end method
 * 
* *
where Hello is defined by:

* *
 * public class Hello {
 *
 *     public static void main(String[] args) {
 *         System.out.println("hello");
 *     }
 * }
 * 
* *
* * @author Eric Bruneton */ public class JasminifierClassAdapter extends ClassAdapter { /** * The print writer to be used to print the class. */ protected PrintWriter pw; /** * The label names. This map associate String values to Label keys. */ protected final Map labelNames; /** * Prints a disassembled view of the given class in Jasmin assembler format * to the standard output.

Usage: JasminifierClassAdapter [-debug] * <fully qualified class name or class file name > * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { int i = 0; int flags = ClassReader.SKIP_DEBUG; boolean ok = true; if (args.length < 1 || args.length > 2) { ok = false; } if (ok && "-debug".equals(args[0])) { i = 1; flags = 0; if (args.length != 2) { ok = false; } } if (!ok) { System.err.println("Prints a disassembled view of the given class."); System.err.println("Usage: JasminifierClassAdapter [-debug] " + ""); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new JasminifierClassAdapter(new PrintWriter(System.out, true), null), flags | ClassReader.EXPAND_FRAMES); } /** * Constructs a new {@link JasminifierClassAdapter}. * * @param pw the print writer to be used to print the class. * @param cv the {@link ClassVisitor} to which this visitor delegates calls. * May be null. */ public JasminifierClassAdapter(final PrintWriter pw, final ClassVisitor cv) { super(new ClassNode() { public void visitEnd() { if (cv != null) { accept(cv); } } }); this.pw = pw; labelNames = new HashMap(); } public void visitEnd() { ClassNode cn = (ClassNode) cv; pw.print(".bytecode "); pw.print(cn.version & 0xFFFF); pw.print('.'); pw.println(cn.version >>> 16); println(".source ", cn.sourceFile); pw.print(".class"); pw.print(access(cn.access)); pw.print(' '); pw.println(cn.name); if (cn.superName == null) { // TODO Jasmin bug workaround println(".super ", "java/lang/Object"); } else { println(".super ", cn.superName); } for (int i = 0; i < cn.interfaces.size(); ++i) { println(".implements ", (String) cn.interfaces.get(i)); } if (cn.signature != null) println(".signature ", '"' + cn.signature + '"'); if (cn.outerClass != null) { pw.print(".enclosing method "); pw.print(cn.outerClass); if (cn.outerMethod != null) { pw.print('/'); pw.print(cn.outerMethod); pw.println(cn.outerMethodDesc); } else { pw.println(); } } if ((cn.access & Opcodes.ACC_DEPRECATED) != 0) { pw.println(".deprecated"); } printAnnotations(cn); println(".debug ", cn.sourceDebug == null ? null : '"' + cn.sourceDebug + '"'); for (int i = 0; i < cn.innerClasses.size(); ++i) { InnerClassNode in = (InnerClassNode) cn.innerClasses.get(i); pw.print(".inner class"); pw.print(access(in.access)); if (in.innerName != null) { pw.print(' '); pw.print(in.innerName); } if (in.name != null) { pw.print(" inner "); pw.print(in.name); } if (in.outerName != null) { pw.print(" outer "); pw.print(in.outerName); } pw.println(); } for (int i = 0; i < cn.fields.size(); ++i) { FieldNode fn = (FieldNode) cn.fields.get(i); boolean annotations = false; if (fn.visibleAnnotations != null && fn.visibleAnnotations.size() > 0) { annotations = true; } if (fn.invisibleAnnotations != null && fn.invisibleAnnotations.size() > 0) { annotations = true; } boolean deprecated = (fn.access & Opcodes.ACC_DEPRECATED) != 0; pw.print("\n.field"); pw.print(access(fn.access)); pw.print(" '"); pw.print(fn.name); pw.print("' "); pw.print(fn.desc); if (fn.signature != null && (!deprecated && !annotations)) { pw.print(" signature \""); pw.print(fn.signature); pw.print("\""); } if (fn.value instanceof String) { StringBuffer buf = new StringBuffer(); AbstractVisitor.appendString(buf, (String) fn.value); pw.print(" = "); pw.print(buf.toString()); } else if (fn.value != null) { pw.print(" = "); print(fn.value); pw.println(); } pw.println(); if (fn.signature != null && (deprecated || annotations)) { pw.print(".signature \""); pw.print(fn.signature); pw.println("\""); } if (deprecated) { pw.println(".deprecated"); } printAnnotations(fn); if (deprecated || annotations) { pw.println(".end field"); } } for (int i = 0; i < cn.methods.size(); ++i) { MethodNode mn = (MethodNode) cn.methods.get(i); pw.print("\n.method"); pw.print(access(mn.access)); pw.print(' '); pw.print(mn.name); pw.println(mn.desc); if (mn.signature != null) { pw.print(".signature \""); pw.print(mn.signature); pw.println("\""); } if (mn.annotationDefault != null) { pw.println(".annotation default"); printAnnotationValue(mn.annotationDefault); pw.println(".end annotation"); } printAnnotations(mn); if (mn.visibleParameterAnnotations != null) { for (int j = 0; j < mn.visibleParameterAnnotations.length; ++j) { List l = mn.visibleParameterAnnotations[j]; if (l != null) { for (int k = 0; k < l.size(); ++k) { printAnnotation((AnnotationNode) l.get(k), 1, j + 1); } } } } if (mn.invisibleParameterAnnotations != null) { for (int j = 0; j < mn.invisibleParameterAnnotations.length; ++j) { List l = mn.invisibleParameterAnnotations[j]; if (l != null) { for (int k = 0; k < l.size(); ++k) { printAnnotation((AnnotationNode) l.get(k), 2, j + 1); } } } } for (int j = 0; j < mn.exceptions.size(); ++j) { println(".throws ", (String) mn.exceptions.get(j)); } if ((mn.access & Opcodes.ACC_DEPRECATED) != 0) { pw.println(".deprecated"); } if (mn.instructions.size() > 0) { labelNames.clear(); for (int j = 0; j < mn.tryCatchBlocks.size(); ++j) { TryCatchBlockNode tcb = (TryCatchBlockNode) mn.tryCatchBlocks.get(j); pw.print(".catch "); pw.print(tcb.type); pw.print(" from "); print(tcb.start); pw.print(" to "); print(tcb.end); pw.print(" using "); print(tcb.handler); pw.println(); } for (int j = 0; j < mn.instructions.size(); ++j) { AbstractInsnNode in = mn.instructions.get(j); in.accept(new EmptyVisitor() { public void visitFrame( int type, int local, Object[] locals, int stack, Object[] stacks) { if (type != Opcodes.F_FULL && type != Opcodes.F_NEW) { throw new RuntimeException("Compressed frames unsupported, use EXPAND_FRAMES option"); } pw.println(".stack"); for (int i = 0; i < local; ++i) { pw.print("locals "); printFrameType(locals[i]); pw.println(); } for (int i = 0; i < stack; ++i) { pw.print("stack "); printFrameType(stacks[i]); pw.println(); } pw.println(".end stack"); } public void visitInsn(int opcode) { print(opcode); pw.println(); } public void visitIntInsn(int opcode, int operand) { print(opcode); if (opcode == Opcodes.NEWARRAY) { switch (operand) { case Opcodes.T_BOOLEAN: pw.println(" boolean"); break; case Opcodes.T_CHAR: pw.println(" char"); break; case Opcodes.T_FLOAT: pw.println(" float"); break; case Opcodes.T_DOUBLE: pw.println(" double"); break; case Opcodes.T_BYTE: pw.println(" byte"); break; case Opcodes.T_SHORT: pw.println(" short"); break; case Opcodes.T_INT: pw.println(" int"); break; case Opcodes.T_LONG: default: pw.println(" long"); break; } } else { pw.print(' '); pw.println(operand); } } public void visitVarInsn(int opcode, int var) { print(opcode); pw.print(' '); pw.println(var); } public void visitTypeInsn(int opcode, String type) { print(opcode); pw.print(' '); pw.println(type); } public void visitFieldInsn( int opcode, String owner, String name, String desc) { print(opcode); pw.print(' '); pw.print(owner); pw.print('/'); pw.print(name); pw.print(' '); pw.println(desc); } public void visitMethodInsn( int opcode, String owner, String name, String desc) { print(opcode); pw.print(' '); pw.print(owner); pw.print('/'); pw.print(name); pw.print(desc); if (opcode == Opcodes.INVOKEINTERFACE) { pw.print(' '); pw.print((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); } pw.println(); } public void visitJumpInsn(int opcode, Label label) { print(opcode); pw.print(' '); print(label); pw.println(); } public void visitLabel(Label label) { print(label); pw.println(':'); } public void visitLdcInsn(Object cst) { pw.print("ldc "); if (cst instanceof Type) { pw.print(((Type) cst).getInternalName()); } else { print(cst); } pw.println(); } public void visitIincInsn(int var, int increment) { pw.print("iinc "); pw.print(var); pw.print(' '); pw.println(increment); } public void visitTableSwitchInsn( int min, int max, Label dflt, Label[] labels) { pw.print("tableswitch "); pw.println(min); for (int i = 0; i < labels.length; ++i) { print(labels[i]); pw.println(); } pw.print("default : "); print(dflt); pw.println(); } public void visitLookupSwitchInsn( Label dflt, int[] keys, Label[] labels) { if (keys.length == 0) { pw.print("goto "); // TODO Jasmin bug // workaround print(dflt); pw.println(); return; } pw.println("lookupswitch"); for (int i = 0; i < keys.length; ++i) { pw.print(keys[i]); pw.print(" : "); print(labels[i]); pw.println(); } pw.print("default : "); print(dflt); pw.println(); } public void visitMultiANewArrayInsn( String desc, int dims) { pw.print("multianewarray "); pw.print(desc); pw.print(' '); pw.println(dims); } public void visitLineNumber(int line, Label start) { pw.print(".line "); pw.println(line); } }); } for (int j = 0; j < mn.localVariables.size(); ++j) { LocalVariableNode lv = (LocalVariableNode) mn.localVariables.get(j); pw.print(".var "); pw.print(lv.index); pw.print(" is '"); pw.print(lv.name); pw.print("' "); pw.print(lv.desc); if (lv.signature != null) { pw.print(" signature \""); pw.print(lv.signature); pw.print("\""); } pw.print(" from "); print(lv.start); pw.print(" to "); print(lv.end); pw.println(); } println(".limit locals ", Integer.toString(mn.maxLocals)); println(".limit stack ", Integer.toString(mn.maxStack)); } pw.println(".end method"); } super.visitEnd(); } protected void println(final String directive, final String arg) { if (arg != null) { pw.print(directive); pw.println(arg); } } protected String access(final int access) { StringBuffer b = new StringBuffer(); if ((access & Opcodes.ACC_PUBLIC) != 0) { b.append(" public"); } if ((access & Opcodes.ACC_PRIVATE) != 0) { b.append(" private"); } if ((access & Opcodes.ACC_PROTECTED) != 0) { b.append(" protected"); } if ((access & Opcodes.ACC_STATIC) != 0) { b.append(" static"); } if ((access & Opcodes.ACC_FINAL) != 0) { b.append(" final"); } if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { b.append(" synchronized"); } if ((access & Opcodes.ACC_VOLATILE) != 0) { b.append(" volatile"); } if ((access & Opcodes.ACC_TRANSIENT) != 0) { b.append(" transient"); } if ((access & Opcodes.ACC_NATIVE) != 0) { b.append(" native"); } if ((access & Opcodes.ACC_ABSTRACT) != 0) { b.append(" abstract"); } if ((access & Opcodes.ACC_STRICT) != 0) { b.append(" fpstrict"); } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { b.append(" synthetic"); } if ((access & Opcodes.ACC_INTERFACE) != 0) { b.append(" interface"); } if ((access & Opcodes.ACC_ANNOTATION) != 0) { b.append(" annotation"); } if ((access & Opcodes.ACC_ENUM) != 0) { b.append(" enum"); } return b.toString(); } protected void print(final int opcode) { pw.print(AbstractVisitor.OPCODES[opcode].toLowerCase()); } protected void print(final Object cst) { if (cst instanceof String) { StringBuffer buf = new StringBuffer(); AbstractVisitor.appendString(buf, (String) cst); pw.print(buf.toString()); } else if (cst instanceof Float) { Float f = (Float) cst; if (f.isNaN() || f.isInfinite()) { pw.print("0.0"); // TODO Jasmin bug workaround } else { pw.print(f); } } else if (cst instanceof Double) { Double d = (Double) cst; if (d.isNaN() || d.isInfinite()) { pw.print("0.0"); // TODO Jasmin bug workaround } else { pw.print(d); } } else { pw.print(cst); } } protected void print(final Label l) { String name = (String) labelNames.get(l); if (name == null) { name = "L" + labelNames.size(); labelNames.put(l, name); } pw.print(name); } protected void print(final LabelNode l) { print(l.getLabel()); } protected void printAnnotations(final MemberNode n) { if (n.visibleAnnotations != null) { for (int j = 0; j < n.visibleAnnotations.size(); ++j) { printAnnotation((AnnotationNode) n.visibleAnnotations.get(j), 1, -1); } } if (n.invisibleAnnotations != null) { for (int j = 0; j < n.invisibleAnnotations.size(); ++j) { printAnnotation((AnnotationNode) n.invisibleAnnotations.get(j), 2, -1); } } } protected void printAnnotation( final AnnotationNode n, final int visible, final int param) { pw.print(".annotation "); if (visible > 0) { if (param == -1) { pw.print(visible == 1 ? "visible " : "invisible "); } else { pw.print(visible == 1 ? "visibleparam " : "invisibleparam "); pw.print(param); pw.print(' '); } pw.print(n.desc); } pw.println(); if (n.values != null) { for (int i = 0; i < n.values.size(); i += 2) { pw.print(n.values.get(i)); pw.print(' '); printAnnotationValue(n.values.get(i + 1)); } } pw.println(".end annotation"); } protected void printAnnotationValue(final Object value) { if (value instanceof String[]) { pw.print("e "); pw.print(((String[]) value)[0]); pw.print(" = "); print(((String[]) value)[1]); pw.println(); } else if (value instanceof AnnotationNode) { pw.print("@ "); pw.print(((AnnotationNode) value).desc); pw.print(" = "); printAnnotation((AnnotationNode) value, 0, -1); } else if (value instanceof byte[]) { pw.print("[B = "); byte[] v = (byte[]) value; for (int i = 0; i < v.length; i++) { pw.print(v[i]); pw.print(' '); } pw.println(); } else if (value instanceof boolean[]) { pw.print("[Z = "); boolean[] v = (boolean[]) value; for (int i = 0; i < v.length; i++) { pw.print(v[i] ? '1' : '0'); pw.print(' '); } pw.println(); } else if (value instanceof short[]) { pw.print("[S = "); short[] v = (short[]) value; for (int i = 0; i < v.length; i++) { pw.print(v[i]); pw.print(' '); } pw.println(); } else if (value instanceof char[]) { pw.print("[C = "); char[] v = (char[]) value; for (int i = 0; i < v.length; i++) { pw.print(new Integer(v[i])); pw.print(' '); } pw.println(); } else if (value instanceof int[]) { pw.print("[I = "); int[] v = (int[]) value; for (int i = 0; i < v.length; i++) { pw.print(v[i]); pw.print(' '); } pw.println(); } else if (value instanceof long[]) { pw.print("[J = "); long[] v = (long[]) value; for (int i = 0; i < v.length; i++) { pw.print(v[i]); pw.print(' '); } pw.println(); } else if (value instanceof float[]) { pw.print("[F = "); float[] v = (float[]) value; for (int i = 0; i < v.length; i++) { print(new Float(v[i])); pw.print(' '); } pw.println(); } else if (value instanceof double[]) { pw.print("[D = "); double[] v = (double[]) value; for (int i = 0; i < v.length; i++) { print(new Double(v[i])); pw.print(' '); } pw.println(); } else if (value instanceof List) { List l = (List) value; if (l.size() > 0) { Object o = l.get(0); if (o instanceof String[]) { pw.print("[e "); pw.print(((String[]) o)[0]); pw.print(" = "); } else if (o instanceof AnnotationNode) { pw.print("[& "); pw.print(((AnnotationNode) o).desc); pw.print(" = "); pw.print("[@ = "); } else if (o instanceof String) { pw.print("[s = "); } else if (o instanceof Byte) { pw.print("[B = "); } else if (o instanceof Boolean) { pw.print("[Z = "); } else if (o instanceof Character) { pw.print("[C = "); } else if (o instanceof Short) { pw.print("[S = "); } else if (o instanceof Type) { pw.print("[c = "); } else if (o instanceof Integer) { pw.print("[I = "); } else if (o instanceof Float) { pw.print("[F = "); } else if (o instanceof Long) { pw.print("[J = "); } else if (o instanceof Double) { pw.print("[D = "); } for (int j = 0; j < l.size(); ++j) { printAnnotationArrayValue(l.get(j)); pw.print(' '); } } else { pw.print("; empty array annotation value"); } pw.println(); } else if (value instanceof String) { pw.print("s = "); print(value); pw.println(); } else if (value instanceof Byte) { pw.print("B = "); pw.println(((Byte) value).intValue()); } else if (value instanceof Boolean) { pw.print("Z = "); pw.println(((Boolean) value).booleanValue() ? 1 : 0); } else if (value instanceof Character) { pw.print("C = "); pw.println(new Integer(((Character) value).charValue())); } else if (value instanceof Short) { pw.print("S = "); pw.println(((Short) value).intValue()); } else if (value instanceof Type) { pw.print("c = "); pw.println(((Type) value).getDescriptor()); } else if (value instanceof Integer) { pw.print("I = "); print(value); pw.println(); } else if (value instanceof Float) { pw.print("F = "); print(value); pw.println(); } else if (value instanceof Long) { pw.print("J = "); print(value); pw.println(); } else if (value instanceof Double) { pw.print("D = "); print(value); pw.println(); } else { throw new RuntimeException(); } } protected void printAnnotationArrayValue(final Object value) { if (value instanceof String[]) { print(((String[]) value)[1]); } else if (value instanceof AnnotationNode) { printAnnotation((AnnotationNode) value, 0, -1); } else if (value instanceof String) { print(value); } else if (value instanceof Byte) { pw.print(((Byte) value).intValue()); } else if (value instanceof Boolean) { pw.print(((Boolean) value).booleanValue() ? 1 : 0); } else if (value instanceof Character) { pw.print(new Integer(((Character) value).charValue())); } else if (value instanceof Short) { pw.print(((Short) value).intValue()); } else if (value instanceof Type) { pw.print(((Type) value).getDescriptor()); } else { print(value); } } protected void printFrameType(final Object type) { if (type == Opcodes.TOP) { pw.print("Top"); } else if (type == Opcodes.INTEGER) { pw.print("Integer"); } else if (type == Opcodes.FLOAT) { pw.print("Float"); } else if (type == Opcodes.LONG) { pw.print("Long"); } else if (type == Opcodes.DOUBLE) { pw.print("Double"); } else if (type == Opcodes.NULL) { pw.print("Null"); } else if (type == Opcodes.UNINITIALIZED_THIS) { pw.print("UninitializedThis"); } else if (type instanceof Label) { pw.print("Uninitialized "); print((Label) type); } else { pw.print("Object "); pw.print(type); } } } asm-3.3.2/examples/jasmin/etc/0000755000175000017500000000000011633370220016104 5ustar twernertwernerasm-3.3.2/examples/jasmin/etc/execute.properties0000644000175000017500000000010611101041231021644 0ustar twernertwernerrun.classname JasminifierClassAdapter run.parameters java.lang.Object asm-3.3.2/examples/jasmin/test/0000755000175000017500000000000011633370220016310 5ustar twernertwernerasm-3.3.2/examples/jasmin/test/JasminifierClassAdapterTest.java0000644000175000017500000002342711101041231024535 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import jas.jasError; import jasmin.ClassFile; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.util.Arrays; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import junit.framework.TestCase; import junit.framework.TestSuite; import org.objectweb.asm.Attribute; import org.objectweb.asm.ByteVector; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.TraceClassVisitor; class ClassFilter extends ClassAdapter { public ClassFilter() { super(null); } public void setNext(final ClassVisitor cv) { this.cv = cv; } } class Comment extends Attribute { public Comment() { super("Comment"); } public boolean isUnknown() { return false; } protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return new Comment(); } protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { return new ByteVector(); } } class CodeComment extends Attribute { public CodeComment() { super("CodeComment"); } public boolean isUnknown() { return false; } public boolean isCodeAttribute() { return true; } protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return new CodeComment(); } protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { return new ByteVector(); } protected Label[] getLabels() { super.getLabels(); return new Label[] { new Label() }; } } /** * JasminifierAdapterTest tests. * * @author Eric Bruneton */ public class JasminifierClassAdapterTest extends TestCase { protected String n; protected InputStream is; public static TestSuite suite() throws Exception { return new JasminifierClassAdapterTest().getSuite(); } public JasminifierClassAdapterTest() { super("test"); } protected void init(final String n, final InputStream is) { this.n = n; this.is = is; } protected TestSuite getSuite() throws Exception { TestSuite suite = new TestSuite(getClass().getName()); String files = System.getProperty("asm.test") + ","; String clazz = System.getProperty("asm.test.class"); String partcount = System.getProperty("parts"); String partid = System.getProperty("part"); int parts = partcount == null ? 1 : Integer.parseInt(partcount); int part = partid == null ? 0 : Integer.parseInt(partid); int id = 0; while (files.indexOf(',') != -1) { String file = files.substring(0, files.indexOf(',')); files = files.substring(files.indexOf(',') + 1); File f = new File(file); if (f.isDirectory()) { scanDirectory("", f, suite, clazz); } else { ZipFile zip = new ZipFile(file); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry e = (ZipEntry) entries.nextElement(); String n = e.getName(); String p = n.replace('/', '.'); System.out.println(n+" "+clazz); if (n.endsWith(".class") && (clazz == null || p.indexOf(clazz) != -1)) { n = p.substring(0, p.length() - 6); if (id % parts == part) { JasminifierClassAdapterTest t; InputStream is = zip.getInputStream(e); t = new JasminifierClassAdapterTest(); t.init(n, is); suite.addTest(t); } ++id; } } } } return suite; } private void scanDirectory( final String path, final File f, final TestSuite suite, final String clazz) throws Exception { File[] fs = f.listFiles(); for (int i = 0; i < fs.length; ++i) { String n = fs[i].getName(); String qn = path.length() == 0 ? n : path + "." + n; if (fs[i].isDirectory()) { scanDirectory(qn, fs[i], suite, clazz); } else if (qn.endsWith(".class") && (clazz == null || qn.indexOf(clazz) != -1)) { qn = qn.substring(0, qn.length() - 6); InputStream is = new FileInputStream(fs[i]); JasminifierClassAdapterTest t; t = new JasminifierClassAdapterTest(); t.init(qn, is); suite.addTest(t); } } } public void assertEquals(final ClassReader cr1, final ClassReader cr2) throws Exception { assertEquals(cr1, cr2, null, null); } public void assertEquals( final ClassReader cr1, final ClassReader cr2, final ClassFilter filter1, final ClassFilter filter2) throws Exception { if (!Arrays.equals(cr1.b, cr2.b)) { StringWriter sw1 = new StringWriter(); StringWriter sw2 = new StringWriter(); ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1)); ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2)); if (filter1 != null) { filter1.setNext(cv1); } if (filter2 != null) { filter2.setNext(cv2); } cr1.accept(filter1 == null ? cv1 : filter1, 0); cr2.accept(filter2 == null ? cv2 : filter2, 0); String s1 = sw1.toString(); String s2 = sw2.toString(); assertEquals("different data", s1, s2); } } public String getName() { return super.getName() + ": " + n; } public void test() throws Exception { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new JasminifierClassAdapter(pw, cw); cr.accept(cv, new Attribute[] { new Comment(), new CodeComment() }, ClassReader.EXPAND_FRAMES); pw.close(); String jasmin = sw.toString(); ClassFile cf = new ClassFile(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); cf.readJasmin(new StringReader(jasmin), "test", false); if (cf.errorCount() != 0) { throw new jasError(); } cf.write(bos); bos.close(); assertEquals(cr, new ClassReader(bos.toByteArray()), new ClassFilter() { @Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { access |= Opcodes.ACC_SUPER; // Jasmin bug workaround super.visit(version, access, name, signature, superName, interfaces); } }, null); } } asm-3.3.2/examples/jasmin/test/build.xml0000644000175000017500000000245511101041231020122 0ustar twernertwerner asm-3.3.2/examples/common/0000755000175000017500000000000011633370220015340 5ustar twernertwernerasm-3.3.2/examples/common/README.txt0000644000175000017500000000107710007705133017042 0ustar twernertwernerThis directory contains the examples of the product. It contains(*) the following items: - lib: jar files shared by all examples, - etc: configuration files shared by all examples, - README.txt: explains the organisation of the examples directory, - all other directories contain(*) the following items: - README.txt file: describes the example and its configuration, - lib: jar files needed by the example, - etc: configuration files needed by the example, - src: source code of the example. (*) some items may not be present, depending on the product or example.asm-3.3.2/examples/common/etc/0000755000175000017500000000000011633370220016113 5ustar twernertwernerasm-3.3.2/examples/common/etc/build.properties0000644000175000017500000000173710204100644021332 0ustar twernertwerner# Wich compiler do you want use ? # build.compiler jikes # Class path for the ASM library (version @product.version@) # See http://asm.objectweb.org asm.path ../../lib/asm-@product.version@.jar # Class path for the ASM tree library (version @product.version@) # See http://asm.objectweb.org asm.tree.path ../../lib/asm-tree-@product.version@.jar # Class path for the ASM analysis library (version @product.version@) # See http://asm.objectweb.org asm.analysis.path ../../lib/asm-analysis-@product.version@.jar # Class path for the ASM attrs library (version @product.version@) # See http://asm.objectweb.org asm.attrs.path ../../lib/asm-attrs-@product.version@.jar # Class path for the ASM util library (version @product.version@) # See http://asm.objectweb.org asm.util.path ../../lib/asm-util-@product.version@.jar # Class path for the ASM commons library (version @product.version@) # See http://asm.objectweb.org asm.commons.path ../../lib/asm-commons-@product.version@.jar asm-3.3.2/examples/common/build.xml0000644000175000017500000000655010263445565017204 0ustar twernertwerner asm-3.3.2/examples/xml/0000755000175000017500000000000011633370220014650 5ustar twernertwernerasm-3.3.2/examples/xml/readme.txt0000644000175000017500000000162510340642030016645 0ustar twernertwerner This directory contains sample XSL transformation templates that demonstrate features of org.objectweb.asm.xml package. copy.xsl Copying source document into target without changes. strip.xsl Strips all attribute values from the target XML. Result document can't be used to generate bytecode. annotate.xsl Adds comments for labels and variable instructions to the target XML document. linenumbers.xsl Adds code to dump source line numbers for the executing code to System.err profile.xsl Adds code to dump execution time for each method to System.err You can use the following command to transform java -jar asm-xml-.jar [-in ] [-out ] [-xslt ] where and is one of code, xml or singlexml when -in or -out is omitted sysin and sysout would be used asm-3.3.2/examples/xml/profile.xsl0000644000175000017500000000750310033740602017043 0ustar twernertwerner asm-3.3.2/examples/xml/copy.xsl0000644000175000017500000000376710033740602016365 0ustar twernertwerner asm-3.3.2/examples/xml/linenumbers.xsl0000644000175000017500000000574510033740602017734 0ustar twernertwerner Line: asm-3.3.2/examples/xml/strip.xsl0000644000175000017500000000444010035657424016554 0ustar twernertwerner asm-3.3.2/examples/xml/annotate.xsl0000644000175000017500000001141210033740602017206 0ustar twernertwerner Incoming calls: Line: try start try end catch () asm-3.3.2/examples/adapt/0000755000175000017500000000000011633370220015141 5ustar twernertwernerasm-3.3.2/examples/adapt/src/0000755000175000017500000000000011633370220015730 5ustar twernertwernerasm-3.3.2/examples/adapt/src/Adapt.java0000644000175000017500000002016210635277351017641 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.Method; /** * @author Eric Bruneton */ public class Adapt extends ClassLoader { protected synchronized Class loadClass( final String name, final boolean resolve) throws ClassNotFoundException { if (name.startsWith("java.")) { System.err.println("Adapt: loading class '" + name + "' without on the fly adaptation"); return super.loadClass(name, resolve); } else { System.err.println("Adapt: loading class '" + name + "' with on the fly adaptation"); } // gets an input stream to read the bytecode of the class String resource = name.replace('.', '/') + ".class"; InputStream is = getResourceAsStream(resource); byte[] b; // adapts the class on the fly try { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new TraceFieldClassAdapter(cw); cr.accept(cv, 0); b = cw.toByteArray(); } catch (Exception e) { throw new ClassNotFoundException(name, e); } // optional: stores the adapted class on disk try { FileOutputStream fos = new FileOutputStream(resource + ".adapted"); fos.write(b); fos.close(); } catch (Exception e) { } // returns the adapted class return defineClass(name, b, 0, b.length); } public static void main(final String args[]) throws Exception { // loads the application class (in args[0]) with an Adapt class loader ClassLoader loader = new Adapt(); Class c = loader.loadClass(args[0]); // calls the 'main' static method of this class with the // application arguments (in args[1] ... args[n]) as parameter Method m = c.getMethod("main", new Class[] { String[].class }); String[] applicationArgs = new String[args.length - 1]; System.arraycopy(args, 1, applicationArgs, 0, applicationArgs.length); m.invoke(null, new Object[] { applicationArgs }); } } class TraceFieldClassAdapter extends ClassAdapter implements Opcodes { private String owner; public TraceFieldClassAdapter(final ClassVisitor cv) { super(cv); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { owner = name; super.visit(version, access, name, signature, superName, interfaces); } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { FieldVisitor fv = super.visitField(access, name, desc, signature, value); if ((access & ACC_STATIC) == 0) { Type t = Type.getType(desc); int size = t.getSize(); // generates getter method String gDesc = "()" + desc; MethodVisitor gv = cv.visitMethod(ACC_PRIVATE, "_get" + name, gDesc, null, null); gv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); gv.visitLdcInsn("_get" + name + " called"); gv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); gv.visitVarInsn(ALOAD, 0); gv.visitFieldInsn(GETFIELD, owner, name, desc); gv.visitInsn(t.getOpcode(IRETURN)); gv.visitMaxs(1 + size, 1); gv.visitEnd(); // generates setter method String sDesc = "(" + desc + ")V"; MethodVisitor sv = cv.visitMethod(ACC_PRIVATE, "_set" + name, sDesc, null, null); sv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;"); sv.visitLdcInsn("_set" + name + " called"); sv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); sv.visitVarInsn(ALOAD, 0); sv.visitVarInsn(t.getOpcode(ILOAD), 1); sv.visitFieldInsn(PUTFIELD, owner, name, desc); sv.visitInsn(RETURN); sv.visitMaxs(1 + size, 1 + size); sv.visitEnd(); } return fv; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); return mv == null ? null : new TraceFieldCodeAdapter(mv, owner); } } class TraceFieldCodeAdapter extends MethodAdapter implements Opcodes { private String owner; public TraceFieldCodeAdapter(final MethodVisitor mv, final String owner) { super(mv); this.owner = owner; } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { if (owner.equals(this.owner)) { if (opcode == GETFIELD) { // replaces GETFIELD f by INVOKESPECIAL _getf String gDesc = "()" + desc; visitMethodInsn(INVOKESPECIAL, owner, "_get" + name, gDesc); return; } else if (opcode == PUTFIELD) { // replaces PUTFIELD f by INVOKESPECIAL _setf String sDesc = "(" + desc + ")V"; visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc); return; } } super.visitFieldInsn(opcode, owner, name, desc); } } asm-3.3.2/examples/adapt/src/ArraySet.java0000644000175000017500000000625210635277351020346 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** * @author Eric Bruneton */ public class ArraySet { private int[] values = new int[3]; private int size; public boolean contains(final int v) { for (int i = 0; i < size; ++i) { if (values[i] == v) { return true; } } return false; } public void add(final int v) { if (!contains(v)) { if (size == values.length) { System.err.println("[enlarge]"); int[] newValues = new int[values.length + 3]; System.arraycopy(values, 0, newValues, 0, size); values = newValues; } values[size++] = v; } } public void remove(final int v) { int i = 0; int j = 0; while (i < size) { int u = values[i]; if (u != v) { values[j++] = u; } ++i; } size = j; } // test method public static void main(final String[] args) { ArraySet s = new ArraySet(); System.err.println("add 1"); s.add(1); System.err.println("add 1"); s.add(1); System.err.println("add 2"); s.add(2); System.err.println("add 4"); s.add(4); System.err.println("add 8"); s.add(8); System.err.println("contains 3 = " + s.contains(3)); System.err.println("contains 1 = " + s.contains(1)); System.err.println("remove 1"); s.remove(1); System.err.println("contains 1 = " + s.contains(1)); } } asm-3.3.2/examples/adapt/etc/0000755000175000017500000000000011633370220015714 5ustar twernertwernerasm-3.3.2/examples/adapt/etc/execute.properties0000644000175000017500000000005407615213177021507 0ustar twernertwernerrun.classname Adapt run.parameters ArraySet asm-3.3.2/examples/adapt/README0000644000175000017500000000006407513254643016035 0ustar twernertwernerThis file must contain a description of the example asm-3.3.2/examples/compile/0000755000175000017500000000000011633370220015500 5ustar twernertwernerasm-3.3.2/examples/compile/src/0000755000175000017500000000000011633370220016267 5ustar twernertwernerasm-3.3.2/examples/compile/src/Compile.java0000644000175000017500000001746510635277351020553 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Label; import java.io.FileOutputStream; /** * @author Eric Bruneton */ public class Compile extends ClassLoader { public static void main(final String[] args) throws Exception { // creates the expression tree corresponding to // exp(i) = i > 3 && 6 > i Exp exp = new And(new GT(new Var(0), new Cst(3)), new GT(new Cst(6), new Var(0))); // compiles this expression into an Expression class Compile main = new Compile(); byte[] b = exp.compile("Example"); FileOutputStream fos = new FileOutputStream("Example.class"); fos.write(b); fos.close(); Class expClass = main.defineClass("Example", b, 0, b.length); // instantiates this compiled expression class... Expression iexp = (Expression) expClass.newInstance(); // ... and uses it to evaluate exp(0) to exp(9) for (int i = 0; i < 10; ++i) { boolean val = iexp.eval(i, 0) == 1; System.out.println(i + " > 3 && " + i + " < 6 = " + val); } } } /** * An abstract expression. * * @author Eric Bruneton */ abstract class Exp implements Opcodes { /* * Returns the byte code of an Expression class corresponding to this * expression. */ byte[] compile(final String name) { // class header String[] itfs = { Expression.class.getName() }; ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, name, null, "java/lang/Object", itfs); // default public constructor MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); // eval method mv = cw.visitMethod(ACC_PUBLIC, "eval", "(II)I", null, null); compile(mv); mv.visitInsn(IRETURN); // max stack and max locals automatically computed mv.visitMaxs(0, 0); mv.visitEnd(); return cw.toByteArray(); } /* * Compile this expression. This method must append to the given code writer * the byte code that evaluates and pushes on the stack the value of this * expression. */ abstract void compile(MethodVisitor mv); } /** * A constant expression. */ class Cst extends Exp { int value; Cst(final int value) { this.value = value; } void compile(final MethodVisitor mv) { // pushes the constant's value onto the stack mv.visitLdcInsn(new Integer(value)); } } /** * A variable reference expression. */ class Var extends Exp { int index; Var(final int index) { this.index = index + 1; } void compile(final MethodVisitor mv) { // pushes the 'index' local variable onto the stack mv.visitVarInsn(ILOAD, index); } } /** * An abstract binary expression. */ abstract class BinaryExp extends Exp { Exp e1; Exp e2; BinaryExp(final Exp e1, final Exp e2) { this.e1 = e1; this.e2 = e2; } } /** * An addition expression. */ class Add extends BinaryExp { Add(final Exp e1, final Exp e2) { super(e1, e2); } void compile(final MethodVisitor mv) { // compiles e1, e2, and adds an instruction to add the two values e1.compile(mv); e2.compile(mv); mv.visitInsn(IADD); } } /** * A multiplication expression. */ class Mul extends BinaryExp { Mul(final Exp e1, final Exp e2) { super(e1, e2); } void compile(final MethodVisitor mv) { // compiles e1, e2, and adds an instruction to multiply the two values e1.compile(mv); e2.compile(mv); mv.visitInsn(IMUL); } } /** * A "greater than" expression. */ class GT extends BinaryExp { GT(final Exp e1, final Exp e2) { super(e1, e2); } void compile(final MethodVisitor mv) { // compiles e1, e2, and adds the instructions to compare the two values e1.compile(mv); e2.compile(mv); Label iftrue = new Label(); Label end = new Label(); mv.visitJumpInsn(IF_ICMPGT, iftrue); // case where e1 <= e2 : pushes false and jump to "end" mv.visitLdcInsn(new Integer(0)); mv.visitJumpInsn(GOTO, end); // case where e1 > e2 : pushes true mv.visitLabel(iftrue); mv.visitLdcInsn(new Integer(1)); mv.visitLabel(end); } } /** * A logical "and" expression. */ class And extends BinaryExp { And(final Exp e1, final Exp e2) { super(e1, e2); } void compile(final MethodVisitor mv) { // compiles e1 e1.compile(mv); // tests if e1 is false mv.visitInsn(DUP); Label end = new Label(); mv.visitJumpInsn(IFEQ, end); // case where e1 is true : e1 && e2 is equal to e2 mv.visitInsn(POP); e2.compile(mv); // if e1 is false, e1 && e2 is equal to e1: // we jump directly to this label, without evaluating e2 mv.visitLabel(end); } } /** * A logical "or" expression. */ class Or extends BinaryExp { Or(final Exp e1, final Exp e2) { super(e1, e2); } void compile(final MethodVisitor mv) { // compiles e1 e1.compile(mv); // tests if e1 is true mv.visitInsn(DUP); Label end = new Label(); mv.visitJumpInsn(IFNE, end); // case where e1 is false : e1 || e2 is equal to e2 mv.visitInsn(POP); e2.compile(mv); // if e1 is true, e1 || e2 is equal to e1: // we jump directly to this label, without evaluating e2 mv.visitLabel(end); } } /** * A logical "not" expression. */ class Not extends Exp { Exp e; Not(final Exp e) { this.e = e; } void compile(final MethodVisitor mv) { // computes !e1 by evaluating 1 - e1 mv.visitLdcInsn(new Integer(1)); e.compile(mv); mv.visitInsn(ISUB); } } asm-3.3.2/examples/compile/src/Expression.java0000644000175000017500000000377010635277351021314 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** * An integer or boolean expression of at most two variables. * * @author Eric Bruneton */ public interface Expression { /** * Evaluates this expression. * * @param i the value of the first variable. * @param j the value of the second variable. * @return the value of this expression for the given variable values. */ int eval(int i, int j); } asm-3.3.2/examples/compile/etc/0000755000175000017500000000000011633370220016253 5ustar twernertwernerasm-3.3.2/examples/compile/etc/execute.properties0000644000175000017500000000004507513254643022046 0ustar twernertwernerrun.classname Compile run.parameters asm-3.3.2/examples/compile/README0000644000175000017500000000006407513254643016374 0ustar twernertwernerThis file must contain a description of the example asm-3.3.2/examples/dependencies/0000755000175000017500000000000011633370220016476 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/0000755000175000017500000000000011633370220017265 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/org/0000755000175000017500000000000011633370220020054 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/org/objectweb/0000755000175000017500000000000011633370220022020 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/org/objectweb/asm/0000755000175000017500000000000011633370220022600 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/org/objectweb/asm/depend/0000755000175000017500000000000011633370220024037 5ustar twernertwernerasm-3.3.2/examples/dependencies/src/org/objectweb/asm/depend/DependencyTracker.java0000644000175000017500000001664510635277351030324 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.depend; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.imageio.ImageIO; import org.objectweb.asm.ClassReader; /** * DependencyTracker * * @author Eugene Kuleshov * * @see http://www.onjava.com/pub/a/onjava/2005/08/17/asm3.html */ public class DependencyTracker { private static final int CELL_PAD = 1; private static final int GRID_SIZE = 10; private static final int CELLS_SIZE = 8; private static final int LABEL_WIDTH = 200; private static final String LABEL_FONT = "Tahoma-9"; public static void main(final String[] args) throws IOException { DependencyVisitor v = new DependencyVisitor(); ZipFile f = new ZipFile(args[0]); long l1 = System.currentTimeMillis(); Enumeration< ? extends ZipEntry> en = f.entries(); while (en.hasMoreElements()) { ZipEntry e = en.nextElement(); String name = e.getName(); if (name.endsWith(".class")) { new ClassReader(f.getInputStream(e)).accept(v, 0); } } long l2 = System.currentTimeMillis(); Map> globals = v.getGlobals(); Set jarPackages = globals.keySet(); Set classPackages = v.getPackages(); int size = classPackages.size(); System.err.println("time: " + (l2 - l1) / 1000f + " " + size); String[] jarNames = jarPackages.toArray(new String[jarPackages.size()]); String[] classNames = classPackages.toArray(new String[classPackages.size()]); Arrays.sort(jarNames); Arrays.sort(classNames); buildDiagram(jarNames, classNames, globals); } public static void buildDiagram( final String[] jarNames, final String[] classNames, final Map> globals) throws IOException { // normalize int max = 0; for (int i = 0; i < classNames.length; i++) { Map map = globals.get(classNames[i]); if (map == null) { continue; } Integer maxCount = Collections.max(map.values()); if (maxCount > max) { max = maxCount; } } List colors = new ArrayList(); for (int i = LABEL_WIDTH; i >= 0; i--) { colors.add(new Color(i, i, 255)); } for (int i = 255; i >= 128; i--) { colors.add(new Color(0, 0, i)); } int maxcolor = colors.size() - 1; int heigh = CELL_PAD + (CELLS_SIZE + CELL_PAD) * classNames.length; int width = CELL_PAD + (CELLS_SIZE + CELL_PAD) * jarNames.length; BufferedImage img = new BufferedImage(width + LABEL_WIDTH, heigh + LABEL_WIDTH, BufferedImage.TYPE_INT_RGB); Graphics2D g = img.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(Color.WHITE); g.fillRect(0, 0, width + LABEL_WIDTH, heigh + LABEL_WIDTH); // draw lines g.setColor(Color.LIGHT_GRAY); for (int y = GRID_SIZE; y < classNames.length; y += GRID_SIZE) { g.drawLine(0, y * (CELLS_SIZE + CELL_PAD), width, y * (CELLS_SIZE + CELL_PAD)); } for (int x = GRID_SIZE; x < jarNames.length; x += GRID_SIZE) { g.drawLine(x * (CELLS_SIZE + CELL_PAD), 0, x * (CELLS_SIZE + CELL_PAD), heigh); } // draw diagram for (int y = 0; y < classNames.length; y++) { // System.err.println( y+" : "+classNames[ y]); for (int x = 0; x < jarNames.length; x++) { Map map = globals.get(jarNames[x]); Integer count = map == null ? null : map.get(classNames[y]); if (count != null) { int b = (int) ((float) count * maxcolor / max); g.setColor(colors.get(b)); g.fillRect(CELL_PAD + x * (CELLS_SIZE + CELL_PAD), CELL_PAD + y * (CELLS_SIZE + CELL_PAD), CELLS_SIZE, CELLS_SIZE); } } } // draw labels Font f = Font.decode(LABEL_FONT); g.setFont(f); // g.setColor( new Color( 70, 70, 255)); g.setColor(Color.GRAY); for (int y = 0; y < classNames.length; y++) { AffineTransform trans = g.getTransform(); g.transform(AffineTransform.getTranslateInstance(CELL_PAD * 2 + width, CELLS_SIZE + y * (CELLS_SIZE + CELL_PAD))); g.transform(AffineTransform.getRotateInstance(Math.PI / 12)); g.drawString(classNames[y], 0, 0); g.setTransform(trans); } for (int x = 0; x < jarNames.length; x++) { AffineTransform trans = g.getTransform(); g.transform(AffineTransform.getTranslateInstance(CELL_PAD * 2 + x * (CELLS_SIZE + CELL_PAD), heigh + CELL_PAD * 2)); g.transform(AffineTransform.getRotateInstance(Math.PI / 2.5)); g.drawString(jarNames[x], 0, 0); g.setTransform(trans); } FileOutputStream fos = new FileOutputStream("test.png"); ImageIO.write(img, "png", fos); fos.flush(); fos.close(); } } asm-3.3.2/examples/dependencies/src/org/objectweb/asm/depend/DependencyVisitor.java0000644000175000017500000002577011503337206030356 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.depend; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; /** * DependencyVisitor * * @author Eugene Kuleshov */ public class DependencyVisitor implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor { Set packages = new HashSet(); Map> groups = new HashMap>(); Map current; public Map> getGlobals() { return groups; } public Set getPackages() { return packages; } // ClassVisitor public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { String p = getGroupKey(name); current = groups.get(p); if (current == null) { current = new HashMap(); groups.put(p, current); } if (signature == null) { if (superName != null) { addInternalName(superName); } addInternalNames(interfaces); } else { addSignature(signature); } } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { addDesc(desc); return this; } public void visitAttribute(final Attribute attr) { } public FieldVisitor visitField( final int access, final String name, final String desc, final String signature, final Object value) { if (signature == null) { addDesc(desc); } else { addTypeSignature(signature); } if (value instanceof Type) { addType((Type) value); } return this; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (signature == null) { addMethodDesc(desc); } else { addSignature(signature); } addInternalNames(exceptions); return this; } public void visitSource(final String source, final String debug) { } public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { // addName( outerName); // addName( innerName); } public void visitOuterClass( final String owner, final String name, final String desc) { // addName(owner); // addMethodDesc(desc); } // MethodVisitor public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { addDesc(desc); return this; } public void visitTypeInsn(final int opcode, final String type) { addType(Type.getObjectType(type)); } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { addInternalName(owner); addDesc(desc); } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { addInternalName(owner); addMethodDesc(desc); } public void visitLdcInsn(final Object cst) { if (cst instanceof Type) { addType((Type) cst); } } public void visitMultiANewArrayInsn(final String desc, final int dims) { addDesc(desc); } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { addTypeSignature(signature); } public AnnotationVisitor visitAnnotationDefault() { return this; } public void visitCode() { } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { } public void visitInsn(final int opcode) { } public void visitIntInsn(final int opcode, final int operand) { } public void visitVarInsn(final int opcode, final int var) { } public void visitJumpInsn(final int opcode, final Label label) { } public void visitLabel(final Label label) { } public void visitIincInsn(final int var, final int increment) { } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels) { } public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels) { } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { if (type != null) { addInternalName(type); } } public void visitLineNumber(final int line, final Label start) { } public void visitMaxs(final int maxStack, final int maxLocals) { } // AnnotationVisitor public void visit(final String name, final Object value) { if (value instanceof Type) { addType((Type) value); } } public void visitEnum( final String name, final String desc, final String value) { addDesc(desc); } public AnnotationVisitor visitAnnotation( final String name, final String desc) { addDesc(desc); return this; } public AnnotationVisitor visitArray(final String name) { return this; } // SignatureVisitor String signatureClassName; public void visitFormalTypeParameter(final String name) { } public SignatureVisitor visitClassBound() { return this; } public SignatureVisitor visitInterfaceBound() { return this; } public SignatureVisitor visitSuperclass() { return this; } public SignatureVisitor visitInterface() { return this; } public SignatureVisitor visitParameterType() { return this; } public SignatureVisitor visitReturnType() { return this; } public SignatureVisitor visitExceptionType() { return this; } public void visitBaseType(final char descriptor) { } public void visitTypeVariable(final String name) { } public SignatureVisitor visitArrayType() { return this; } public void visitClassType(final String name) { signatureClassName = name; addInternalName(name); } public void visitInnerClassType(final String name) { signatureClassName = signatureClassName + "$" + name; addInternalName(signatureClassName); } public void visitTypeArgument() { } public SignatureVisitor visitTypeArgument(final char wildcard) { return this; } // common public void visitEnd() { } // --------------------------------------------- private String getGroupKey(String name) { int n = name.lastIndexOf('/'); if (n > -1) { name = name.substring(0, n); } packages.add(name); return name; } private void addName(final String name) { if (name == null) { return; } String p = getGroupKey(name); if (current.containsKey(p)) { current.put(p, current.get(p) + 1); } else { current.put(p, 1); } } private void addInternalName(final String name) { addType(Type.getObjectType(name)); } private void addInternalNames(final String[] names) { for (int i = 0; names != null && i < names.length; i++) { addInternalName(names[i]); } } private void addDesc(final String desc) { addType(Type.getType(desc)); } private void addMethodDesc(final String desc) { addType(Type.getReturnType(desc)); Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; i++) { addType(types[i]); } } private void addType(final Type t) { switch (t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getInternalName()); break; } } private void addSignature(final String signature) { if (signature != null) { new SignatureReader(signature).accept(this); } } private void addTypeSignature(final String signature) { if (signature != null) { new SignatureReader(signature).acceptType(this); } } } asm-3.3.2/examples/helloworld/0000755000175000017500000000000011633370220016223 5ustar twernertwernerasm-3.3.2/examples/helloworld/src/0000755000175000017500000000000011633370220017012 5ustar twernertwernerasm-3.3.2/examples/helloworld/src/Helloworld.java0000644000175000017500000001412210635277351022004 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import java.io.FileOutputStream; import java.io.PrintStream; /** * @author Eric Bruneton */ public class Helloworld extends ClassLoader implements Opcodes { public static void main(final String args[]) throws Exception { // Generates the bytecode corresponding to the following Java class: // // public class Example { // public static void main (String[] args) { // System.out.println("Hello world!"); // } // } // creates a ClassWriter for the Example public class, // which inherits from Object ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); // creates a MethodWriter for the (implicit) constructor MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); // pushes the 'this' variable mw.visitVarInsn(ALOAD, 0); // invokes the super class constructor mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mw.visitInsn(RETURN); // this code uses a maximum of one stack element and one local variable mw.visitMaxs(1, 1); mw.visitEnd(); // creates a MethodWriter for the 'main' method mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); // pushes the 'out' field (of type PrintStream) of the System class mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); // pushes the "Hello World!" String constant mw.visitLdcInsn("Hello world!"); // invokes the 'println' method (defined in the PrintStream class) mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mw.visitInsn(RETURN); // this code uses a maximum of two stack elements and two local // variables mw.visitMaxs(2, 2); mw.visitEnd(); // gets the bytecode of the Example class, and loads it dynamically byte[] code = cw.toByteArray(); FileOutputStream fos = new FileOutputStream("Example.class"); fos.write(code); fos.close(); Helloworld loader = new Helloworld(); Class exampleClass = loader.defineClass("Example", code, 0, code.length); // uses the dynamically generated class to print 'Helloworld' exampleClass.getMethods()[0].invoke(null, new Object[] { null }); // ------------------------------------------------------------------------ // Same example with a GeneratorAdapter (more convenient but slower) // ------------------------------------------------------------------------ cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); // creates a GeneratorAdapter for the (implicit) constructor Method m = Method.getMethod("void ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m); mg.returnValue(); mg.endMethod(); // creates a GeneratorAdapter for the 'main' method m = Method.getMethod("void main (String[])"); mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); mg.push("Hello world!"); mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); mg.returnValue(); mg.endMethod(); cw.visitEnd(); code = cw.toByteArray(); loader = new Helloworld(); exampleClass = loader.defineClass("Example", code, 0, code.length); // uses the dynamically generated class to print 'Helloworld' exampleClass.getMethods()[0].invoke(null, new Object[] { null }); } } asm-3.3.2/examples/helloworld/etc/0000755000175000017500000000000011633370220016776 5ustar twernertwernerasm-3.3.2/examples/helloworld/etc/execute.properties0000644000175000017500000000005007513254643022565 0ustar twernertwernerrun.classname Helloworld run.parameters asm-3.3.2/examples/helloworld/README0000644000175000017500000000006407513254643017117 0ustar twernertwernerThis file must contain a description of the example asm-3.3.2/examples/jbfc/0000755000175000017500000000000011633370220014754 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/0000755000175000017500000000000011633370220015543 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/jbfc.java0000644000175000017500000000621010635277351017325 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.jbfc.BFCompiler; import org.objectweb.asm.util.TraceClassVisitor; /** * A naive implementation of compiler for Brain**** language. * http://www.muppetlabs.com/~breadbox/bf/ * * * @author Eugene Kuleshov */ public class jbfc { public static void main(final String[] args) throws IOException { if (args.length < 2) { System.out.println("Usage: jbfc [-v] "); return; } boolean verbose = false; String fileName = null; String className = null; for (int i = 0; i < args.length; i++) { if ("-v".equals(args[i])) { verbose = true; } else { fileName = args[i]; className = args[i + 1]; break; } } FileReader r = new FileReader(fileName); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); BFCompiler c = new BFCompiler(); if (verbose) { c.compile(r, className, fileName, new TraceClassVisitor(cw, new PrintWriter(System.out))); } else { c.compile(r, className, fileName, cw); } r.close(); FileOutputStream os = new FileOutputStream(className + ".class"); os.write(cw.toByteArray()); os.flush(); os.close(); } } asm-3.3.2/examples/jbfc/src/org/0000755000175000017500000000000011633370220016332 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/org/objectweb/0000755000175000017500000000000011633370220020276 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/org/objectweb/asm/0000755000175000017500000000000011633370220021056 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/org/objectweb/asm/jbfc/0000755000175000017500000000000011633370220021762 5ustar twernertwernerasm-3.3.2/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompilerTest.java0000644000175000017500000001553210635277351025471 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.jbfc; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import junit.framework.TestCase; import org.objectweb.asm.ClassWriter; /** * A naive implementation of compiler for Brain**** language. * http://www.muppetlabs.com/~breadbox/bf/ * * * @author Eugene Kuleshov */ public class BFCompilerTest extends TestCase { private BFCompiler bc; private ClassWriter cw; protected void setUp() throws Exception { super.setUp(); bc = new BFCompiler(); cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); } public void testCompileHelloWorld() throws Throwable { assertEquals("Hello World!\n", execute("Hello", ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]" + "<.#>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[" + "<++++>-]<+.[-]++++++++++.", "")); } public void testCompileEcho() throws Throwable { assertEquals("AAA", execute("Echo", ",+[-.,+]", "AAA")); } public void testCompileYaPi() throws Throwable { assertEquals("3.1415926\n", execute("YaPi", ">+++++[<+++++++++>-]>>>>>>\r\n\r\n+++++ +++ (7 " + "digits)\r\n\r\n[<<+>++++++++++>-]<<+>>+++<[->>+" + "<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>[-]>[<+>-]<[>+<[" + "-\r\n>>>>>>>+<<<<<<<]>[->+>>>>>>+<<<<<<<]>>>>++" + ">>-]>[-]<<<[<<<<<<<]<[->>>>>[>>>>>>>]<\r\n<<<<<" + "<[>>>>[-]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<<[<<++" + "++++++++>>-]>[<<<<[>+>>+<<<-\r\n]>>>[<<<+>>>-]>" + "-]<<<<[>>++>+<<<-]>>->[<<<+>>>-]>[-]<<<[->>+<-[" + ">>>]>[[<+>-]>+>>]<\r\n<<<<]>[-]<<<<<<<<<]>+>>>>" + ">>->>>>[<<<<<<<<+>>>>>>>>-]<<<<<<<[-]++++++++++" + "<[->>+<-\r\n[>>>]>[[<+>-]>+>>]<<<<<]>[-]>[>>>>>" + "+<<<<<-]>[<+>>+<-]>[<+>-]<<<+<+>>[-[-[-[-[-[-\r" + "\n[-[-[-<->[-<+<->>[<<+>>[-]]]]]]]]]]]]<[+++++[" + "<<<<++++++++>>>>>++++++++<-]>+<<<<-\r\n>>[>+>-<" + "<<<<+++++++++>>>-]<<<<[>>>>>>+<<<<<<-]<[>>>>>>>" + ".<<<<<<<<[+.[-]]>>]>[<]<+\r\n>>>[<.>-]<[-]>>>>>" + "[-]<[>>[<<<<<<<+>>>>>>>-]<<-]]>>[-]>+<<<<[-]<]+" + "+++++++++.", "")); } public void testCompileTest1() throws Throwable { assertEquals("H\n", execute("Test1", "[]++++++++++[>++++++++++++++++++>+++++++>+<<<-]A;?@![#>>" + "+<<]>[>++<[-]]>.>.", "")); } private String execute( final String name, final String code, final String input) throws Throwable { bc.compile(new StringReader(code), name, name, cw); // ClassReader cr = new ClassReader(cw.toByteArray()); // cr.accept(new TraceClassVisitor(null, new PrintWriter(System.err)), // true); // File tmp = File.createTempFile(name, ".class"); // System.err.println(tmp.getAbsolutePath()); // FileOutputStream fos = new FileOutputStream(tmp); // fos.write(cw.toByteArray()); // fos.flush(); // fos.close(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); InputStream is = System.in; PrintStream os = System.out; System.setIn(new ByteArrayInputStream(input.getBytes())); System.setOut(new PrintStream(bos)); try { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader(), name, cw.toByteArray()); Class c = cl.loadClass(name); Method m = c.getDeclaredMethod("main", new Class[] { String[].class }); m.invoke(null, new Object[] { new String[0] }); } catch (InvocationTargetException ex) { throw ex.getCause(); } finally { System.setIn(is); System.setOut(os); } return new String(bos.toByteArray(), "ASCII"); } private static final class TestClassLoader extends ClassLoader { private final String className; private final ClassLoader cl; private final byte[] bytecode; public TestClassLoader( final ClassLoader cl, final String className, final byte[] bytecode) { super(); this.cl = cl; this.className = className; this.bytecode = bytecode; } public Class loadClass(final String name) throws ClassNotFoundException { if (className.equals(name)) { return super.defineClass(className, bytecode, 0, bytecode.length); } return cl.loadClass(name); } } } asm-3.3.2/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompiler.java0000644000175000017500000001641210635277351024627 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.jbfc; import java.io.IOException; import java.io.Reader; import java.util.Stack; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * A naive implementation of compiler for Brain**** language. * http://www.muppetlabs.com/~breadbox/bf/ * * * @author Eugene Kuleshov */ public class BFCompiler implements Opcodes { private static final int V_IS = 0; private static final int V_OS = 1; private static final int V_P = 2; private static final int V_D = 3; public void compile( final Reader r, final String className, final String sourceName, final ClassVisitor cv) throws IOException { cv.visit(Opcodes.V1_3, ACC_PUBLIC, className.replace('.', '/'), null, "java/lang/Object", null); cv.visitSource(sourceName, null); MethodVisitor mv; { mv = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { // Init local vars for BF environment: // 0 InputStream // 1 OutputStream // 2 Data Pointer // 3 Data Array (int[ 30000]) mv = cv.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "in", "Ljava/io/InputStream;"); mv.visitVarInsn(ASTORE, V_IS); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitVarInsn(ASTORE, V_OS); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, V_P); mv.visitIntInsn(SIPUSH, 30000); mv.visitIntInsn(NEWARRAY, T_INT); mv.visitVarInsn(ASTORE, V_D); Stack labels = new Stack(); int d = 0; int p = 0; int c; while ((c = r.read()) != -1) { switch (c) { case '>': d = storeD(mv, d); p++; break; case '<': d = storeD(mv, d); p--; break; case '+': p = storeP(mv, p); d++; break; case '-': p = storeP(mv, p); d--; break; case '.': p = storeP(mv, p); d = storeD(mv, d); mv.visitVarInsn(ALOAD, V_OS); mv.visitVarInsn(ALOAD, V_D); mv.visitVarInsn(ILOAD, V_P); mv.visitInsn(IALOAD); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/OutputStream", "write", "(I)V"); break; case ',': p = storeP(mv, p); d = storeD(mv, d); mv.visitVarInsn(ALOAD, V_D); mv.visitVarInsn(ILOAD, V_P); mv.visitVarInsn(ALOAD, V_IS); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", "read", "()I"); mv.visitInsn(IASTORE); break; case '[': p = storeP(mv, p); d = storeD(mv, d); Label ls = new Label(); Label le = new Label(); labels.push(ls); labels.push(le); mv.visitJumpInsn(GOTO, le); mv.visitLabel(ls); break; case ']': p = storeP(mv, p); d = storeD(mv, d); mv.visitLabel((Label) labels.pop()); mv.visitVarInsn(ALOAD, V_D); mv.visitVarInsn(ILOAD, V_P); mv.visitInsn(IALOAD); mv.visitJumpInsn(IFNE, (Label) labels.pop()); break; } } mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } } private int storeD(final MethodVisitor mv, final int d) { if (d != 0) { mv.visitVarInsn(ALOAD, V_D); mv.visitVarInsn(ILOAD, V_P); mv.visitInsn(DUP2); mv.visitInsn(IALOAD); mv.visitIntInsn(SIPUSH, d); mv.visitInsn(IADD); mv.visitInsn(IASTORE); } return 0; } private int storeP(final MethodVisitor mv, final int p) { if (p != 0) { mv.visitIincInsn(V_P, p); } return 0; } } asm-3.3.2/examples/annotations/0000755000175000017500000000000011633370220016405 5ustar twernertwernerasm-3.3.2/examples/annotations/src/0000755000175000017500000000000011633370220017174 5ustar twernertwernerasm-3.3.2/examples/annotations/src/Annotations.java0000644000175000017500000001403710635277351022355 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class Annotations { public static void foo(final @NotNull String arg) { System.out.println(arg); } public static void main(final String[] args) throws Exception { System.out.println("Calling foo(null) results in a NullPointerException:"); try { foo(null); } catch (Exception e) { e.printStackTrace(System.out); } final String n = Annotations.class.getName(); final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassReader cr = new ClassReader(n); cr.accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { final Type[] args = Type.getArgumentTypes(desc); MethodVisitor v = cv.visitMethod(access, name, desc, signature, exceptions); return new MethodAdapter(v) { private final List params = new ArrayList(); public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { AnnotationVisitor av; av = mv.visitParameterAnnotation(parameter, desc, visible); if (desc.equals("LNotNull;")) { params.add(new Integer(parameter)); } return av; } public void visitCode() { int var = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; for (int p = 0; p < params.size(); ++p) { int param = ((Integer) params.get(p)).intValue(); for (int i = 0; i < param; ++i) { var += args[i].getSize(); } String c = "java/lang/IllegalArgumentException"; String d = "(Ljava/lang/String;)V"; Label end = new Label(); mv.visitVarInsn(Opcodes.ALOAD, var); mv.visitJumpInsn(Opcodes.IFNONNULL, end); mv.visitTypeInsn(Opcodes.NEW, c); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn("Argument " + param + " must not be null"); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, c, "", d); mv.visitInsn(Opcodes.ATHROW); mv.visitLabel(end); } } }; } }, 0); Class c = new ClassLoader() { public Class loadClass(final String name) throws ClassNotFoundException { if (name.equals(n)) { byte[] b = cw.toByteArray(); return defineClass(name, b, 0, b.length); } return super.loadClass(name); } }.loadClass(n); System.out.println(); System.out.println("Calling foo(null) on the transformed class results in an IllegalArgumentException:"); Method m = c.getMethod("foo", new Class[] { String.class }); try { m.invoke(null, new Object[] { null }); } catch (InvocationTargetException e) { e.getCause().printStackTrace(System.out); } } } asm-3.3.2/examples/annotations/src/NotNull.java0000644000175000017500000000344310635277351021452 0ustar twernertwerner/*** * ASM examples: examples showing how ASM can be used * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.CLASS) public @interface NotNull { String value() default ""; } asm-3.3.2/examples/annotations/etc/0000755000175000017500000000000011633370220017160 5ustar twernertwernerasm-3.3.2/examples/annotations/etc/execute.properties0000644000175000017500000000005310144074236022742 0ustar twernertwernerrun.classname Annotations run.parameters asm-3.3.2/examples/annotations/build.xml0000644000175000017500000000662310177716604020251 0ustar twernertwerner asm-3.3.2/archive/0000755000175000017500000000000011633370220013653 5ustar twernertwernerasm-3.3.2/archive/asm-xml.pom0000644000175000017500000000064610474422514015762 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM XML asm-xml jar asm-util asm asm-3.3.2/archive/README.txt0000644000175000017500000000164610007705133015357 0ustar twernertwernerThis directory contains ant files to build the jars of the product. The following rules describe the convention to write such files: - An ant file must build only one jar file. - The name of the ant file must be the name of the jar it builds: org-foo-bar.xml must build org-foo-bar.jar. - Among the elements which are included into a jar, you must specify a manifest. It is adviced to store the manifest file in this directory. The manifest file can be shared by several jars. The name of the manifest file must be similar to the name of the jar file. - Only the default task is called on each ant file. - The jar file must be produced into the ${dist.lib} directory. Sample ant file: ... asm-3.3.2/archive/asm-xml.xml0000644000175000017500000000315110474422514015761 0ustar twernertwerner asm-3.3.2/archive/asm.pom0000644000175000017500000000042710474422514015161 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM Core asm jar asm-3.3.2/archive/asm-util.pom0000644000175000017500000000065010474422514016132 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM Util asm-util jar asm-tree asm asm-3.3.2/archive/asm-analysis.pom0000644000175000017500000000066010474422514017001 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM Analysis asm-analysis jar asm-tree asm asm-3.3.2/archive/asm-parent.xml0000644000175000017500000000152310474422514016453 0ustar twernertwerner asm-3.3.2/archive/asm-all.xml0000644000175000017500000000526510744624621015744 0ustar twernertwerner It is highly recommended to use only the necessary ASM jars for your application instead of using the asm-all jar, unless you really need all ASM packages. asm-3.3.2/archive/asm-tree.pom0000644000175000017500000000064310474422514016116 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM Tree asm-tree jar asm asm asm-3.3.2/archive/asm-commons.xml0000644000175000017500000000263310474422514016640 0ustar twernertwerner asm-3.3.2/archive/asm.xml0000644000175000017500000000267110474422514015171 0ustar twernertwerner asm-3.3.2/archive/asm-analysis.xml0000644000175000017500000000267210474422514017013 0ustar twernertwerner asm-3.3.2/archive/asm-commons.pom0000644000175000017500000000065610474422514016636 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ ASM Commons asm-commons jar asm-tree asm asm-3.3.2/archive/asm-parent.pom0000644000175000017500000001037111225010263016434 0ustar twernertwerner 4.0.0 asm-parent asm @product.artifact@ pom ASM A very small and fast Java bytecode manipulation framework http://asm.objectweb.org/ ObjectWeb http://www.objectweb.org/ 2000 BSD http://asm.objectweb.org/license.html Eric Bruneton ebruneton ebruneton@free.fr Creator Java Developer Eugene Kuleshov eu eu@javatx.org Java Developer Remi Forax forax forax@univ-mlv.fr Java Developer scm:svn:svn://svn.forge.objectweb.org/svnroot/asm/trunk scm:svn:svn+ssh://${maven.username}@svn.forge.objectweb.org/svnroot/asm/trunk http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/asm/trunk/ http://forge.objectweb.org/tracker/?group_id=23 asm ${project.groupId} ${project.version} asm-tree ${project.groupId} ${project.version} asm-analysis ${project.groupId} ${project.version} asm-commons ${project.groupId} ${project.version} asm-util ${project.groupId} ${project.version} asm-xml ${project.groupId} ${project.version} ASM Users List sympa@ow2.org?subject=subscribe%20asm sympa@ow2.org?subject=unsubscribe%20asm asm@ow2.org http://www.ow2.org/wws/arc/asm ASM Team List sympa@ow2.org?subject=subscribe%20asm-team sympa@ow2.org?subject=unsubscribe%20asm-team asm-team@ow2.org http://www.ow2.org/wws/arc/asm-team http://mojo.codehaus.org/my-project objectweb false ObjectWeb Maven 2.0 Repository dav:https://maven.forge.objectweb.org:8002/maven2/ default objectweb.snapshots false ObjectWeb Maven 2.0 Snapshot Repository dav:https://maven.forge.objectweb.org:8002/maven2-snapshot/ default asm-3.3.2/archive/asm-tree.xml0000644000175000017500000000263510474422514016126 0ustar twernertwerner asm-3.3.2/archive/asm-debug-all.xml0000644000175000017500000000534511225010263017011 0ustar twernertwerner It is highly recommended to use only the necessary ASM jars for your application instead of using the asm-all jar, unless you really need all ASM packages. asm-3.3.2/archive/asm-util.xml0000644000175000017500000000262710474422514016145 0ustar twernertwerner asm-3.3.2/archive/asm-debug-all.pom0000644000175000017500000000047711101043521017001 0ustar twernertwerner 4.0.0 asm asm-parent @product.artifact@ ASM Debug All asm asm-debug-all jar asm-3.3.2/archive/asm-all.pom0000644000175000017500000000046310474422514015727 0ustar twernertwerner 4.0.0 asm asm-parent @product.artifact@ ASM All asm asm-all jar asm-3.3.2/.settings/0000755000175000017500000000000011633370220014150 5ustar twernertwernerasm-3.3.2/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000006266511224532001021142 0ustar twernertwerner#Mon Jul 06 22:30:13 EDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning org.eclipse.jdt.core.compiler.problem.forbiddenReference=error org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore org.eclipse.jdt.core.compiler.problem.nullReference=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled org.eclipse.jdt.core.compiler.problem.unusedImport=warning org.eclipse.jdt.core.compiler.problem.unusedLabel=warning org.eclipse.jdt.core.compiler.problem.unusedLocal=warning org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=ignore org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=80 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=80 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=80 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=80 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=48 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=52 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=52 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=80 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=80 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=80 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=32 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=0 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line_on_wrap org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false org.eclipse.jdt.core.formatter.comment.format_comments=true org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=false org.eclipse.jdt.core.formatter.comment.format_source_code=false org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_empty_lines=false org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true org.eclipse.jdt.core.formatter.indentation.size=4 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false org.eclipse.jdt.core.formatter.lineSplit=80 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false asm-3.3.2/.settings/org.eclipse.mylar.tasklist.prefs0000644000175000017500000000022310530515602022400 0ustar twernertwerner#Tue Nov 21 01:22:11 EST 2006 eclipse.preferences.version=1 project.repository.kind=web project.repository.url=http\://forge.objectweb.org/tracker asm-3.3.2/.settings/org.eclipse.jdt.ui.prefs0000644000175000017500000001606710551645406020642 0ustar twernertwerner#Tue Jan 02 00:10:12 EST 2007 comment_clear_blank_lines=false comment_format_comments=true comment_format_header=false comment_format_html=false comment_format_source_code=false comment_indent_parameter_description=false comment_indent_root_tags=true comment_line_length=80 comment_new_line_for_parameter=false comment_separate_root_tags=true eclipse.preferences.version=1 formatter_settings_version=10 org.eclipse.jdt.ui.text.custom_code_templates= asm-3.3.2/doc/0000755000175000017500000000000011633370220012777 5ustar twernertwernerasm-3.3.2/doc/README.txt0000644000175000017500000000007210007750443014477 0ustar twernertwernerThis directory contains the documentation of the product. asm-3.3.2/.fbprefs0000644000175000017500000002115011126521175013665 0ustar twernertwerner#FindBugs User Preferences #Tue Dec 30 20:00:35 CET 2008 detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true detectorBCPMethodReturnCheck=BCPMethodReturnCheck|false detectorBadAppletConstructor=BadAppletConstructor|false detectorBadResultSetAccess=BadResultSetAccess|false detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true detectorBadUseOfReturnValue=BadUseOfReturnValue|true detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true detectorBooleanReturnNull=BooleanReturnNull|true detectorBuildInterproceduralCallGraph=BuildInterproceduralCallGraph|false detectorBuildObligationPolicyDatabase=BuildObligationPolicyDatabase|true detectorCallToUnsupportedMethod=CallToUnsupportedMethod|true detectorCalledMethods=CalledMethods|true detectorCheckCalls=CheckCalls|false detectorCheckExpectedWarnings=CheckExpectedWarnings|false detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true detectorCheckTypeQualifiers=CheckTypeQualifiers|true detectorCloneIdiom=CloneIdiom|true detectorComparatorIdiom=ComparatorIdiom|false detectorConfusedInheritance=ConfusedInheritance|true detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true detectorCrossSiteScripting=CrossSiteScripting|true detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true detectorDontUseEnum=DontUseEnum|true detectorDroppedException=DroppedException|true detectorDumbMethodInvocations=DumbMethodInvocations|true detectorDumbMethods=DumbMethods|true detectorDuplicateBranches=DuplicateBranches|true detectorEmptyZipFileEntry=EmptyZipFileEntry|true detectorEqStringTest=EqStringTest|false detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true detectorFieldItemSummary=FieldItemSummary|true detectorFinalizerNullsFields=FinalizerNullsFields|true detectorFindBadCast=FindBadCast|false detectorFindBadCast2=FindBadCast2|true detectorFindBadEqualsImplementation=FindBadEqualsImplementation|false detectorFindBadForLoop=FindBadForLoop|true detectorFindBugsSummaryStats=FindBugsSummaryStats|true detectorFindCircularDependencies=FindCircularDependencies|false detectorFindDeadLocalStores=FindDeadLocalStores|true detectorFindDoubleCheck=FindDoubleCheck|true detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true detectorFindFinalizeInvocations=FindFinalizeInvocations|true detectorFindFloatEquality=FindFloatEquality|true detectorFindFloatMath=FindFloatMath|false detectorFindHEmismatch=FindHEmismatch|true detectorFindInconsistentSync2=FindInconsistentSync2|true detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true detectorFindMaskedFields=FindMaskedFields|true detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true detectorFindNakedNotify=FindNakedNotify|true detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|false detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true detectorFindNonShortCircuit=FindNonShortCircuit|true detectorFindNullDeref=FindNullDeref|true detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true detectorFindOpenStream=FindOpenStream|true detectorFindPuzzlers=FindPuzzlers|true detectorFindRefComparison=FindRefComparison|true detectorFindReturnRef=FindReturnRef|false detectorFindRunInvocations=FindRunInvocations|true detectorFindSelfComparison=FindSelfComparison|true detectorFindSelfComparison2=FindSelfComparison2|true detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true detectorFindSpinLoop=FindSpinLoop|true detectorFindSqlInjection=FindSqlInjection|false detectorFindTwoLockWait=FindTwoLockWait|true detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true detectorFindUnconditionalWait=FindUnconditionalWait|true detectorFindUninitializedGet=FindUninitializedGet|true detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true detectorFindUnreleasedLock=FindUnreleasedLock|true detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true detectorFindUnsyncGet=FindUnsyncGet|true detectorFindUselessControlFlow=FindUselessControlFlow|true detectorFormatStringChecker=FormatStringChecker|true detectorHugeSharedStringConstants=HugeSharedStringConstants|true detectorIDivResultCastToDouble=IDivResultCastToDouble|true detectorIncompatMask=IncompatMask|true detectorInconsistentAnnotations=InconsistentAnnotations|true detectorInefficientMemberAccess=InefficientMemberAccess|false detectorInefficientToArray=InefficientToArray|true detectorInfiniteLoop=InfiniteLoop|true detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|false detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true detectorInitializationChain=InitializationChain|true detectorInstantiateStaticClass=InstantiateStaticClass|true detectorInvalidJUnitTest=InvalidJUnitTest|true detectorIteratorIdioms=IteratorIdioms|true detectorLazyInit=LazyInit|true detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true detectorLockedFields=LockedFields|false detectorMethodReturnCheck=MethodReturnCheck|true detectorMethods=Methods|true detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true detectorMutableLock=MutableLock|true detectorMutableStaticFields=MutableStaticFields|false detectorNaming=Naming|true detectorNoteAnnotationRetention=NoteAnnotationRetention|true detectorNoteCheckReturnValue=NoteCheckReturnValue|true detectorNoteCheckReturnValueAnnotations=NoteCheckReturnValueAnnotations|true detectorNoteDirectlyRelevantTypeQualifiers=NoteDirectlyRelevantTypeQualifiers|true detectorNoteJCIPAnnotation=NoteJCIPAnnotation|true detectorNoteNonNullAnnotations=NoteNonNullAnnotations|true detectorNoteNonnullReturnValues=NoteNonnullReturnValues|true detectorNoteSuppressedWarnings=NoteSuppressedWarnings|true detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true detectorNumberConstructor=NumberConstructor|false detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true detectorPublicSemaphores=PublicSemaphores|true detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true detectorRedundantInterfaces=RedundantInterfaces|true detectorReflectiveClasses=ReflectiveClasses|true detectorRepeatedConditionals=RepeatedConditionals|true detectorResolveAllReferences=ResolveAllReferences|false detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true detectorSerializableIdiom=SerializableIdiom|false detectorStartInConstructor=StartInConstructor|true detectorStaticCalendarDetector=StaticCalendarDetector|true detectorStringConcatenation=StringConcatenation|true detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true detectorSwitchFallthrough=SwitchFallthrough|true detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true detectorTestASM=TestASM|false detectorTestDataflowAnalysis=TestDataflowAnalysis|false detectorTestingGround=TestingGround|false detectorTrainFieldStoreTypes=TrainFieldStoreTypes|true detectorTrainNonNullAnnotations=TrainNonNullAnnotations|true detectorTrainUnconditionalDerefParams=TrainUnconditionalDerefParams|true detectorURLProblems=URLProblems|true detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true detectorUnnecessaryMath=UnnecessaryMath|true detectorUnreadFields=UnreadFields|true detectorUseObjectEquals=UseObjectEquals|true detectorUselessSubclassMethod=UselessSubclassMethod|true detectorVarArgsProblems=VarArgsProblems|true detectorVolatileUsage=VolatileUsage|true detectorWaitInLoop=WaitInLoop|true detectorWrongMapIterator=WrongMapIterator|true detectorXMLFactoryBypass=XMLFactoryBypass|true detector_threshold=2 effort=max excludefilter0=findbugsExclude.xml filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false filter_settings_neg=| run_at_full_build=false asm-3.3.2/.classpath0000644000175000017500000000434411101041231014205 0ustar twernertwerner asm-3.3.2/LICENSE.txt0000644000175000017500000000307610177716604014077 0ustar twernertwerner ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. asm-3.3.2/findbugsExclude.xml0000644000175000017500000000107011126521175016071 0ustar twernertwerner asm-3.3.2/jdoc/0000755000175000017500000000000011633370220013151 5ustar twernertwernerasm-3.3.2/jdoc/README.txt0000644000175000017500000000230010007705133014641 0ustar twernertwernerThis directory contains ant files to build the javadocs of the product. The following rules describe the convention to write such files: - An ant file must build only one javadoc. - As there may exist several javadocs, all javadocs must be produced in a sub dir of ${out.dist.jdoc}. For example the user javadoc could be produced into the ${out.dist.jdoc}/user directory - The name of the ant file must be the name of the destination directory of the javadoc it builds. - Only the default task is called on an xml file. Sample ant file: ... asm-3.3.2/jdoc/package-list0000644000175000017500000000255410033740137015447 0ustar twernertwernerjava.applet java.awt java.awt.color java.awt.datatransfer java.awt.dnd java.awt.event java.awt.font java.awt.geom java.awt.im java.awt.im.spi java.awt.image java.awt.image.renderable java.awt.print java.beans java.beans.beancontext java.io java.lang java.lang.ref java.lang.reflect java.math java.net java.rmi java.rmi.activation java.rmi.dgc java.rmi.registry java.rmi.server java.security java.security.acl java.security.cert java.security.interfaces java.security.spec java.sql java.text java.util java.util.jar java.util.zip javax.accessibility javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi javax.rmi javax.rmi.CORBA javax.sound.midi javax.sound.midi.spi javax.sound.sampled javax.sound.sampled.spi javax.swing javax.swing.border javax.swing.colorchooser javax.swing.event javax.swing.filechooser javax.swing.plaf javax.swing.plaf.basic javax.swing.plaf.metal javax.swing.plaf.multi javax.swing.table javax.swing.text javax.swing.text.html javax.swing.text.html.parser javax.swing.text.rtf javax.swing.tree javax.swing.undo javax.transaction org.omg.CORBA org.omg.CORBA_2_3 org.omg.CORBA_2_3.portable org.omg.CORBA.DynAnyPackage org.omg.CORBA.ORBPackage org.omg.CORBA.portable org.omg.CORBA.TypeCodePackage org.omg.CosNaming org.omg.CosNaming.NamingContextPackage org.omg.SendingContext org.omg.stub.java.rmi org.xml.sax org.xml.sax.helpersasm-3.3.2/jdoc/user.xml0000644000175000017500000000251010767171762014670 0ustar twernertwerner asm-3.3.2/build.properties0000644000175000017500000001026611504060777015466 0ustar twernertwerner############################################################################### #ASM: a very small and fast Java bytecode manipulation framework #Copyright (c) 2000-2005 INRIA, France Telecom #All rights reserved. # #Redistribution and use in source and binary forms, with or without #modification, are permitted provided that the following conditions #are met: #1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. #2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. #3. Neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE #IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE #ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE #LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR #CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS #INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN #CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) #ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF #THE POSSIBILITY OF SUCH DAMAGE. ############################################################################### # Some information about the product product.name asm product.version 3.3.1 # product.snapshot yes plugin.version 3.3.0 ############################################################################### # BUILD ############################################################################### # Wich compiler do you want to use ? # jikes is faster than javac but keeps line numbers in compiled classes, even # with the -O option (javac removes line numbers and local variable names with # this option, resulting in smaller classes) build.compiler modern # Build class path (classes needed to build the project) # Class path for the ObjectWeb utility Ant tasks (version 1.3.2 or higher) # See http://forge.objectweb.org/projects/monolog # objectweb.ant.tasks.path ow_util_ant_tasks.jar ############################################################################### # TESTS (PERFORMANCE COMPARISONS WITH BCEL AND SERP) ############################################################################### # Class path for the BCEL library (version 5.2) # See http://jakarta.apache.org/bcel # bcel.path bcel.jar # Class path for the AspectJ library that contains the modified BCEL version # (version 1.5) See http://www.eclipse.org/aspectj # aspectj.path aspectjweaver.jar # Class path for the SERP library (version 1.14.2) # See http://serp.sourceforge.net # serp.path serp.jar # Class path for the Javassist library (version 3.6.GA) # See http://www.csg.is.titech.ac.jp/~chiba/javassist # javassist.path javassist.jar # Class path for the Janino compiler (version 2.5.11) # See http://www.janino.net/ # janino.path janino.jar # Class paths for Cobertura (version 1.9) # corbertura.path cobertura.jar # cobertura.runtime.path cobertura.jar # Class paths for Kawa (version 1.9.1) # kawa.runtime.path kawa.jar # Class paths for CSG Bytecode # csg-bytecode.runtime.path csg-bytecode.jar # Class paths for Cojen (version 2.0) # cojen.runtime.path cojen.jar # Class paths for JBET (version 3-R1) # jbet.runtime.path jbet.jar # Class paths for JClassLib # jclasslib.runtime.path jclasslib.jar # Class paths for Jiapi # jiapi.runtime.path jiapi.jar # Class paths for mozilla.classfile (version 1_7R1) # rhino.runtime.path rhino.jar ############################################################################### # DOCUMENTATION ############################################################################### # URLs of external Javadocs (JDK) jdk.url http://java.sun.com/j2se/1.4.2/docs/api asm-3.3.2/.project0000644000175000017500000000111411063536156013707 0ustar twernertwerner asm3 org.eclipse.jdt.core.javabuilder edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder org.eclipse.jdt.core.javanature edu.umd.cs.findbugs.plugin.eclipse.findbugsNature asm-3.3.2/test/0000755000175000017500000000000011633370220013211 5ustar twernertwernerasm-3.3.2/test/lib/0000755000175000017500000000000011633370217013765 5ustar twernertwernerasm-3.3.2/test/README.txt0000644000175000017500000000115310007705133014706 0ustar twernertwernerThis directory contains the tests of the product. It contains(*) the following items: - lib: external libraries required to run the tests - conform: conformance tests (unit tests) - deviance: deviance tests (unit tests) - thread: multi-threading tests (unit tests) - stress: stress tests - perf: performance tests Each sub directory contains: - the source of the tests, with package struture if there is one, - the xml descriptors to launch test suites. An xml desriptor describes the execution of a test suite. The default task is called on this file. (*) some items may not be present, depending on the product.asm-3.3.2/test/perf/0000755000175000017500000000000011633370220014145 5ustar twernertwernerasm-3.3.2/test/perf/all.xml0000644000175000017500000000145310714642760015454 0ustar twernertwerner asm-3.3.2/test/perf/gen.xml0000644000175000017500000000145311053005772015446 0ustar twernertwerner asm-3.3.2/test/perf/org/0000755000175000017500000000000011633370220014734 5ustar twernertwernerasm-3.3.2/test/perf/org/objectweb/0000755000175000017500000000000011633370217016706 5ustar twernertwernerasm-3.3.2/test/perf/org/objectweb/asm/0000755000175000017500000000000011633370220017460 5ustar twernertwernerasm-3.3.2/test/perf/org/objectweb/asm/ALLPerfTest.java0000644000175000017500000005623310715334473022433 0ustar twernertwerner/*** * ASM performance test: measures the performances of asm package * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.verifier.structurals.ModifiedPass3bVerifier; import org.objectweb.asm.commons.EmptyVisitor; import org.objectweb.asm.commons.LocalVariablesSorter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Analyzer; import org.objectweb.asm.tree.analysis.SimpleVerifier; import serp.bytecode.BCClass; import serp.bytecode.BCMethod; import serp.bytecode.Code; import serp.bytecode.Project; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * @author Eric Bruneton * @author Peter Lawrey */ public abstract class ALLPerfTest { static boolean compute; static boolean computeFrames; static boolean skipDebug; static ClassPool pool; static Project p; static BCClass c; static int repeats; static List classes = new ArrayList(); static List classNames = new ArrayList(); private static final Runnable NOTHING = new Runnable() { public void run() { } }; private static final int MAX_ITERATION_SEC = Integer.getInteger("max.iteration.sec", 10) .intValue(); public static void main(final String[] args) throws IOException, InterruptedException { String clazz = System.getProperty("asm.test.class"); List jars = findFiles(System.getProperty("java.home"), ".jar"); jars.addAll(findJars(File.pathSeparatorChar, System.getProperty("java.class.path"))); repeats = Integer.getInteger("repeats", 3).intValue() + 1; Set classesFound = new HashSet(); for (int i = 0; i < jars.size(); i++) { ZipFile zip; try { zip = new ZipFile((String) jars.get(i)); } catch (IOException e) { System.err.println("Error openning " + jars.get(i)); e.printStackTrace(); continue; } Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry e = (ZipEntry) entries.nextElement(); String s = e.getName(); if (s.endsWith(".class")) { s = s.substring(0, s.length() - 6).replace('/', '.'); if (!classesFound.add(s)) { continue; } if (clazz == null || s.indexOf(clazz) != -1) { InputStream is = zip.getInputStream(e); byte[] bytes = new ClassReader(is).b; classes.add(bytes); classNames.add(s); is.close(); if (classes.size() % 2500 == 0) { System.out.println("... searching, found " + classes.size() + " classes."); } } } } zip.close(); } System.out.println("Found " + classes.size() + " classes."); RunTest nullBCELAdapt = new RunTest() { public void test(byte[] bytes, int[] errors) throws IOException { nullBCELAdapt(bytes); } }; RunTest nullAspectjBCELAdapt = new RunTest() { public void test(byte[] bytes, int[] errors) throws IOException { nullAspectjBCELAdapt(bytes); } }; Runnable createClassPool = new Runnable() { public void run() { pool = new ClassPool(null); } }; RunTest nullJavassistAdapt = new RunTest() { public void test(byte[] bytes, int[] errors) throws Exception { nullJavassistAdapt(bytes); } }; Runnable createProject = new Runnable() { public void run() { p = new Project(); c = null; } }; RunTest nullSERPAdapt = new RunTest() { public void test(byte[] bytes, int[] errors) throws Exception { nullSERPAdapt(bytes); } }; // get class info and deserialize tests runTestAll("get class info", "", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassReader cr = new ClassReader(bytes); cr.getAccess(); cr.getClassName(); cr.getSuperName(); cr.getInterfaces(); } }); runTestAll("deserialize", "", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { new ClassReader(bytes).accept(new EmptyVisitor(), 0); } }); runTest("deserialize", "tree package", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { new ClassReader(bytes).accept(new ClassNode(), 0); } }); System.out.println(); // deserialize and reserialize tests runTestAll("deserialize and reserialize", "", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassReader cr = new ClassReader(bytes); ClassWriter cw = new ClassWriter(0); cr.accept(cw, 0); cw.toByteArray(); } }); runTestAll("deserialize and reserialize", "copyPool", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassReader cr = new ClassReader(bytes); ClassWriter cw = new ClassWriter(cr, 0); cr.accept(cw, 0); cw.toByteArray(); } }); runTest("deserialize and reserialize", "tree package", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassWriter cw = new ClassWriter(0); ClassNode cn = new ClassNode(); new ClassReader(bytes).accept(cn, 0); cn.accept(cw); cw.toByteArray(); } }); compute = false; computeFrames = false; pool = null; runTest("deserialize and reserialize", "BCEL", NOTHING, nullBCELAdapt); runTest("deserialize and reserialize", "Aspectj BCEL", NOTHING, nullAspectjBCELAdapt); runTest("deserialize and reserialize", "Javassist", createClassPool, nullJavassistAdapt); runTest("deserialize and reserialize", "SERP", createProject, nullSERPAdapt); System.out.println(); // deserialize and reserialize tests with computeMaxs runTest("deserialize and reserialize", "computeMaxs", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); new ClassReader(bytes).accept(cw, 0); cw.toByteArray(); } }); compute = true; computeFrames = false; runTest("deserialize and reserialize", "BCEL and computeMaxs", NOTHING, nullBCELAdapt); runTest("deserialize and reserialize", "Aspectj BCEL and computeMaxs", NOTHING, nullAspectjBCELAdapt); // misc. tests runTest("deserialize and reserialize", "LocalVariablesSorter", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassWriter cw = new ClassWriter(0); new ClassReader(bytes).accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new LocalVariablesSorter(access, desc, cv.visitMethod(access, name, desc, signature, exceptions)); } }, ClassReader.EXPAND_FRAMES); cw.toByteArray(); } }); // This test repeatedly tests the same classes as SimpleVerifier // actually calls Class.forName() on the class which fills the PermGen runTestSome("analyze", "SimpleVerifier", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassReader cr = new ClassReader(bytes); ClassNode cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_DEBUG); List methods = cn.methods; for (int k = 0; k < methods.size(); ++k) { MethodNode method = (MethodNode) methods.get(k); Analyzer a = new Analyzer(new SimpleVerifier()); try { a.analyze(cn.name, method); } catch (Throwable th) { // System.err.println(th); ++errors[0]; } } } }); System.out.println(); // deserialize and reserialize tests with computeFrames runTest("deserialize and reserialize", "computeFrames", NOTHING, new RunTest() { public void test(byte[] bytes, int[] errors) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); new ClassReader(bytes).accept(cw, 0); cw.toByteArray(); } }); // the BCEL+computeFrames tests must be done only at the end, because // after them other tests run very slowly, for some unknown reason // (memory usage?) compute = false; computeFrames = true; runTest("deserialize and reserialize", "BCEL and computeFrames", NOTHING, nullBCELAdapt); runTest("deserialize and reserialize", "Aspectj BCEL and computeFrames", NOTHING, nullAspectjBCELAdapt); } public static List findFiles(String directory, String suffix) { List matches = new ArrayList(); findFiles(matches, new File(directory), suffix); return matches; } static void findFiles(List matches, File directory, String suffix) { File[] files = directory.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isDirectory()) { findFiles(matches, file, suffix); } else if (file.getName().endsWith(suffix)) { matches.add(file.getAbsolutePath()); } } } interface RunTest { public void test(byte[] bytes, int[] errors) throws Exception; } static void runTestAll( String testName, String with, Runnable init, RunTest runTest) throws InterruptedException { runTest0(1, true, testName, with, init, runTest); } static void runTest( String testName, String with, Runnable init, RunTest runTest) throws InterruptedException { runTest0(repeats - 1, false, testName, with, init, runTest); } static void runTestSome( String testName, String with, Runnable init, RunTest runTest) throws InterruptedException { runTest0(repeats - 1, true, testName, with, init, runTest); } private static void runTest0( int testSkip, boolean startAtZero, String testName, String with, Runnable init, RunTest runTest) throws InterruptedException { if (with.length() > 0) { with = " with " + with; } boolean skipBigClasses = with.contains("BCEL and computeFrames"); int totalCount = 0; long totalSize = 0; long totalTime = 0; System.out.println("\nStarting " + testName + with + " test."); for (int i = 0; i < repeats; ++i) { init.run(); long t = System.currentTimeMillis(); int count = 0; long size = 0; int[] errors = { 0 }; long longest = 0; int longestSize = 0; int skipped = 0; for (int j = startAtZero ? 0 : i; j < classes.size(); j += testSkip) { count++; byte[] b = (byte[]) classes.get(j); if (skipBigClasses && b.length > 16 * 1024) { skipped++; continue; } size += b.length; try { long start = System.currentTimeMillis(); runTest.test(b, errors); long end = System.currentTimeMillis(); long time = end - start; if (longest < time) { longest = time; longestSize = b.length; } if (time > MAX_ITERATION_SEC * 1000 / 10) { System.out.println("--- time to " + testName + " the class " + classNames.get(j) + with + " took " + time + " ms. bytes=" + b.length); } if (end - t > MAX_ITERATION_SEC * 1000) { // System.out.println("Stopping iteration due to a // longer run time."); break; } } catch (Exception ignored) { errors[0]++; } catch (Throwable e) { System.err.println(classNames.get(j) + ": " + e); errors[0]++; } } t = System.currentTimeMillis() - t; String errorStr = errors[0] > 0 ? " (" + errors[0] + " errors)" : ""; String skippedStr = skipped == 0 ? "" : " (" + skipped + " skipped as BCEL/computeFrames on >16K classes is very slow)"; String longestStr = ""; if (longest > 50) { longestStr = " the longest took " + longest + " ms (" + longestSize + " bytes)"; } if (i > 0) { System.out.println("- to " + testName + ' ' + count + " classes" + with + " = " + t + " ms" + errorStr + longestStr + skippedStr + '.'); totalCount += count; totalSize += size; totalTime += t; } } System.out.println("Time to " + testName + ' ' + totalCount + " classes" + with + " = " + totalTime + " ms.\n" + "Processing rate = " + totalCount * 1000 / totalTime + " classes per sec (" + totalSize * 1000 / totalTime / 1024 + " kB per sec)."); System.gc(); Thread.sleep(2500); } private static List findJars(char pathSeparatorChar, String s) { List ret = new ArrayList(); int start = 0; int pos = s.indexOf(pathSeparatorChar); while (pos >= 0) { String name = s.substring(start, pos); if (name.endsWith(".jar")) { ret.add(name); } start = pos + 1; pos = s.indexOf(pathSeparatorChar, start); } return ret; } static void nullBCELAdapt(final byte[] b) throws IOException { JavaClass jc = new ClassParser(new ByteArrayInputStream(b), "class-name").parse(); ClassGen cg = new ClassGen(jc); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int k = 0; k < ms.length; ++k) { MethodGen mg = new MethodGen(ms[k], cg.getClassName(), cp); boolean lv = ms[k].getLocalVariableTable() == null; boolean ln = ms[k].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } if (computeFrames) { ModifiedPass3bVerifier verif; verif = new ModifiedPass3bVerifier(jc, k); verif.do_verify(); } } cg.replaceMethod(ms[k], mg.getMethod()); } cg.getJavaClass().getBytes(); } static void nullAspectjBCELAdapt(final byte[] b) throws IOException { org.aspectj.apache.bcel.classfile.JavaClass jc = new org.aspectj.apache.bcel.classfile.ClassParser(new ByteArrayInputStream(b), "class-name").parse(); org.aspectj.apache.bcel.generic.ClassGen cg = new org.aspectj.apache.bcel.generic.ClassGen(jc); org.aspectj.apache.bcel.generic.ConstantPoolGen cp = cg.getConstantPool(); org.aspectj.apache.bcel.classfile.Method[] ms = cg.getMethods(); for (int k = 0; k < ms.length; ++k) { org.aspectj.apache.bcel.generic.MethodGen mg = new org.aspectj.apache.bcel.generic.MethodGen(ms[k], cg.getClassName(), cp); boolean lv = ms[k].getLocalVariableTable() == null; boolean ln = ms[k].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); org.aspectj.apache.bcel.generic.InstructionList il = mg.getInstructionList(); if (il != null) { org.aspectj.apache.bcel.generic.InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } if (computeFrames) { org.aspectj.apache.bcel.verifier.structurals.ModifiedPass3bVerifier verif = new org.aspectj.apache.bcel.verifier.structurals.ModifiedPass3bVerifier(jc, k); verif.do_verify(); } } cg.replaceMethod(ms[k], mg.getMethod()); } cg.getJavaClass().getBytes(); } static void nullJavassistAdapt(final byte[] b) throws Exception { CtClass cc = pool.makeClass(new ByteArrayInputStream(b)); CtMethod[] ms = cc.getDeclaredMethods(); for (int j = 0; j < ms.length; ++j) { if (skipDebug) { // is there a mean to remove the debug attributes? } if (compute) { // how to force recomputation of maxStack and maxLocals? } } cc.toBytecode(); } static void nullSERPAdapt(final byte[] b) throws Exception { if (c != null) { p.removeClass(c); } c = p.loadClass(new ByteArrayInputStream(b)); c.getDeclaredFields(); BCMethod[] methods = c.getDeclaredMethods(); for (int i = 0; i < methods.length; ++i) { Code code = methods[i].getCode(false); if (code != null) { while (code.hasNext()) { code.next(); } if (compute) { code.calculateMaxStack(); code.calculateMaxLocals(); } } } c.toByteArray(); } } asm-3.3.2/test/perf/org/objectweb/asm/xml/0000755000175000017500000000000011633370220020260 5ustar twernertwernerasm-3.3.2/test/perf/org/objectweb/asm/xml/XMLPerfTest.java0000644000175000017500000001577211224532001023245 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; /** * Performance test suite for ASM XML * * @author Eugene Kuleshov */ public class XMLPerfTest { private static final String[] ENGINES = { "jd.xml.xslt.trax.TransformerFactoryImpl", "net.sf.saxon.TransformerFactoryImpl", "org.apache.xalan.processor.TransformerFactoryImpl", }; private static final String[] TEMPLATES = { "copy.xsl", "linenumbers.xsl", "profile.xsl", }; public static void main(final String[] args) throws Exception { System.err.println("Comparing XSLT performance for ASM XSLT"); System.err.println("This may take 20 to 30 minutes\n"); File examplesDir = new File(args[0]); if (!examplesDir.isDirectory()) { System.err.println(args[0] + " must be directory"); return; } // File[] templates = examplesDir.listFiles(new FilenameFilter() { // public boolean accept(File dir, String name) { // return name.endsWith(".xsl"); // } // }); for (int i = 0; i < ENGINES.length; i++) { System.err.println(ENGINES[i]); process(null, ENGINES[i]); for (int j = 0; j < TEMPLATES.length; j++) { process(new File(examplesDir, TEMPLATES[j]).getAbsolutePath(), ENGINES[i]); } System.err.println(); } } private static void process(final String name, final String engine) throws Exception { System.setProperty("javax.xml.transform.TransformerFactory", engine); processRep(name, Processor.BYTECODE); processRep(name, Processor.MULTI_XML); processRep(name, Processor.SINGLE_XML); } // private static void processEntry( // String className, // TransformerHandler handler) throws Exception // { // byte[] classData = getCode(new URL(className).openStream()); // ByteArrayOutputStream bos = new ByteArrayOutputStream(); // // handler.setResult(new SAXResult(new ASMContentHandler(bos, false))); // // ClassReader cr = new ClassReader(classData); // cr.accept(new SAXClassAdapter(handler, cr.getVersion(), false), false); // } // // private static byte[] getCode(InputStream is) throws IOException { // ByteArrayOutputStream bos = new ByteArrayOutputStream(); // byte[] buff = new byte[1024]; // int n = -1; // while ((n = is.read(buff)) > -1) // bos.write(buff, 0, n); // return bos.toByteArray(); // } private static void processRep(final String name, final int outRep) { long l1 = System.currentTimeMillis(); int n = 0; try { Class c = XMLPerfTest.class; String u = c.getResource("/java/lang/String.class").toString(); final InputStream is = new BufferedInputStream(new URL(u.substring(4, u.indexOf('!'))).openStream()); final OutputStream os = new IgnoringOutputStream(); final StreamSource xslt = name == null ? null : new StreamSource(new FileInputStream(name)); Processor p = new DotObserver(Processor.BYTECODE, outRep, is, os, xslt); n = p.process(); } catch (Exception ex) { System.err.println(); // ex.printStackTrace(); System.err.println(ex); } long l2 = System.currentTimeMillis(); System.err.println(); System.err.println(" " + outRep + " " + name + " " + (l2 - l1) + "ms " + 1000f * n / (l2 - l1)); // SAXTransformerFactory saxtf = (SAXTransformerFactory) // TransformerFactory.newInstance(); // Templates templates = saxtf.newTemplates(xslt); // // ZipEntry ze = null; // int max = 10000; // while ((ze = zis.getNextEntry()) != null && max > 0) { // if (ze.getName().endsWith(".class")) { // processEntry(u.substring(0, n + 2).concat(ze.getName()), // saxtf.newTransformerHandler(templates)); // max--; // } // } } private static final class DotObserver extends Processor { private int n = 0; public DotObserver( final int inRepresenation, final int outRepresentation, final InputStream input, final OutputStream output, final Source xslt) { super(inRepresenation, outRepresentation, input, output, xslt); } public void update(final Object arg) { n++; if (n % 1000 == 0) { System.err.print("" + n / 1000); } else if (n % 100 == 0) { System.err.print("."); } } } static final class IgnoringOutputStream extends OutputStream { public final void write(final int b) throws IOException { } public final void write(final byte[] b) throws IOException { } public final void write(final byte[] b, final int off, final int len) throws IOException { } } } asm-3.3.2/test/perf/org/objectweb/asm/GenPerfTest.java0000644000175000017500000006156311053005772022527 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2005 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import gnu.bytecode.Access; import gnu.bytecode.ClassType; import gnu.bytecode.CodeAttr; import gnu.bytecode.Field; import gnu.bytecode.Method; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.Arrays; import jbet.Descriptor; import jbet.Instruction; import jbet.Snippit; import org.apache.bcel.Constants; import org.apache.bcel.generic.ArrayType; import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.generic.PUSH; import org.cojen.classfile.MethodInfo; import org.cojen.classfile.Modifiers; import org.cojen.classfile.TypeDesc; import org.gjt.jclasslib.bytecode.ImmediateByteInstruction; import org.gjt.jclasslib.bytecode.ImmediateShortInstruction; import org.gjt.jclasslib.bytecode.SimpleInstruction; import org.gjt.jclasslib.io.ByteCodeWriter; import org.gjt.jclasslib.structures.AccessFlags; import org.gjt.jclasslib.structures.AttributeInfo; import org.gjt.jclasslib.structures.CPInfo; import org.gjt.jclasslib.structures.ConstantPoolUtil; import org.gjt.jclasslib.structures.InvalidByteCodeException; import org.gjt.jclasslib.structures.attributes.CodeAttribute; import org.gjt.jclasslib.structures.attributes.SourceFileAttribute; import org.gjt.jclasslib.structures.constants.ConstantStringInfo; import org.mozilla.classfile.ByteCode; import org.mozilla.classfile.ClassFileWriter; import alt.jiapi.reflect.InstructionFactory; import alt.jiapi.reflect.InstructionList; import alt.jiapi.reflect.JiapiClass; import alt.jiapi.reflect.JiapiMethod; import alt.jiapi.reflect.MethodExistsException; import alt.jiapi.reflect.Signature; import com.claritysys.jvm.builder.CodeBuilder; import com.claritysys.jvm.classfile.CfMethod; import com.claritysys.jvm.classfile.ClassFile; import com.claritysys.jvm.classfile.ConstantPool; import com.claritysys.jvm.classfile.JVM; /** * Performance tests for frameworks that can only do bytecode generation. * * @author Eric Bruneton */ public class GenPerfTest { final static int N = 100000; public static void main(String[] args) throws Exception { for (int i = 0; i < 5; ++i) { asmTest(); } for (int i = 0; i < 5; ++i) { gnuByteCodeTest(); } for (int i = 0; i < 5; ++i) { csgBytecodeTest(); } for (int i = 0; i < 5; ++i) { cojenTest(); } for (int i = 0; i < 5; ++i) { jbetTest(); } for (int i = 0; i < 5; ++i) { jClassLibTest(); } for (int i = 0; i < 5; ++i) { jiapiTest(); } for (int i = 0; i < 5; ++i) { mozillaClassFileTest(); } for (int i = 0; i < 5; ++i) { bcelTest(); } for (int i = 0; i < 5; ++i) { aspectjBcelTest(); } } static void asmTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { asmHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("ASM generation time: " + ((float) t) / N + " ms/class"); } static void gnuByteCodeTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { gnuByteCodeHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("gnu.bytecode generation time: " + ((float) t) / N + " ms/class"); } static void csgBytecodeTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { csgBytecodeHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("CSG bytecode generation time: " + ((float) t) / N + " ms/class"); } static void cojenTest() throws IOException { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { cojenHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("Cojen generation time: " + ((float) t) / N + " ms/class"); } static void jbetTest() throws IOException { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { jbetHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("JBET generation time: " + ((float) t) / N + " ms/class"); } static void jClassLibTest() throws IOException, InvalidByteCodeException { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { jClassLibHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("JClassLib generation time: " + ((float) t) / N + " ms/class"); } static void jiapiTest() throws MethodExistsException { int N = 1000; long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { jiapiHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("Jiapi generation time: " + ((float) t) / N + " ms/class"); } static void mozillaClassFileTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { mozillaClassFileHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("Mozilla Class File generation time: " + ((float) t) / N + " ms/class"); } static void bcelTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { bcelHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("BCEL generation time: " + ((float) t) / N + " ms/class"); } static void aspectjBcelTest() { long t = System.currentTimeMillis(); for (int i = 0; i < N; ++i) { aspectjBcelHelloWorld(); } t = System.currentTimeMillis() - t; System.out.println("AspectJ BCEL generation time: " + ((float) t) / N + " ms/class"); } static byte[] asmHelloWorld() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "HelloWorld", null, "java/lang/Object", null); cw.visitSource("HelloWorld.java", null); MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); mw.visitVarInsn(Opcodes.ALOAD, 0); mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V"); mw.visitInsn(Opcodes.RETURN); mw.visitMaxs(0, 0); mw.visitEnd(); mw = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mw.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mw.visitLdcInsn("Hello world!"); mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mw.visitInsn(Opcodes.RETURN); mw.visitMaxs(0, 0); mw.visitEnd(); return cw.toByteArray(); } static Method objectCtor = gnu.bytecode.Type.pointer_type.getDeclaredMethod("", 0); static Field outField = ClassType.make("java.lang.System").getField("out"); static Method printlnMethod = ClassType.make("java.io.PrintStream") .getDeclaredMethod("println", new gnu.bytecode.Type[] { gnu.bytecode.Type.string_type }); static byte[] gnuByteCodeHelloWorld() { ClassType c = new ClassType("HelloWorld"); c.setSuper("java.lang.Object"); c.setModifiers(Access.PUBLIC); c.setSourceFile("HelloWorld.java"); Method m = c.addMethod("", "()V", Access.PUBLIC); CodeAttr code = m.startCode(); code.pushScope(); code.emitPushThis(); code.emitInvokeSpecial(objectCtor); code.emitReturn(); code.popScope(); m = c.addMethod("main", "([Ljava/lang/String;)V", Access.PUBLIC | Access.STATIC); code = m.startCode(); code.pushScope(); code.emitGetStatic(outField); code.emitPushString("Hello world!"); code.emitInvokeVirtual(printlnMethod); code.emitReturn(); code.popScope(); return c.writeToArray(); } static byte[] csgBytecodeHelloWorld() { ClassFile cf = new ClassFile("HelloWorld", "java/lang/Object", "HelloWorld.java"); ConstantPool cp = cf.getConstantPool(); CfMethod method = cf.addMethod(JVM.ACC_PUBLIC, "", "()V"); CodeBuilder code = new CodeBuilder(method); code.add(JVM.ALOAD_0); code.add(JVM.INVOKESPECIAL, cp.addMethodRef(false, "java/lang/Object", "", "()V")); code.add(JVM.RETURN); code.flush(); method = cf.addMethod(JVM.ACC_PUBLIC + JVM.ACC_STATIC, "main", "([Ljava/lang/String;)V"); code = new CodeBuilder(method); code.add(JVM.GETSTATIC, cp.addFieldRef("java/lang/System", "out", "Ljava/io/PrintStream;")); code.add(JVM.LDC, "Hello world!"); code.add(JVM.INVOKEVIRTUAL, cp.addMethodRef(false, "java/io/PrintStream", "println", "(Ljava/lang/String;)V")); code.add(JVM.RETURN); code.flush(); return cf.writeToArray(); } static TypeDesc printStream = TypeDesc.forClass("java.io.PrintStream"); static byte[] cojenHelloWorld() throws IOException { org.cojen.classfile.ClassFile cf = new org.cojen.classfile.ClassFile("HelloWorld"); cf.setSourceFile("HelloWorld.java"); cf.addDefaultConstructor(); TypeDesc[] params = new TypeDesc[] { TypeDesc.STRING.toArrayType() }; MethodInfo mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "main", null, params); org.cojen.classfile.CodeBuilder b = new org.cojen.classfile.CodeBuilder(mi); b.loadStaticField("java.lang.System", "out", printStream); b.loadConstant("Hello world!"); b.invokeVirtual(printStream, "println", null, new TypeDesc[] { TypeDesc.STRING }); b.returnVoid(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); cf.writeTo(bos); return bos.toByteArray(); } static Descriptor emptyDesc = new Descriptor("()V"); static Descriptor mainDesc = new Descriptor("([Ljava/lang/String;)V"); static Descriptor printlnDesc = new Descriptor("(Ljava/lang/String;)V"); static jbet.Type printStreamType = new jbet.Type("Ljava/io/PrintStream;"); static byte[] jbetHelloWorld() throws IOException { jbet.ClassInfo ci = new jbet.ClassInfo(null, "HelloWorld"); ci.sourceFile = "HelloWorld.java"; jbet.MethodInfo mi = new jbet.MethodInfo("", emptyDesc, jbet.MethodInfo.ACC_PUBLIC); mi.code = new Snippit(); mi.code.push(new Instruction().setAload(0)); mi.code.push(new Instruction().setInvokeSpecial("java/lang/Object", "", emptyDesc)); mi.code.push(new Instruction().setReturn()); mi.maxLocals = 1; mi.maxStack = 1; ci.addMethod(mi); mi = new jbet.MethodInfo("main", mainDesc, jbet.MethodInfo.ACC_PUBLIC | jbet.MethodInfo.ACC_STATIC); mi.code = new Snippit(); mi.code.push(new Instruction().setGetstatic("java/lang/System", "out", printStreamType)); mi.code.push(new Instruction().setSpush("Hello world!")); mi.code.push(new Instruction().setInvokeVirtual("java/io/PrintStream", "println", printlnDesc)); mi.maxLocals = 1; mi.maxStack = 2; ci.addMethod(mi); ci.resolveConstants(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ci.writeFile(bos); return bos.toByteArray(); } static byte[] jClassLibHelloWorld() throws InvalidByteCodeException, IOException { org.gjt.jclasslib.structures.ClassFile cf = new org.gjt.jclasslib.structures.ClassFile(); cf.setConstantPool(new CPInfo[0]); ConstantPoolUtil.addConstantUTF8Info(cf, "", 0); // dummy constant cf.setMajorVersion(45); cf.setMinorVersion(3); cf.setAccessFlags(AccessFlags.ACC_PUBLIC); cf.setThisClass(ConstantPoolUtil.addConstantClassInfo(cf, "HelloWorld", 0)); cf.setSuperClass(ConstantPoolUtil.addConstantClassInfo(cf, "java/lang/Object", 0)); SourceFileAttribute sa = new SourceFileAttribute(); sa.setAttributeNameIndex(ConstantPoolUtil.addConstantUTF8Info(cf, SourceFileAttribute.ATTRIBUTE_NAME, 0)); sa.setSourcefileIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "HelloWorld.java", 0)); org.gjt.jclasslib.structures.MethodInfo mi1 = new org.gjt.jclasslib.structures.MethodInfo(); mi1.setAccessFlags(AccessFlags.ACC_PUBLIC); mi1.setNameIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "", 0)); mi1.setDescriptorIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "()V", 0)); CodeAttribute ca1 = new CodeAttribute(); ca1.setAttributeNameIndex(ConstantPoolUtil.addConstantUTF8Info(cf, CodeAttribute.ATTRIBUTE_NAME, 0)); ca1.setCode(ByteCodeWriter.writeByteCode(Arrays.asList(new org.gjt.jclasslib.bytecode.AbstractInstruction[] { new SimpleInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_ALOAD_0), new ImmediateShortInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_INVOKESPECIAL, ConstantPoolUtil.addConstantMethodrefInfo(cf, "java/lang/Object", "", "()V", 0)), new SimpleInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_RETURN) }))); ca1.setMaxStack(1); ca1.setMaxLocals(1); mi1.setAttributes(new AttributeInfo[] { ca1 }); ConstantStringInfo s = new ConstantStringInfo(); s.setStringIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "Hello world!", 0)); org.gjt.jclasslib.structures.MethodInfo mi2 = new org.gjt.jclasslib.structures.MethodInfo(); mi2.setAccessFlags(AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC); mi2.setNameIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "main", 0)); mi2.setDescriptorIndex(ConstantPoolUtil.addConstantUTF8Info(cf, "([Ljava/lang/String;)V", 0)); CodeAttribute ca2 = new CodeAttribute(); ca2.setAttributeNameIndex(ConstantPoolUtil.addConstantUTF8Info(cf, CodeAttribute.ATTRIBUTE_NAME, 0)); ca2.setCode(ByteCodeWriter.writeByteCode(Arrays.asList(new org.gjt.jclasslib.bytecode.AbstractInstruction[] { new ImmediateShortInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_GETSTATIC, ConstantPoolUtil.addConstantFieldrefInfo(cf, "java/lang/System", "out", "Ljava/io/PrintStream;", 0)), new ImmediateByteInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_LDC, false, ConstantPoolUtil.addConstantPoolEntry(cf, s, 0)), new ImmediateShortInstruction(org.gjt.jclasslib.bytecode.Opcodes.OPCODE_INVOKEVIRTUAL, ConstantPoolUtil.addConstantMethodrefInfo(cf, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", 0)) }))); ca2.setMaxStack(2); ca2.setMaxLocals(1); mi2.setAttributes(new AttributeInfo[] { ca2 }); cf.setMethods(new org.gjt.jclasslib.structures.MethodInfo[] { mi1, mi2 }); cf.setAttributes(new AttributeInfo[] { sa }); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); cf.write(dos); dos.close(); return bos.toByteArray(); } static Signature emptySig = new Signature("()V"); static Signature mainSig = new Signature("([Ljava/lang/String;)V"); static Signature printlnSig = new Signature("(Ljava/lang/String;)V"); static byte[] jiapiHelloWorld() throws MethodExistsException { JiapiClass c = JiapiClass.createClass("HelloWorld"); // No API to set SourceFile! JiapiMethod method = c.addMethod(Modifier.PUBLIC, "", emptySig); InstructionList il = method.getInstructionList(); InstructionFactory iFactory = il.getInstructionFactory(); il.add(iFactory.aload(0)); il.add(iFactory.invoke(0, "java/lang/Object", "", emptySig)); il.add(iFactory.returnMethod(method)); method = c.addMethod(Modifier.PUBLIC | Modifier.STATIC, "main", mainSig); il = method.getInstructionList(); iFactory = il.getInstructionFactory(); il.add(iFactory.getField(Modifier.STATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); il.add(iFactory.pushConstant("Hello world!")); il.add(iFactory.invoke(0, "java/io/PrintStream", "println", printlnSig)); il.add(iFactory.returnMethod(method)); return c.getByteCode(); } static byte[] mozillaClassFileHelloWorld() { ClassFileWriter c = new ClassFileWriter("HelloWorld", "java/lang/Object", "HelloWorld.java"); c.startMethod("", "()V", ClassFileWriter.ACC_PUBLIC); c.addLoadThis(); c.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Object", "", "()V"); c.add(ByteCode.RETURN); c.stopMethod((short) 1); c.startMethod("main", "()V", (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_STATIC)); c.add(ByteCode.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); c.addPush("Hello world!"); c.addInvoke(ByteCode.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); c.add(ByteCode.RETURN); c.stopMethod((short) 1); return c.toByteArray(); } static org.apache.bcel.generic.Type printStreamT = org.apache.bcel.generic.Type.getType("Ljava/io/PrintStream;"); static byte[] bcelHelloWorld() { ClassGen cg = new ClassGen("HelloWorld", "java/lang/Object", "HelloWorld.java", Constants.ACC_PUBLIC, null); cg.addEmptyConstructor(Constants.ACC_PUBLIC); ConstantPoolGen cp = cg.getConstantPool(); org.apache.bcel.generic.InstructionList il = new org.apache.bcel.generic.InstructionList(); org.apache.bcel.generic.InstructionFactory factory = new org.apache.bcel.generic.InstructionFactory(cg); MethodGen mg = new MethodGen(Constants.ACC_STATIC | Constants.ACC_PUBLIC, org.apache.bcel.generic.Type.VOID, new org.apache.bcel.generic.Type[] { new ArrayType(org.apache.bcel.generic.Type.STRING, 1) }, null, "main", "HelloWorld", il, cp); il.append(factory.createGetStatic("java/lang/System", "out", printStreamT)); il.append(new PUSH(cp, "Hello world!")); il.append(factory.createInvoke("java.io.PrintStream", "println", org.apache.bcel.generic.Type.VOID, new org.apache.bcel.generic.Type[] { org.apache.bcel.generic.Type.STRING }, Constants.INVOKESPECIAL)); mg.setMaxStack(); cg.addMethod(mg.getMethod()); return cg.getJavaClass().getBytes(); } static org.aspectj.apache.bcel.generic.Type printStreamAT = org.aspectj.apache.bcel.generic.Type.getType("Ljava/io/PrintStream;"); static byte[] aspectjBcelHelloWorld() { org.aspectj.apache.bcel.generic.ClassGen cg = new org.aspectj.apache.bcel.generic.ClassGen("HelloWorld", "java/lang/Object", "HelloWorld.java", Constants.ACC_PUBLIC, null); cg.addEmptyConstructor(Constants.ACC_PUBLIC); org.aspectj.apache.bcel.generic.ConstantPoolGen cp = cg.getConstantPool(); org.aspectj.apache.bcel.generic.InstructionList il = new org.aspectj.apache.bcel.generic.InstructionList(); org.aspectj.apache.bcel.generic.InstructionFactory factory = new org.aspectj.apache.bcel.generic.InstructionFactory(cg); org.aspectj.apache.bcel.generic.MethodGen mg = new org.aspectj.apache.bcel.generic.MethodGen(Constants.ACC_STATIC | Constants.ACC_PUBLIC, org.aspectj.apache.bcel.generic.Type.VOID, new org.aspectj.apache.bcel.generic.Type[] { new org.aspectj.apache.bcel.generic.ArrayType(org.aspectj.apache.bcel.generic.Type.STRING, 1) }, null, "main", "HelloWorld", il, cp); il.append(factory.createGetStatic("java/lang/System", "out", printStreamAT)); il.append(new org.aspectj.apache.bcel.generic.PUSH(cp, "Hello world!")); il.append(factory.createInvoke("java.io.PrintStream", "println", org.aspectj.apache.bcel.generic.Type.VOID, new org.aspectj.apache.bcel.generic.Type[] { org.aspectj.apache.bcel.generic.Type.STRING }, Constants.INVOKESPECIAL)); mg.setMaxStack(); cg.addMethod(mg.getMethod()); return cg.getJavaClass().getBytes(); } } asm-3.3.2/test/perf/org/objectweb/asm/ASMMemTest.java0000644000175000017500000001710010521126777022254 0ustar twernertwerner/*** * ASM performance test: measures the performances of asm package * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodNode; /* * Created on Nov 30, 2004 as part of ASMPerf by treffer */ /** * Memory performances tests for tree package. * * @author treffer */ public class ASMMemTest { public static void main(final String[] args) { if (args.length < 2) { System.out.println("java ASMMemTest "); System.exit(1); } Runtime runtime = Runtime.getRuntime(); memDown(runtime); System.out.println("Initial memory load: ".concat(memFormat(getUsedMem(runtime)))); LinkedList fileData = new LinkedList(); int limit = Integer.parseInt(args[1]); try { long totalSize = 0; JarInputStream jar = new JarInputStream(new FileInputStream(args[0])); JarEntry entry = jar.getNextJarEntry(); while (fileData.size() < limit && entry != null) { String name = entry.getName(); if (name.endsWith(".class")) { if (entry.getSize() != -1) { int len = (int) entry.getSize(); byte[] data = new byte[len]; jar.read(data); fileData.add(data); totalSize += data.length; } else { System.err.println("No jar-entry size given... Unimplemented, jar file not supported"); } } entry = jar.getNextJarEntry(); } System.out.println(memFormat(totalSize) + " class data, ~" + memFormat(totalSize / limit) + " per class."); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } ArrayList result = new ArrayList(fileData.size()); long startmem; for (int i = 0; i < 10; i++) { System.out.println("\n> Run ".concat(Integer.toString(i + 1))); Iterator files = fileData.iterator(); result.clear(); memDown(runtime); System.out.println("Empty memory load: ".concat(memFormat(startmem = getUsedMem(runtime)))); long time = -System.currentTimeMillis(); while (files.hasNext()) { byte data[] = (byte[]) files.next(); ClassReader reader = new ClassReader(data); ClassNode clazz = new ClassNode(); reader.accept(clazz, 0); result.add(clazz); } time += System.currentTimeMillis(); memDown(runtime); System.out.println("Time: ".concat(timeFormat(time))); System.out.println("Final memory load: ".concat(memFormat(getUsedMem(runtime)))); System.out.println("ASM memory load: ".concat(memFormat(getUsedMem(runtime) - startmem))); for (int j = 0; j < limit; j++) { ClassNode clazz = (ClassNode) result.get(j); List l = clazz.methods; for (int k = 0, lim = l.size(); k < lim; k++) { MethodNode m = (MethodNode) l.get(k); InsnList insn = m.instructions; if (insn != null) { insn.clear(); } } } memDown(runtime); System.out.println("ASM memory load (removed method code): ".concat(memFormat(getUsedMem(runtime) - startmem))); } } public final static long getUsedMem(final Runtime r) { return r.totalMemory() - r.freeMemory(); } public final static String timeFormat(final long time) { int min = (int) (time / (60 * 1000)); int sec = (int) ((time / 1000) % 60); int msec = (int) (time % 1000); StringBuffer sbuf = new StringBuffer(30); if (min > 0) { sbuf.append(min); sbuf.append("min "); } if (sec > 0 || min > 0) { sbuf.append(sec); sbuf.append("s "); } if (msec > 0 || sec > 0 || min > 0) { sbuf.append(msec); sbuf.append("ms "); } sbuf.append('('); sbuf.append(time); sbuf.append("ms)"); return sbuf.toString(); } public final static String memFormat(final long mem) { int gb = (int) ((mem >> 30) & 0x3FF); int mb = (int) ((mem >> 20) & 0x3FF); int kb = (int) ((mem >> 10) & 0x3FF); int bytes = (int) (mem & 0x3FF); StringBuffer sbuf = new StringBuffer(30); if (gb > 0) { sbuf.append(gb); sbuf.append("GB "); } if (mb > 0 || gb > 0) { sbuf.append(mb); sbuf.append("MB "); } if (kb > 0 || mb > 0 || gb > 0) { sbuf.append(kb); sbuf.append("KB "); } if (bytes > 0 || kb > 0 || mb > 0 || gb > 0) { sbuf.append(bytes); sbuf.append("bytes "); } sbuf.append('('); sbuf.append(mem); sbuf.append("bytes)"); return sbuf.toString(); } public final static void memDown(final Runtime r) { long oldmem; do { oldmem = getUsedMem(r); for (int i = 0; i < 10; i++) { // Calling System.gc once is very unsafe System.gc(); try { Thread.sleep(10); } catch (InterruptedException ie) { } } } while (getUsedMem(r) < oldmem); } }asm-3.3.2/test/perf/org/apache/0000755000175000017500000000000011633370217016163 5ustar twernertwernerasm-3.3.2/test/perf/org/apache/bcel/0000755000175000017500000000000011633370217017070 5ustar twernertwernerasm-3.3.2/test/perf/org/apache/bcel/verifier/0000755000175000017500000000000011633370217020703 5ustar twernertwernerasm-3.3.2/test/perf/org/apache/bcel/verifier/structurals/0000755000175000017500000000000011633370217023276 5ustar twernertwernerasm-3.3.2/test/perf/org/apache/bcel/verifier/structurals/ModifiedPass3bVerifier.java0000644000175000017500000004327211342504140030430 0ustar twernertwerner/* * Copyright 2000-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.bcel.verifier.structurals; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Vector; import org.apache.bcel.Constants; import org.apache.bcel.Repository; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.GETFIELD; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InvokeInstruction; import org.apache.bcel.generic.JsrInstruction; import org.apache.bcel.generic.LoadInstruction; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.generic.ObjectType; import org.apache.bcel.generic.RET; import org.apache.bcel.generic.ReturnInstruction; import org.apache.bcel.generic.ReturnaddressType; import org.apache.bcel.generic.Type; import org.apache.bcel.verifier.PassVerifier; import org.apache.bcel.verifier.VerificationResult; import org.apache.bcel.verifier.Verifier; import org.apache.bcel.verifier.exc.AssertionViolatedException; import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; import org.apache.bcel.verifier.exc.VerifierConstraintViolatedException; /** * This PassVerifier verifies a method of class file according to pass 3, * so-called structural verification as described in The Java Virtual Machine * Specification, 2nd edition. * More detailed information is to be found at the do_verify() method's * documentation. * * @version $Id: ModifiedPass3bVerifier.java,v 1.3 2007-11-08 17:22:56 ebruneton Exp $ * @author Enver Haase * @see #do_verify() */ public final class ModifiedPass3bVerifier extends PassVerifier{ /* TODO: Throughout pass 3b, upper halves of LONG and DOUBLE are represented by Type.UNKNOWN. This should be changed in favour of LONG_Upper and DOUBLE_Upper as in pass 2. */ /** * An InstructionContextQueue is a utility class that holds * (InstructionContext, ArrayList) pairs in a Queue data structure. * This is used to hold information about InstructionContext objects * externally --- i.e. that information is not saved inside the * InstructionContext object itself. This is useful to save the * execution path of the symbolic execution of the * Pass3bVerifier - this is not information * that belongs into the InstructionContext object itself. * Only at "execute()"ing * time, an InstructionContext object will get the current information * we have about its symbolic execution predecessors. */ static final class InstructionContextQueue{ private List ics = new Vector(); // Type: InstructionContext private List ecs = new Vector(); // Type: ArrayList (of InstructionContext) public void add(InstructionContext ic, ArrayList executionChain){ ics.add(ic); ecs.add(executionChain); } public boolean isEmpty(){ return ics.isEmpty(); } public void remove(){ this.remove(0); } public void remove(int i){ ics.remove(i); ecs.remove(i); } public InstructionContext getIC(int i){ return (InstructionContext) ics.get(i); } public ArrayList getEC(int i){ return (ArrayList) ecs.get(i); } public int size(){ return ics.size(); } } // end Inner Class InstructionContextQueue /** In DEBUG mode, the verification algorithm is not randomized. */ private static final boolean DEBUG = true; private JavaClass jc; /** The method number to verify. */ private int method_no; /** * This class should only be instantiated by a Verifier. * * @see org.apache.bcel.verifier.Verifier */ public ModifiedPass3bVerifier(JavaClass jc, int method_no){ this.jc = jc; this.method_no = method_no; } /** * Whenever the outgoing frame * situation of an InstructionContext changes, all its successors are * put [back] into the queue [as if they were unvisited]. * The proof of termination is about the existence of a * fix point of frame merging. */ private void circulationPump(MethodGen m,ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){ final Random random = new Random(); InstructionContextQueue icq = new InstructionContextQueue(); start.execute(vanillaFrame, new ArrayList(), icv, ev); // new ArrayList() <=> no Instruction was executed before // => Top-Level routine (no jsr call before) icq.add(start, new ArrayList()); // LOOP! while (!icq.isEmpty()){ InstructionContext u; ArrayList ec; if (!DEBUG){ int r = random.nextInt(icq.size()); u = icq.getIC(r); ec = icq.getEC(r); icq.remove(r); } else{ u = icq.getIC(0); ec = icq.getEC(0); icq.remove(0); } ArrayList oldchain = (ArrayList) (ec.clone()); ArrayList newchain = (ArrayList) (ec.clone()); newchain.add(u); if ((u.getInstruction().getInstruction()) instanceof RET){ //System.err.println(u); // We can only follow _one_ successor, the one after the // JSR that was recently executed. RET ret = (RET) (u.getInstruction().getInstruction()); ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); // Sanity check InstructionContext lastJSR = null; int skip_jsr = 0; for (int ss=oldchain.size()-1; ss >= 0; ss--){ if (skip_jsr < 0){ throw new AssertionViolatedException("More RET than JSR in execution chain?!"); } //System.err.println("+"+oldchain.get(ss)); if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){ if (skip_jsr == 0){ lastJSR = (InstructionContext) oldchain.get(ss); break; } else{ skip_jsr--; } } if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof RET){ skip_jsr++; } } if (lastJSR == null){ throw new AssertionViolatedException("RET without a JSR before in ExecutionChain?! EC: '"+oldchain+"'."); } JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction()); if ( theSuccessor != (cfg.contextOf(jsr.physicalSuccessor())) ){ throw new AssertionViolatedException("RET '"+u.getInstruction()+"' info inconsistent: jump back to '"+theSuccessor+"' or '"+cfg.contextOf(jsr.physicalSuccessor())+"'?"); } if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)){ icq.add(theSuccessor, (ArrayList) newchain.clone()); } } else{// "not a ret" // Normal successors. Add them to the queue of successors. InstructionContext[] succs = u.getSuccessors(); for (int s=0; s. */ import org.apache.bcel.Constants; import java.io.*; /** * This class is derived from Attribute and represents a reference to * a GJ attribute. * * @version $Id: Signature.java,v 1.2 2006-07-05 15:22:56 ebruneton Exp $ * @author M. Dahm * @see Attribute */ public final class Signature extends Attribute { private int signature_index; /** * Initialize from another object. Note that both objects use the same * references (shallow copy). Use clone() for a physical copy. * * @param c */ public Signature(final Signature c) { this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); } /** * Construct object from file stream. * * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ Signature( final int name_index, final int length, final DataInputStream file, final ConstantPool constant_pool) throws IOException { this(name_index, length, file.readUnsignedShort(), constant_pool); } /** * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param constant_pool Array of constants * @param signature_index Index in constant pool to CONSTANT_Utf8 */ public Signature( final int name_index, final int length, final int signature_index, final ConstantPool constant_pool) { super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); this.signature_index = signature_index; } /** * Called by objects that are traversing the nodes of the tree implicitely * defined by the contents of a Java class. I.e., the hierarchy of methods, * fields, attributes, etc. spawns a tree of objects. * * @param v Visitor object */ public void accept(final Visitor v) { // System.err.println("Visiting non-standard Signature object"); // v.visitSignature(this); } /** * Dump source file attribute to file stream in binary format. * * @param file Output file stream * @throws IOException */ public final void dump(final DataOutputStream file) throws IOException { super.dump(file); file.writeShort(signature_index); } /** * @return Index in constant pool of source file name. */ public final int getSignatureIndex() { return signature_index; } /** * @param signature_index */ public final void setSignatureIndex(final int signature_index) { this.signature_index = signature_index; } /** * @return GJ signature. */ public final String getSignature() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * Extends ByteArrayInputStream to make 'unreading' chars possible. */ private static final class MyByteArrayInputStream extends ByteArrayInputStream { MyByteArrayInputStream(final String data) { super(data.getBytes()); } final int mark() { return pos; } final String getData() { return new String(buf); } final void reset(final int p) { pos = p; } final void unread() { if (pos > 0) { pos--; } } } private static boolean identStart(final int ch) { return ch == 'T' || ch == 'L'; } // private static boolean identPart(int ch) { // return ch == '/' || ch == ';'; // } private static final void matchIdent( final MyByteArrayInputStream in, final StringBuffer buf) { int ch; if ((ch = in.read()) == -1) { throw new RuntimeException("Illegal signature: " + in.getData() + " no ident, reaching EOF"); } // System.out.println("return from ident:" + (char)ch); if (!identStart(ch)) { StringBuffer buf2 = new StringBuffer(); int count = 1; while (Character.isJavaIdentifierPart((char) ch)) { buf2.append((char) ch); count++; ch = in.read(); } if (ch == ':') { // Ok, formal parameter in.skip("Ljava/lang/Object".length()); buf.append(buf2); ch = in.read(); in.unread(); // System.out.println("so far:" + buf2 + ":next:" +(char)ch); } else { for (int i = 0; i < count; i++) { in.unread(); } } return; } StringBuffer buf2 = new StringBuffer(); ch = in.read(); do { buf2.append((char) ch); ch = in.read(); // System.out.println("within ident:"+ (char)ch); } while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/')); buf.append(buf2.toString().replace('/', '.')); // System.out.println("regular return ident:"+ (char)ch + ":" + buf2); if (ch != -1) { in.unread(); } } private static final void matchGJIdent( final MyByteArrayInputStream in, final StringBuffer buf) { int ch; matchIdent(in, buf); ch = in.read(); if (ch == '<' || ch == '(') { // Parameterized or method // System.out.println("Enter <"); buf.append((char) ch); matchGJIdent(in, buf); while ((ch = in.read()) != '>' && ch != ')') { // List of // parameters if (ch == -1) { throw new RuntimeException("Illegal signature: " + in.getData() + " reaching EOF"); } // System.out.println("Still no >"); buf.append(", "); in.unread(); matchGJIdent(in, buf); // Recursive call } // System.out.println("Exit >"); buf.append((char) ch); } else { in.unread(); } ch = in.read(); if (identStart(ch)) { in.unread(); matchGJIdent(in, buf); } else if (ch == ')') { in.unread(); return; } else if (ch != ';') { throw new RuntimeException("Illegal signature: " + in.getData() + " read " + (char) ch); } } public static String translate(final String s) { // System.out.println("Sig:" + s); StringBuffer buf = new StringBuffer(); matchGJIdent(new MyByteArrayInputStream(s), buf); return buf.toString(); } public static final boolean isFormalParameterList(final String s) { return s.startsWith("<") && s.indexOf(':') > 0; } public static final boolean isActualParameterList(final String s) { return s.startsWith("L") && s.endsWith(">;"); } /** * @return String representation */ public final String toString() { String s = getSignature(); return "Signature(" + s + ")"; } /** * @param constant_pool * @return deep copy of this attribute */ public Attribute copy(final ConstantPool constant_pool) { return (Signature) clone(); } } asm-3.3.2/test/perf/org/aspectj/apache/bcel/verifier/0000755000175000017500000000000011633370220022326 5ustar twernertwernerasm-3.3.2/test/perf/org/aspectj/apache/bcel/verifier/structurals/0000755000175000017500000000000011633370220024721 5ustar twernertwernerasm-3.3.2/test/perf/org/aspectj/apache/bcel/verifier/structurals/ModifiedPass3bVerifier.java0000644000175000017500000004174211224532001032055 0ustar twernertwerner/* * Copyright 2000-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.aspectj.apache.bcel.verifier.structurals; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Random; import java.util.Vector; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.apache.bcel.generic.ConstantPoolGen; import org.aspectj.apache.bcel.generic.JsrInstruction; import org.aspectj.apache.bcel.generic.MethodGen; import org.aspectj.apache.bcel.generic.ObjectType; import org.aspectj.apache.bcel.generic.RET; import org.aspectj.apache.bcel.generic.ReturnaddressType; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.apache.bcel.verifier.VerificationResult; import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException; import org.aspectj.apache.bcel.verifier.exc.VerifierConstraintViolatedException; import org.aspectj.apache.bcel.verifier.structurals.ControlFlowGraph; import org.aspectj.apache.bcel.verifier.structurals.ExceptionHandler; import org.aspectj.apache.bcel.verifier.structurals.ExecutionVisitor; import org.aspectj.apache.bcel.verifier.structurals.Frame; import org.aspectj.apache.bcel.verifier.structurals.InstConstraintVisitor; import org.aspectj.apache.bcel.verifier.structurals.InstructionContext; import org.aspectj.apache.bcel.verifier.structurals.OperandStack; import org.aspectj.apache.bcel.verifier.structurals.UninitializedObjectType; /** * This PassVerifier verifies a method of class file according to pass 3, * so-called structural verification as described in The Java Virtual Machine * Specification, 2nd edition. More detailed information is to be found at the * do_verify() method's documentation. * * @version $Id: ModifiedPass3bVerifier.java,v 1.1.2.1 2005/09/16 07:19:38 * ebruneton Exp $ * @author Enver Haase * @see #do_verify() */ public final class ModifiedPass3bVerifier { /* * TODO: Throughout pass 3b, upper halves of LONG and DOUBLE are represented * by Type.UNKNOWN. This should be changed in favour of LONG_Upper and * DOUBLE_Upper as in pass 2. */ /** * An InstructionContextQueue is a utility class that holds * (InstructionContext, ArrayList) pairs in a Queue data structure. This is * used to hold information about InstructionContext objects externally --- * i.e. that information is not saved inside the InstructionContext object * itself. This is useful to save the execution path of the symbolic * execution of the Pass3bVerifier - this is not information that belongs * into the InstructionContext object itself. Only at "execute()"ing time, * an InstructionContext object will get the current information we have * about its symbolic execution predecessors. */ static final class InstructionContextQueue { private final Vector ics = new Vector(); // Type: InstructionContext private final Vector ecs = new Vector(); // Type: ArrayList (of // InstructionContext) public void add( final InstructionContext ic, final ArrayList executionChain) { ics.add(ic); ecs.add(executionChain); } public boolean isEmpty() { return ics.isEmpty(); } public void remove() { this.remove(0); } public void remove(final int i) { ics.remove(i); ecs.remove(i); } public InstructionContext getIC(final int i) { return (InstructionContext) ics.get(i); } public ArrayList getEC(final int i) { return (ArrayList) ecs.get(i); } public int size() { return ics.size(); } } // end Inner Class InstructionContextQueue /** In DEBUG mode, the verification algorithm is not randomized. */ private static final boolean DEBUG = true; /** The Verifier that created this. */ private JavaClass jc; /** The method number to verify. */ private int method_no; /** * This class should only be instantiated by a Verifier. * * @param jc * @param method_no * * @see org.apache.bcel.verifier.Verifier */ public ModifiedPass3bVerifier(final JavaClass jc, final int method_no) { this.jc = jc; this.method_no = method_no; } /** * Whenever the outgoing frame situation of an InstructionContext changes, * all its successors are put [back] into the queue [as if they were * unvisited]. The proof of termination is about the existence of a fix * point of frame merging. * * @param cfg * @param start * @param vanillaFrame * @param icv * @param ev */ private void circulationPump( final ControlFlowGraph cfg, final InstructionContext start, final Frame vanillaFrame, final InstConstraintVisitor icv, final ExecutionVisitor ev) { final Random random = new Random(); InstructionContextQueue icq = new InstructionContextQueue(); start.execute(vanillaFrame, new ArrayList(), icv, ev); // new // ArrayList() // <=> no // Instruction // was executed // before // => Top-Level routine (no jsr call before) icq.add(start, new ArrayList()); // LOOP! while (!icq.isEmpty()) { InstructionContext u; ArrayList ec; if (!DEBUG) { int r = random.nextInt(icq.size()); u = icq.getIC(r); ec = icq.getEC(r); icq.remove(r); } else { u = icq.getIC(0); ec = icq.getEC(0); icq.remove(0); } ArrayList oldchain = (ArrayList) ec.clone(); ArrayList newchain = (ArrayList) ec.clone(); newchain.add(u); if (u.getInstruction().getInstruction() instanceof RET) { // System.err.println(u); // We can only follow _one_ successor, the one after the // JSR that was recently executed. RET ret = (RET) u.getInstruction().getInstruction(); ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain) .getLocals() .get(ret.getIndex()); InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); // Sanity check InstructionContext lastJSR = null; int skip_jsr = 0; for (int ss = oldchain.size() - 1; ss >= 0; ss--) { if (skip_jsr < 0) { throw new AssertionViolatedException("More RET than JSR in execution chain?!"); } // System.err.println("+"+oldchain.get(ss)); if (((InstructionContext) oldchain.get(ss)).getInstruction() .getInstruction() instanceof JsrInstruction) { if (skip_jsr == 0) { lastJSR = (InstructionContext) oldchain.get(ss); break; } else { skip_jsr--; } } if (((InstructionContext) oldchain.get(ss)).getInstruction() .getInstruction() instanceof RET) { skip_jsr++; } } if (lastJSR == null) { throw new AssertionViolatedException("RET without a JSR before in ExecutionChain?! EC: '" + oldchain + "'."); } JsrInstruction jsr = (JsrInstruction) lastJSR.getInstruction() .getInstruction(); if (theSuccessor != cfg.contextOf(jsr.physicalSuccessor())) { throw new AssertionViolatedException("RET '" + u.getInstruction() + "' info inconsistent: jump back to '" + theSuccessor + "' or '" + cfg.contextOf(jsr.physicalSuccessor()) + "'?"); } if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { icq.add(theSuccessor, (ArrayList) newchain.clone()); } } else {// "not a ret" // Normal successors. Add them to the queue of successors. InstructionContext[] succs = u.getSuccessors(); for (int s = 0; s < succs.length; s++) { InstructionContext v = succs[s]; if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { icq.add(v, (ArrayList) newchain.clone()); } } }// end "not a ret" // Exception Handlers. Add them to the queue of successors. // [subroutines are never protected; mandated by JustIce] ExceptionHandler[] exc_hds = u.getExceptionHandlers(); for (int s = 0; s < exc_hds.length; s++) { InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart()); // TODO: the "oldchain" and "newchain" is used to determine the // subroutine // we're in (by searching for the last JSR) by the // InstructionContext // implementation. Therefore, we should not use this chain // mechanism // when dealing with exception handlers. // Example: a JSR with an exception handler as its successor // does not // mean we're in a subroutine if we go to the exception handler. // We should address this problem later; by now we simply "cut" // the chain // by using an empty chain for the exception handlers. // if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), // new OperandStack (u.getOutFrame().getStack().maxStack(), // (exc_hds[s].getExceptionType()==null? Type.THROWABLE : // exc_hds[s].getExceptionType())) ), newchain), icv, ev){ // icq.add(v, (ArrayList) newchain.clone()); if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack(u.getOutFrame(oldchain) .getStack() .maxStack(), (exc_hds[s].getExceptionType() == null ? Type.THROWABLE : exc_hds[s].getExceptionType()))), new ArrayList(), icv, ev)) { icq.add(v, new ArrayList()); } } }// while (!icq.isEmpty()) END // InstructionHandle ih = start.getInstruction(); // do{ // if ((ih.getInstruction() instanceof ReturnInstruction) && // (!(cfg.isDead(ih)))) { // InstructionContext ic = cfg.contextOf(ih); // Frame f = ic.getOutFrame(new ArrayList()); // TODO: This is buggy, we // check only the top-level return instructions this way. Maybe some // maniac returns from a method when in a subroutine? // LocalVariables lvs = f.getLocals(); // for (int i=0; i asm-3.3.2/test/conform/0000755000175000017500000000000011633370175014665 5ustar twernertwernerasm-3.3.2/test/conform/verifyclass.xml0000644000175000017500000000113211434755347017745 0ustar twernertwerner asm-3.3.2/test/conform/classreader.xml0000644000175000017500000000113210140406020017651 0ustar twernertwerner asm-3.3.2/test/conform/saxadapter.xml0000644000175000017500000000112710143655501017536 0ustar twernertwerner asm-3.3.2/test/conform/annotations.xml0000644000175000017500000000113010522056320017724 0ustar twernertwerner asm-3.3.2/test/conform/localvariablessorter2.xml0000644000175000017500000000666210452754520021723 0ustar twernertwerner asm-3.3.2/test/conform/localvariablessorter.xml0000644000175000017500000000114110233405570021617 0ustar twernertwerner asm-3.3.2/test/conform/checksignatureadapter.xml0000644000175000017500000000114410664276120021745 0ustar twernertwerner asm-3.3.2/test/conform/unit.xml0000644000175000017500000000075210452754520016370 0ustar twernertwerner asm-3.3.2/test/conform/traceclassadapter.xml0000644000175000017500000000114010260173427021064 0ustar twernertwerner asm-3.3.2/test/conform/staticinitmerger.xml0000644000175000017500000000076510233405570020765 0ustar twernertwerner asm-3.3.2/test/conform/classadapter.xml0000644000175000017500000000113110140406020020026 0ustar twernertwerner asm-3.3.2/test/conform/adviceadapter.xml0000644000175000017500000000113410334575654020210 0ustar twernertwerner asm-3.3.2/test/conform/analyzeradapter.xml0000644000175000017500000000113410452754520020572 0ustar twernertwerner asm-3.3.2/test/conform/classwriterresizeinsns.xml0000644000175000017500000000552110452754520022247 0ustar twernertwerner asm-3.3.2/test/conform/basicverifier.xml0000644000175000017500000000113410140406020020200 0ustar twernertwerner asm-3.3.2/test/conform/checkclassadapter.xml0000644000175000017500000000114010140406020021024 0ustar twernertwerner asm-3.3.2/test/conform/codesizeevaluator.xml0000644000175000017500000000114010452754520021131 0ustar twernertwerner asm-3.3.2/test/conform/gasmifier.xml0000644000175000017500000000153610452754520017360 0ustar twernertwerner asm-3.3.2/test/conform/sourceinterpreter.xml0000644000175000017500000000114010452754520021165 0ustar twernertwerner asm-3.3.2/test/conform/simpleverifier.xml0000644000175000017500000000435310452754520020437 0ustar twernertwerner asm-3.3.2/test/conform/svuidadder.xml0000644000175000017500000000114410452754520017537 0ustar twernertwerner asm-3.3.2/test/conform/classwritercopypool.xml0000644000175000017500000000114010452754520021530 0ustar twernertwerner asm-3.3.2/test/conform/jsrinlineradapter.xml0000644000175000017500000000123610452754520021127 0ustar twernertwerner asm-3.3.2/test/conform/remappingadapter.xml0000644000175000017500000000114210564776410020734 0ustar twernertwerner asm-3.3.2/test/conform/remappingadapter2.xml0000644000175000017500000000114310564776410021017 0ustar twernertwerner asm-3.3.2/test/conform/org/0000755000175000017500000000000011633370174015453 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/0000755000175000017500000000000011633370174017417 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/0000755000175000017500000000000011633370175020200 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/util/0000755000175000017500000000000011633370175021155 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/util/TraceSignatureVisitorUnitTest.java0000644000175000017500000001735010530757141030023 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.util.StringTokenizer; import junit.framework.TestCase; import junit.framework.TestSuite; import org.objectweb.asm.Opcodes; import org.objectweb.asm.signature.SignatureReader; /** * TraceSignatureVisitor unit tests. * * @author Eugene Kuleshov */ public class TraceSignatureVisitorUnitTest extends TestCase { public final static String[] DATA = { "C|E|> implements java.lang.Comparable, java.io.Serializable" + "|;>Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable;", "C|I| extends java.lang.reflect.Type" + "|Ljava/lang/Object;Ljava/lang/reflect/Type;", "C|C| extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap, java.io.Serializable" + "|Ljava/util/AbstractMap;Ljava/util/concurrent/ConcurrentMap;Ljava/io/Serializable;", "C|C|, V> extends java.util.AbstractMap implements java.io.Serializable, java.lang.Cloneable" + "|;V:Ljava/lang/Object;>Ljava/util/AbstractMap;Ljava/io/Serializable;Ljava/lang/Cloneable;", "F|C|java.lang.Class|Ljava/lang/Class<*>;", "F|C|java.lang.reflect.Constructor|Ljava/lang/reflect/Constructor;", "F|C|T[]|[TT;", "F|C|java.util.Hashtable|Ljava/util/Hashtable<**>;", "F|C|java.util.concurrent.atomic.AtomicReferenceFieldUpdater" + "|Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;", "F|C|AA|LAA<[[B>;", "F|C|AA[][]>" + "|LAA<[[Ljava/util/Map;>;", "F|C|java.util.Hashtable" + "|Ljava/util/Hashtable;", "M|C|void(boolean, byte, char, short, int, float, long, double)" + "|(ZBCSIFJD)V", "M|C|void()E, F|()V^TE;^TF;", "M|C|java.lang.Class()" + "|()Ljava/lang/Class<+TE;>;", "M|C|java.lang.Class()" + "|()Ljava/lang/Class<-TE;>;", "M|C|void(A.B)|(LA.B;)V", "M|C|void(A.B)|(LA.B;)V", "M|C|void(java.lang.String, java.lang.Class, java.lang.reflect.Method[], java.lang.reflect.Method, java.lang.reflect.Method)" + "|(Ljava/lang/String;Ljava/lang/Class<*>;[Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V", "M|C|java.util.Map(java.lang.Object, java.util.Map)" + "|(Ljava/lang/Object;Ljava/util/Map;)Ljava/util/Map;", "M|C|java.util.Map(java.lang.Object, java.util.Map, T)" + "|(Ljava/lang/Object;Ljava/util/Map;TT;)Ljava/util/Map;", "M|C|java.util.Map>(java.lang.Object, java.util.Map, T)" + "|;>(Ljava/lang/Object;Ljava/util/Map;TT;)Ljava/util/Map;", }; public static TestSuite suite() { TestSuite suite = new TestSuite(TraceSignatureVisitorUnitTest.class.getName()); for (int i = 0; i < DATA.length; i++) { suite.addTest(new TraceSignatureVisitorUnitTest(new TestData(DATA[i]))); } return suite; } private TestData data; private TraceSignatureVisitorUnitTest(final TestData data) { super("testSignature"); this.data = data; } public void testSignature() { TraceSignatureVisitor d = new TraceSignatureVisitor(data.access); SignatureReader r = new SignatureReader(data.signature); switch (data.type) { case 'C': r.accept(d); assertEquals(data.declaration, d.getDeclaration()); break; case 'F': r.acceptType(d); assertEquals(data.declaration, d.getDeclaration()); break; case 'M': r.accept(d); String fullMethodDeclaration = d.getReturnType() + d.getDeclaration() + (d.getExceptions() != null ? d.getExceptions() : ""); assertEquals(data.declaration, fullMethodDeclaration); break; } } public String getName() { return super.getName() + " " + data.signature; } public static class TestData { public final char type; public final int access; public final String declaration; public final String signature; public TestData(final String data) { StringTokenizer st = new StringTokenizer(data, "|"); this.type = st.nextToken().charAt(0); String acc = st.nextToken(); switch (acc.charAt(0)) { case 'E': this.access = Opcodes.ACC_ENUM; break; case 'I': this.access = Opcodes.ACC_INTERFACE; break; case 'A': this.access = Opcodes.ACC_ANNOTATION; break; default: this.access = 0; } this.declaration = st.nextToken(); this.signature = st.nextToken(); } } } asm-3.3.2/test/conform/org/objectweb/asm/util/ASMifierUnitTest.java0000644000175000017500000000425410452754520025162 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import junit.framework.TestCase; /** * ASMifierClassVisitor unit tests * * @author Eric Bruneton */ public class ASMifierUnitTest extends TestCase { public void testASMifierClassVisitor() throws Exception { String s = getClass().getName(); ASMifierClassVisitor.main(new String[0]); ASMifierClassVisitor.main(new String[] { "-debug" }); ASMifierClassVisitor.main(new String[] { s }); ASMifierClassVisitor.main(new String[] { "-debug", s }); ASMifierClassVisitor.main(new String[] { "output/test/cases/Interface.class" }); } } asm-3.3.2/test/conform/org/objectweb/asm/util/CheckClassAdapterTest.java0000644000175000017500000000434310452754520026166 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; /** * CheckClassAdapter tests. * * @author Eric Bruneton */ public class CheckClassAdapterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new CheckClassAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); cr.accept(new CheckClassAdapter(cw), 0); assertEquals(cr, new ClassReader(cw.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/util/VerifyClassTest.java0000644000175000017500000000502711434755347025125 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.PrintWriter; import java.io.StringWriter; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; /** * CheckClassAdapter tests. * * @author Eric Bruneton */ public class VerifyClassTest extends AbstractTest { public static TestSuite suite() throws Exception { return new VerifyClassTest().getSuite(); } public void test() throws Exception { if (n.startsWith("pkg.")) { return; } ClassReader cr = new ClassReader(is); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); CheckClassAdapter.verify(cr, false, pw); pw.close(); String s = sw.toString(); if (!s.isEmpty()) { System.out.println("In class: " + n); System.out.println(s); } assertTrue(s.isEmpty()); } } asm-3.3.2/test/conform/org/objectweb/asm/util/ASMifierTest.java0000644000175000017500000001054110452754520024316 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import junit.framework.TestSuite; import org.codehaus.janino.ClassLoaderIClassLoader; import org.codehaus.janino.DebuggingInformation; import org.codehaus.janino.IClassLoader; import org.codehaus.janino.Parser; import org.codehaus.janino.Scanner; import org.codehaus.janino.UnitCompiler; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassReader; import org.objectweb.asm.attrs.CodeComment; import org.objectweb.asm.attrs.Comment; import org.objectweb.asm.util.ASMifierClassVisitor; /** * ASMifier tests. * * @author Eugene Kuleshov * @author Eric Bruneton */ public class ASMifierTest extends AbstractTest { public static final Compiler COMPILER = new Compiler(); public static final TestClassLoader LOADER = new TestClassLoader(); public static TestSuite suite() throws Exception { return new ASMifierTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); if (cr.b.length > 20000) { return; } StringWriter sw = new StringWriter(); ASMifierClassVisitor cv = new ASMifierClassVisitor(new PrintWriter(sw)); cr.accept(cv, new Attribute[] { new Comment(), new CodeComment() }, 0); String generated = sw.toString(); byte[] generatorClassData; try { generatorClassData = COMPILER.compile(n, generated); } catch (Exception ex) { System.err.println(generated); System.err.println("------------------"); throw ex; } String nd = n + "Dump"; if (n.indexOf('.') != -1) { nd = "asm." + nd; } Class c = LOADER.defineClass(nd, generatorClassData); Method m = c.getMethod("dump", new Class[0]); byte[] b = (byte[]) m.invoke(null, new Object[0]); assertEquals(cr, new ClassReader(b)); } public static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } public static class Compiler { final static IClassLoader CL = new ClassLoaderIClassLoader(new URLClassLoader(new URL[0])); public byte[] compile(final String name, final String source) throws Exception { Parser p = new Parser(new Scanner(name, new StringReader(source))); UnitCompiler uc = new UnitCompiler(p.parseCompilationUnit(), CL); return uc.compileUnit(DebuggingInformation.ALL)[0].toByteArray(); } } } asm-3.3.2/test/conform/org/objectweb/asm/util/CheckClassAdapterUnitTest.java0000644000175000017500000006607011052515015027022 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import junit.framework.TestCase; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.attrs.Comment; import org.objectweb.asm.commons.EmptyVisitor; public class CheckClassAdapterUnitTest extends TestCase implements Opcodes { public void testCheckClassVisitor() throws Exception { String s = getClass().getName(); CheckClassAdapter.main(new String[0]); CheckClassAdapter.main(new String[] { s }); CheckClassAdapter.main(new String[] { "output/test/cases/Interface.class" }); } public void testVerifyValidClass() throws Exception { ClassReader cr = new ClassReader(getClass().getName()); CheckClassAdapter.verify(cr, true, new PrintWriter(System.err)); } public void testVerifyInvalidClass() { ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ISTORE, 30); mv.visitInsn(RETURN); mv.visitMaxs(1, 31); mv.visitEnd(); cw.visitEnd(); ClassReader cr = new ClassReader(cw.toByteArray()); CheckClassAdapter.verify(cr, true, new PrintWriter(System.err)); } public void testIllegalClassAccessFlag() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visit(V1_1, 1 << 20, "C", null, "java/lang/Object", null); fail(); } catch (Exception e) { } } public void testIllegalSuperClass() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visit(V1_1, ACC_PUBLIC, "java/lang/Object", null, "java/lang/Object", null); fail(); } catch (Exception e) { } } public void testIllegalInterfaceSuperClass() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visit(V1_1, ACC_INTERFACE, "I", null, "C", null); fail(); } catch (Exception e) { } } public void testIllegalClassSignature() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visit(V1_1, ACC_PUBLIC, "C", "LC;I", "java/lang/Object", null); fail(); } catch (Exception e) { } } public void testIllegalClassAccessFlagSet() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visit(V1_1, ACC_FINAL + ACC_ABSTRACT, "C", null, "java/lang/Object", null); fail(); } catch (Exception e) { } } public void testIllegalClassMemberVisitBeforeStart() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); try { cv.visitSource(null, null); fail(); } catch (Exception e) { } } public void testIllegalClassAttribute() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visitAttribute(null); fail(); } catch (Exception e) { } } public void testIllegalMultipleVisitCalls() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); fail(); } catch (Exception e) { } } public void testIllegalMultipleVisitSourceCalls() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); cv.visitSource(null, null); try { cv.visitSource(null, null); fail(); } catch (Exception e) { } } public void testIllegalOuterClassName() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visitOuterClass(null, null, null); fail(); } catch (Exception e) { } } public void testIllegalMultipleVisitOuterClassCalls() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); cv.visitOuterClass("name", null, null); try { cv.visitOuterClass(null, null, null); fail(); } catch (Exception e) { } } public void testIllegalFieldAccessFlagSet() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visitField(ACC_PUBLIC + ACC_PRIVATE, "i", "I", null, null); fail(); } catch (Exception e) { } } public void testIllegalFieldSignature() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visitField(ACC_PUBLIC, "i", "I", "L;", null); fail(); } catch (Exception e) { } try { cv.visitField(ACC_PUBLIC, "i", "I", "LC+", null); fail(); } catch (Exception e) { } try { cv.visitField(ACC_PUBLIC, "i", "I", "LC;I", null); fail(); } catch (Exception e) { } } public void testIllegalClassMemberVisitAfterEnd() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); cv.visitEnd(); try { cv.visitSource(null, null); fail(); } catch (Exception e) { } } public void testIllegalFieldMemberVisitAfterEnd() { FieldVisitor fv = new CheckFieldAdapter(new EmptyVisitor()); fv.visitEnd(); try { fv.visitAttribute(new Comment()); fail(); } catch (Exception e) { } } public void testIllegalFieldAttribute() { FieldVisitor fv = new CheckFieldAdapter(new EmptyVisitor()); try { fv.visitAttribute(null); fail(); } catch (Exception e) { } } public void testIllegalAnnotationDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); try { mv.visitParameterAnnotation(0, "'", true); fail(); } catch (Exception e) { } } public void testIllegalAnnotationName() { AnnotationVisitor av = new CheckAnnotationAdapter(new EmptyVisitor()); try { av.visit(null, new Integer(0)); fail(); } catch (Exception e) { } } public void testIllegalAnnotationValue() { AnnotationVisitor av = new CheckAnnotationAdapter(new EmptyVisitor()); try { av.visit("name", new Object()); fail(); } catch (Exception e) { } } public void testIllegalAnnotationEnumValue() { AnnotationVisitor av = new CheckAnnotationAdapter(new EmptyVisitor()); try { av.visitEnum("name", "Lpkg/Enum;", null); fail(); } catch (Exception e) { } } public void testIllegalAnnotationValueAfterEnd() { AnnotationVisitor av = new CheckAnnotationAdapter(new EmptyVisitor()); av.visitEnd(); try { av.visit("name", new Integer(0)); fail(); } catch (Exception e) { } } public void testIllegalMethodMemberVisitAfterEnd() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitEnd(); try { mv.visitAttribute(new Comment()); fail(); } catch (Exception e) { } } public void testIllegalMethodAttribute() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); try { mv.visitAttribute(null); fail(); } catch (Exception e) { } } public void testIllegalMethodSignature() { ClassVisitor cv = new CheckClassAdapter(new EmptyVisitor()); cv.visit(V1_1, ACC_PUBLIC, "C", null, "java/lang/Object", null); try { cv.visitMethod(ACC_PUBLIC, "m", "()V", ";>()V^LA;X", null); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnVisitBeforeStart() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); try { mv.visitInsn(NOP); fail(); } catch (Exception e) { } } public void testIllegalFrameType() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(123, 0, null, 0, null); fail(); } catch (Exception e) { } } public void testIllegalFrameLocalCount() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(F_SAME, 1, new Object[] { INTEGER }, 0, null); fail(); } catch (Exception e) { } } public void testIllegalFrameStackCount() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(F_SAME, 0, null, 1, new Object[] { INTEGER }); fail(); } catch (Exception e) { } } public void testIllegalFrameLocalArray() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(F_APPEND, 1, new Object[0], 0, null); fail(); } catch (Exception e) { } } public void testIllegalFrameStackArray() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(F_SAME1, 0, null, 1, new Object[0]); fail(); } catch (Exception e) { } } public void testIllegalFrameValue() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFrame(F_FULL, 1, new Object[] { "LC;" }, 0, null); fail(); } catch (Exception e) { } try { mv.visitFrame(F_FULL, 1, new Object[] { new Integer(0) }, 0, null); fail(); } catch (Exception e) { } } public void testIllegalMethodInsn() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitInsn(-1); fail(); } catch (Exception e) { } } public void testIllegalByteInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitIntInsn(BIPUSH, Integer.MAX_VALUE); fail(); } catch (Exception e) { } } public void testIllegalShortInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitIntInsn(SIPUSH, Integer.MAX_VALUE); fail(); } catch (Exception e) { } } public void testIllegalVarInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitVarInsn(ALOAD, -1); fail(); } catch (Exception e) { } } public void testIllegalIntInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitIntInsn(NEWARRAY, 0); fail(); } catch (Exception e) { } } public void testIllegalTypeInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitTypeInsn(NEW, "[I"); fail(); } catch (Exception e) { } } public void testIllegalLabelInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); Label l = new Label(); mv.visitLabel(l); try { mv.visitLabel(l); fail(); } catch (Exception e) { } } public void testIllegalDebugLabelUse() throws IOException { ClassReader cr = new ClassReader("java.lang.Object"); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); ClassVisitor cv = new ClassAdapter(cw) { public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { final MethodVisitor next = cv.visitMethod(access, name, desc, signature, exceptions); if (next == null) { return next; } return new MethodAdapter(new CheckMethodAdapter(next)) { private Label entryLabel = null; public void visitLabel(Label label) { if (entryLabel == null) { entryLabel = label; } mv.visitLabel(label); } public void visitMaxs(int maxStack, int maxLocals) { Label unwindhandler = new Label(); mv.visitLabel(unwindhandler); mv.visitInsn(Opcodes.ATHROW); // rethrow mv.visitTryCatchBlock(entryLabel, unwindhandler, unwindhandler, null); mv.visitMaxs(maxStack, maxLocals); } }; } }; try { cr.accept(cv, ClassReader.EXPAND_FRAMES); fail(); } catch (Exception e) { } } public void testIllegalTableSwitchParameters1() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitTableSwitchInsn(1, 0, new Label(), new Label[0]); fail(); } catch (Exception e) { } } public void testIllegalTableSwitchParameters2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitTableSwitchInsn(0, 1, null, new Label[0]); fail(); } catch (Exception e) { } } public void testIllegalTableSwitchParameters3() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitTableSwitchInsn(0, 1, new Label(), null); fail(); } catch (Exception e) { } } public void testIllegalTableSwitchParameters4() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitTableSwitchInsn(0, 1, new Label(), new Label[0]); fail(); } catch (Exception e) { } } public void testIllegalLookupSwitchParameters1() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitLookupSwitchInsn(new Label(), null, new Label[0]); fail(); } catch (Exception e) { } } public void testIllegalLookupSwitchParameters2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitLookupSwitchInsn(new Label(), new int[0], null); fail(); } catch (Exception e) { } } public void testIllegalLookupSwitchParameters3() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitLookupSwitchInsn(new Label(), new int[0], new Label[1]); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnNullOwner() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, null, "i", "I"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnOwner() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "-", "i", "I"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnNullName() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", null, "I"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnName() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "-", "I"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnName2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "a-", "I"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnNullDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", null); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnVoidDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", "V"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnPrimitiveDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", "II"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnArrayDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", "["); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnReferenceDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", "L"); fail(); } catch (Exception e) { } } public void testIllegalFieldInsnReferenceDesc2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitFieldInsn(GETFIELD, "C", "i", "L-;"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnNullName() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", null, "()V"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnName() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "-", "()V"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnName2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "a-", "()V"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnNullDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", null); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", "I"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnParameterDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", "(V)V"); fail(); } catch (Exception e) { } } public void testIllegalMethodInsnReturnDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", "()VV"); fail(); } catch (Exception e) { } } public void testIllegalLdcInsnOperand() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitLdcInsn(new Object()); fail(); } catch (Exception e) { } } public void testIllegalMultiANewArrayDesc() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMultiANewArrayInsn("I", 1); fail(); } catch (Exception e) { } } public void testIllegalMultiANewArrayDims() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMultiANewArrayInsn("[[I", 0); fail(); } catch (Exception e) { } } public void testIllegalMultiANewArrayDims2() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitMultiANewArrayInsn("[[I", 3); fail(); } catch (Exception e) { } } public void testIllegalTryCatchBlock() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); Label m = new Label(); Label n = new Label(); mv.visitLabel(m); try { mv.visitTryCatchBlock(m, n, n, null); fail(); } catch (Exception e) { } try { mv.visitTryCatchBlock(n, m, n, null); fail(); } catch (Exception e) { } try { mv.visitTryCatchBlock(n, n, m, null); fail(); } catch (Exception e) { } } public void testIllegalDataflow() { MethodVisitor mv = new CheckMethodAdapter(ACC_PUBLIC, "m", "(I)V", new EmptyVisitor(), new HashMap()); mv.visitCode(); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(IRETURN); mv.visitMaxs(1, 2); try { mv.visitEnd(); fail(); } catch (Exception e) { } } public void testIllegalDataflow2() { MethodVisitor mv = new CheckMethodAdapter(ACC_PUBLIC, "m", "(I)I", new EmptyVisitor(), new HashMap()); mv.visitCode(); mv.visitInsn(RETURN); mv.visitMaxs(0, 2); try { mv.visitEnd(); fail(); } catch (Exception e) { } } public void testIllegalLocalVariableLabels() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); Label m = new Label(); Label n = new Label(); mv.visitLabel(n); mv.visitInsn(NOP); mv.visitLabel(m); try { mv.visitLocalVariable("i", "I", null, m, n, 0); fail(); } catch (Exception e) { } } public void testIllegalLineNumerLabel() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); try { mv.visitLineNumber(0, new Label()); fail(); } catch (Exception e) { } } public void testIllegalInsnVisitAfterEnd() { MethodVisitor mv = new CheckMethodAdapter(new EmptyVisitor()); mv.visitCode(); mv.visitMaxs(0, 0); try { mv.visitInsn(NOP); fail(); } catch (Exception e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/util/CheckSignatureAdapterUnitTest.java0000644000175000017500000001737210664276120027730 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import junit.framework.TestCase; import junit.framework.TestSuite; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.util.TraceSignatureVisitorUnitTest.TestData; /** * CheckSignatureAdapter tests. * * @author Eric Bruneton */ public class CheckSignatureAdapterUnitTest extends TestCase { public static TestSuite suite() { TestSuite suite = new TestSuite(CheckSignatureAdapterUnitTest.class.getName()); for (int i = 0; i < TraceSignatureVisitorUnitTest.DATA.length; i++) { suite.addTest(new CheckSignatureAdapterUnitTest(new TestData(TraceSignatureVisitorUnitTest.DATA[i]))); } suite.addTestSuite(CheckSignatureAdapterUnitTest.class); return suite; } private TestData data; private SignatureVisitor sv; public CheckSignatureAdapterUnitTest() { } private CheckSignatureAdapterUnitTest(final TestData data) { super("checkSignature"); this.data = data; } public void checkSignature() { SignatureWriter wrt = new SignatureWriter(); SignatureReader rdr = new SignatureReader(data.signature); switch (data.type) { case 'C': rdr.accept(new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, wrt)); break; case 'M': rdr.accept(new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, wrt)); break; case 'F': rdr.acceptType(new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, wrt)); break; default: return; } assertEquals(data.signature, wrt.toString()); } public void testIllegalFormalTypeParam() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitFormalTypeParameter("T"); fail(); } catch (Exception e) { } } public void testIllegalClassBound() { setup(CheckSignatureAdapter.CLASS_SIGNATURE); try { sv.visitClassBound(); fail(); } catch (Exception e) { } } public void testIllegalInterfaceBound() { setup(CheckSignatureAdapter.CLASS_SIGNATURE); try { sv.visitInterfaceBound(); fail(); } catch (Exception e) { } } public void testIllegalSuperclass() { setup(CheckSignatureAdapter.METHOD_SIGNATURE); try { sv.visitSuperclass(); fail(); } catch (Exception e) { } } public void testIllegalInterface() { setup(CheckSignatureAdapter.CLASS_SIGNATURE); try { sv.visitInterface(); fail(); } catch (Exception e) { } } public void testIllegalParameterType() { setup(CheckSignatureAdapter.CLASS_SIGNATURE); try { sv.visitParameterType(); fail(); } catch (Exception e) { } } public void testIllegalReturnType() { setup(CheckSignatureAdapter.METHOD_SIGNATURE); try { sv.visitReturnType(); sv.visitReturnType(); fail(); } catch (Exception e) { } } public void testIllegalExceptionType() { setup(CheckSignatureAdapter.METHOD_SIGNATURE); try { sv.visitExceptionType(); fail(); } catch (Exception e) { } } public void testIllegalBaseType() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitBaseType('I'); sv.visitBaseType('I'); fail(); } catch (Exception e) { } setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitBaseType('V'); fail(); } catch (Exception e) { } setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitBaseType('A'); fail(); } catch (Exception e) { } } public void testIllegalTypeVariable() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitTypeVariable("T"); sv.visitTypeVariable("T"); fail(); } catch (Exception e) { } } public void testIllegalArrayType() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitArrayType(); sv.visitArrayType(); fail(); } catch (Exception e) { } } public void testIllegalClassType() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitClassType("A"); sv.visitClassType("A"); fail(); } catch (Exception e) { } } public void testIllegalInnerClassType() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitInnerClassType("A"); fail(); } catch (Exception e) { } } public void testIllegalTypeArgument() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitTypeArgument(); fail(); } catch (Exception e) { } setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitTypeArgument('+'); fail(); } catch (Exception e) { } setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitClassType("A"); sv.visitTypeArgument('*'); fail(); } catch (Exception e) { } } public void testIllegalEnd() { setup(CheckSignatureAdapter.TYPE_SIGNATURE); try { sv.visitEnd(); fail(); } catch (Exception e) { } } public String getName() { if (data == null) { return super.getName(); } else { return super.getName() + " " + data.signature; } } private void setup(int type) { sv = new CheckSignatureAdapter(type, null); } } asm-3.3.2/test/conform/org/objectweb/asm/util/CheckSignatureAdapterTest.java0000644000175000017500000001031510664276120027056 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureWriter; /** * CheckSignatureAdapter tests. * * @author Eric Bruneton */ public class CheckSignatureAdapterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new CheckSignatureAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); cr.accept(new EmptyVisitor() { public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.accept(new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, sw)); assertEquals(signature, sw.toString()); } } public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.acceptType(new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, sw)); assertEquals(signature, sw.toString()); } return null; } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.accept(new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, sw)); assertEquals(signature, sw.toString()); } return null; } }, 0); } } asm-3.3.2/test/conform/org/objectweb/asm/util/TraceClassAdapterTest.java0000644000175000017500000000511310452754520026203 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import java.io.CharArrayWriter; import java.io.PrintWriter; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.attrs.CodeComment; import org.objectweb.asm.attrs.Comment; /** * CheckClassAdapter tests. * * @author Eric Bruneton */ public class TraceClassAdapterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new TraceClassAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(new CharArrayWriter())); cr.accept(cv, new Attribute[] { new Comment(), new CodeComment() }, 0); assertEquals(cr, new ClassReader(cw.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/util/TraceClassAdapterUnitTest.java0000644000175000017500000000424010452754520027043 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.util; import junit.framework.TestCase; /** * TraceClassAdapter unit tests * * @author Eric Bruneton */ public class TraceClassAdapterUnitTest extends TestCase { public void testTraceClassVisitor() throws Exception { String s = getClass().getName(); TraceClassVisitor.main(new String[0]); TraceClassVisitor.main(new String[] { "-debug" }); TraceClassVisitor.main(new String[] { s }); TraceClassVisitor.main(new String[] { "-debug", s }); TraceClassVisitor.main(new String[] { "output/test/cases/Interface.class" }); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/0000755000175000017500000000000011633370175021653 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/commons/RemappingClassAdapterTest2.java0000644000175000017500000000464110635277351027661 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.HashMap; import java.util.Map; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; public class RemappingClassAdapterTest2 extends AbstractTest { public static TestSuite suite() throws Exception { return new RemappingClassAdapterTest2().getSuite(); } public void test() throws Exception { ClassWriter cw = new ClassWriter(0); ClassReader cr = new ClassReader(is); Map map = new HashMap() { public Object get(Object key) { return "Foo"; } }; cr.accept(new RemappingClassAdapter(cw, new SimpleRemapper(map)), ClassReader.EXPAND_FRAMES); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/CodeSizeEvaluatorTest.java0000644000175000017500000000641610452754520026753 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; public class CodeSizeEvaluatorTest extends AbstractTest { public static TestSuite suite() throws Exception { return new CodeSizeEvaluatorTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); cr.accept(new ClassAdapter(new ClassWriter(0)) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); return new CodeSizeEvaluator(mv) { public void visitMaxs( final int maxStack, final int maxLocals) { Label end = new Label(); mv.visitLabel(end); mv.visitMaxs(maxStack, maxLocals); int size = end.getOffset(); assertTrue(getMinSize() + " <= " + size + " <= " + getMaxSize(), getMinSize() <= size && size <= getMaxSize()); } }; } }, 0); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/SerialVersionUIDAdderTest.java0000644000175000017500000000416510452754520027451 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; /** * SerialVerionUIDAdder tests. * * @author Eric Bruneton */ public class SerialVersionUIDAdderTest extends AbstractTest { public static TestSuite suite() throws Exception { return new SerialVersionUIDAdderTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); cr.accept(new SerialVersionUIDAdder(new EmptyVisitor()), 0); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/JSRInlinerAdapterUnitTest.java0000644000175000017500000014120710475035666027511 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestCase; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.util.TraceMethodVisitor; /** * JsrInlinerTest * * @author Eugene Kuleshov, Niko Matsakis, Eric Bruneton */ public class JSRInlinerAdapterUnitTest extends TestCase { private JSRInlinerAdapter jsr; private MethodNode exp; private MethodVisitor current; protected void setUp() throws Exception { super.setUp(); jsr = new JSRInlinerAdapter(null, 0, "m", "()V", null, null) { public void visitEnd() { System.err.println("started w/ method:" + name); TraceMethodVisitor mv = new TraceMethodVisitor(); for (int i = 0; i < instructions.size(); ++i) { instructions.get(i).accept(mv); System.err.print(Integer.toString(i + 100000).substring(1)); System.err.print(" : " + mv.text.get(i)); } super.visitEnd(); System.err.println("finished w/ method:" + name); } }; exp = new MethodNode(0, "m", "()V", null, null); } private void setCurrent(final MethodVisitor cv) { this.current = cv; } private void ICONST_0() { this.current.visitInsn(Opcodes.ICONST_0); } private void ISTORE(final int var) { this.current.visitVarInsn(Opcodes.ISTORE, var); } private void ALOAD(final int var) { this.current.visitVarInsn(Opcodes.ALOAD, var); } private void ILOAD(final int var) { this.current.visitVarInsn(Opcodes.ILOAD, var); } private void ASTORE(final int var) { this.current.visitVarInsn(Opcodes.ASTORE, var); } private void RET(final int var) { this.current.visitVarInsn(Opcodes.RET, var); } private void ATHROW() { this.current.visitInsn(Opcodes.ATHROW); } private void ACONST_NULL() { this.current.visitInsn(Opcodes.ACONST_NULL); } private void RETURN() { this.current.visitInsn(Opcodes.RETURN); } private void LABEL(final Label l) { this.current.visitLabel(l); } private void IINC(final int var, final int amnt) { this.current.visitIincInsn(var, amnt); } private void GOTO(final Label l) { this.current.visitJumpInsn(Opcodes.GOTO, l); } private void JSR(final Label l) { this.current.visitJumpInsn(Opcodes.JSR, l); } private void IFNONNULL(final Label l) { this.current.visitJumpInsn(Opcodes.IFNONNULL, l); } private void IFNE(final Label l) { this.current.visitJumpInsn(Opcodes.IFNE, l); } private void TRYCATCH( final Label start, final Label end, final Label handler) { this.current.visitTryCatchBlock(start, end, handler, null); } private void LINE(final int line, final Label start) { this.current.visitLineNumber(line, start); } private void LOCALVAR( final String name, final String desc, final int index, final Label start, final Label end) { this.current.visitLocalVariable(name, desc, null, start, end, index); } private void END(final int maxStack, final int maxLocals) { this.current.visitMaxs(maxStack, maxLocals); this.current.visitEnd(); ClassWriter cw = new ClassWriter(0); cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); ((MethodNode) this.current).accept(cw); cw.visitEnd(); byte[] b = cw.toByteArray(); try { TestClassLoader loader = new TestClassLoader(); Class c = loader.defineClass("C", b); c.newInstance(); } catch (Throwable t) { fail(t.getMessage()); } this.current = null; } static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } /** * Tests a method which has the most basic try{}finally form * imaginable: * *

     *   public void a() {
     *     int a = 0;
     *     try {
     *       a++;
     *     } finally {
     *       a--;
     *     }
     *   }
     * 
*/ public void testBasic() { { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); /* L0: body of try block */ LABEL(L0); IINC(1, 1); GOTO(L1); /* L2: exception handler */ LABEL(L2); ASTORE(3); JSR(L3); ALOAD(3); ATHROW(); /* L3: subroutine */ LABEL(L3); ASTORE(2); IINC(1, -1); RET(2); /* L1: non-exceptional exit from try block */ LABEL(L1); JSR(L3); LABEL(L4); // L4 RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L4, L2); END(1, 4); } { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3_1a = new Label(); Label L3_1b = new Label(); Label L3_2a = new Label(); Label L3_2b = new Label(); Label L4 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // L0: try/catch block LABEL(L0); IINC(1, 1); GOTO(L1); // L2: Exception handler: LABEL(L2); ASTORE(3); ACONST_NULL(); GOTO(L3_1a); LABEL(L3_1b); // L3_1b; ALOAD(3); ATHROW(); // L1: On non-exceptional exit, try block leads here: LABEL(L1); ACONST_NULL(); GOTO(L3_2a); LABEL(L3_2b); // L3_2b LABEL(L4); // L4 RETURN(); // L3_1a: First instantiation of subroutine: LABEL(L3_1a); ASTORE(2); IINC(1, -1); GOTO(L3_1b); LABEL(new Label()); // extra label emitted due to impl quirks // L3_2a: Second instantiation of subroutine: LABEL(L3_2a); ASTORE(2); IINC(1, -1); GOTO(L3_2b); LABEL(new Label()); // extra label emitted due to impl quirks TRYCATCH(L0, L2, L2); TRYCATCH(L1, L4, L2); END(1, 4); } assertEquals(exp, jsr); } /** * Tests a method which has an if/else-if w/in the finally clause: * *
     *   public void a() {
     *     int a = 0;
     *     try {
     *       a++;
     *     } finally {
     *       if (a == 0)
     *         a+=2;
     *       else
     *         a+=3;
     *     }
     *   }
     * 
*/ public void testIfElseInFinally() { { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); Label L6 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); /* L0: body of try block */ LABEL(L0); IINC(1, 1); GOTO(L1); /* L2: exception handler */ LABEL(L2); ASTORE(3); JSR(L3); ALOAD(3); ATHROW(); /* L3: subroutine */ LABEL(L3); ASTORE(2); ILOAD(1); IFNE(L4); IINC(1, 2); GOTO(L5); LABEL(L4); // L4: a != 0 IINC(1, 3); LABEL(L5); // L5: common exit RET(2); /* L1: non-exceptional exit from try block */ LABEL(L1); JSR(L3); LABEL(L6); // L6 is used in the TRYCATCH below RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L6, L2); END(1, 4); } { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3_1a = new Label(); Label L3_1b = new Label(); Label L3_2a = new Label(); Label L3_2b = new Label(); Label L4_1 = new Label(); Label L4_2 = new Label(); Label L5_1 = new Label(); Label L5_2 = new Label(); Label L6 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // L0: try/catch block LABEL(L0); IINC(1, 1); GOTO(L1); // L2: Exception handler: LABEL(L2); ASTORE(3); ACONST_NULL(); GOTO(L3_1a); LABEL(L3_1b); // L3_1b; ALOAD(3); ATHROW(); // L1: On non-exceptional exit, try block leads here: LABEL(L1); ACONST_NULL(); GOTO(L3_2a); LABEL(L3_2b); // L3_2b LABEL(L6); // L6 RETURN(); // L3_1a: First instantiation of subroutine: LABEL(L3_1a); ASTORE(2); ILOAD(1); IFNE(L4_1); IINC(1, 2); GOTO(L5_1); LABEL(L4_1); // L4_1: a != 0 IINC(1, 3); LABEL(L5_1); // L5_1: common exit GOTO(L3_1b); LABEL(new Label()); // extra label emitted due to impl quirks // L3_2a: First instantiation of subroutine: LABEL(L3_2a); ASTORE(2); ILOAD(1); IFNE(L4_2); IINC(1, 2); GOTO(L5_2); LABEL(L4_2); // L4_2: a != 0 IINC(1, 3); LABEL(L5_2); // L5_2: common exit GOTO(L3_2b); LABEL(new Label()); // extra label emitted due to impl quirks TRYCATCH(L0, L2, L2); TRYCATCH(L1, L6, L2); END(1, 4); } assertEquals(exp, jsr); } /** * Tests a simple nested finally: * *
     * public void a1() {
     *   int a = 0;
     *   try {
     *     a += 1;
     *   } finally {
     *     try {
     *       a += 2;
     *     } finally {
     *       a += 3;
     *     }
     *   }
     * }
     * 
*/ public void testSimpleNestedFinally() { { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); // L0: Body of try block: LABEL(L0); IINC(1, 1); JSR(L3); GOTO(L1); // L2: First exception handler: LABEL(L2); JSR(L3); ATHROW(); // L3: First subroutine: LABEL(L3); ASTORE(2); IINC(1, 2); JSR(L4); RET(2); // L5: Second exception handler: LABEL(L5); JSR(L4); ATHROW(); // L4: Second subroutine: LABEL(L4); ASTORE(3); IINC(1, 3); RET(3); // L1: On normal exit, try block jumps here: LABEL(L1); RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L3, L5, L5); END(2, 6); } { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3_1a = new Label(); Label L3_1b = new Label(); Label L3_2a = new Label(); Label L3_2b = new Label(); Label L4_1a = new Label(); Label L4_1b = new Label(); Label L4_2a = new Label(); Label L4_2b = new Label(); Label L4_3a = new Label(); Label L4_3b = new Label(); Label L4_4a = new Label(); Label L4_4b = new Label(); Label L5_1 = new Label(); Label L5_2 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // L0: Body of try block: LABEL(L0); IINC(1, 1); ACONST_NULL(); GOTO(L3_1a); LABEL(L3_1b); // L3_1b GOTO(L1); // L2: First exception handler: LABEL(L2); ACONST_NULL(); GOTO(L3_2a); LABEL(L3_2b); // L3_2b ATHROW(); // L1: On normal exit, try block jumps here: LABEL(L1); RETURN(); // L3_1a: First instantiation of first subroutine: LABEL(L3_1a); ASTORE(2); IINC(1, 2); ACONST_NULL(); GOTO(L4_1a); LABEL(L4_1b); // L4_1b GOTO(L3_1b); LABEL(L5_1); // L5_1 ACONST_NULL(); GOTO(L4_2a); LABEL(L4_2b); // L4_2b ATHROW(); LABEL(new Label()); // extra label emitted due to impl quirks // L3_2a: Second instantiation of first subroutine: LABEL(L3_2a); ASTORE(2); IINC(1, 2); ACONST_NULL(); GOTO(L4_3a); LABEL(L4_3b); // L4_3b GOTO(L3_2b); LABEL(L5_2); // L5_2 ACONST_NULL(); GOTO(L4_4a); LABEL(L4_4b); // L4_4b ATHROW(); LABEL(new Label()); // extra label emitted due to impl quirks // L4_1a: First instantiation of second subroutine: LABEL(L4_1a); ASTORE(3); IINC(1, 3); GOTO(L4_1b); LABEL(new Label()); // extra label emitted due to impl quirks // L4_2a: Second instantiation of second subroutine: LABEL(L4_2a); ASTORE(3); IINC(1, 3); GOTO(L4_2b); LABEL(new Label()); // extra label emitted due to impl quirks // L4_3a: Third instantiation of second subroutine: LABEL(L4_3a); ASTORE(3); IINC(1, 3); GOTO(L4_3b); LABEL(new Label()); // extra label emitted due to impl quirks // L4_4a: Fourth instantiation of second subroutine: LABEL(L4_4a); ASTORE(3); IINC(1, 3); GOTO(L4_4b); LABEL(new Label()); // extra label emitted due to impl quirks TRYCATCH(L0, L2, L2); TRYCATCH(L3_1a, L5_1, L5_1); TRYCATCH(L3_2a, L5_2, L5_2); END(2, 6); } assertEquals(exp, jsr); } /** * This tests a subroutine which has no ret statement, but ends in a * "return" instead. * * We structure this as a try/finally with a break in the finally. Because * the while loop is infinite, it's clear from the byte code that the only * path which reaches the RETURN instruction is through the subroutine. * *
     * public void a1() {
     *   int a = 0;
     *   while (true) {
     *     try {
     *       a += 1;
     *     } finally {
     *       a += 2;
     *       break;
     *     }
     *   }
     * }
     * 
*/ public void testSubroutineWithNoRet() { { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); // L0: while loop header/try block LABEL(L0); IINC(1, 1); JSR(L1); GOTO(L2); // L3: implicit catch block LABEL(L3); ASTORE(2); JSR(L1); ALOAD(2); ATHROW(); // L1: subroutine ... LABEL(L1); ASTORE(3); IINC(1, 2); GOTO(L4); // ...not that it does not return! // L2: end of the loop... goes back to the top! LABEL(L2); GOTO(L0); // L4: LABEL(L4); RETURN(); TRYCATCH(L0, L3, L3); END(1, 4); } { Label L0 = new Label(); Label L1_1a = new Label(); Label L1_1b = new Label(); Label L1_2a = new Label(); Label L1_2b = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4_1 = new Label(); Label L4_2 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // L0: while loop header/try block LABEL(L0); IINC(1, 1); ACONST_NULL(); GOTO(L1_1a); LABEL(L1_1b); // L1_1b GOTO(L2); // L3: implicit catch block LABEL(L3); ASTORE(2); ACONST_NULL(); GOTO(L1_2a); LABEL(L1_2b); // L1_2b ALOAD(2); ATHROW(); // L2: end of the loop... goes back to the top! LABEL(L2); GOTO(L0); LABEL(new Label()); // extra label emitted due to impl quirks // L1_1a: first instantiation of subroutine ... LABEL(L1_1a); ASTORE(3); IINC(1, 2); GOTO(L4_1); // ...not that it does not return! LABEL(L4_1); RETURN(); // L1_2a: second instantiation of subroutine ... LABEL(L1_2a); ASTORE(3); IINC(1, 2); GOTO(L4_2); // ...not that it does not return! LABEL(L4_2); RETURN(); TRYCATCH(L0, L3, L3); END(1, 4); } assertEquals(exp, jsr); } /** * This tests a subroutine which has no ret statement, but ends in a * "return" instead. * *
     *   JSR L0
     * L0:
     *   ASTORE 0 
     *   RETURN 
     * 
*/ public void testSubroutineWithNoRet2() { { Label L0 = new Label(); setCurrent(jsr); JSR(L0); LABEL(L0); ASTORE(0); RETURN(); END(1, 1); } { Label L0_1a = new Label(); Label L0_1b = new Label(); setCurrent(exp); ACONST_NULL(); GOTO(L0_1a); LABEL(L0_1b); // L0_1a: First instantiation of subroutine: LABEL(L0_1a); ASTORE(0); RETURN(); LABEL(new Label()); // extra label emitted due to impl quirks END(1, 1); } assertEquals(exp, jsr); } /** * This tests a subroutine which has no ret statement, but instead exits * implicitely by branching to code which is not part of the subroutine. * (Sadly, this is legal) * * We structure this as a try/finally in a loop with a break in the finally. * The loop is not trivially infinite, so the RETURN statement is reachable * both from the JSR subroutine and from the main entry point. * *
     * public void a1() {
     *   int a = 0;
     *   while (null == null) {
     *     try {
     *       a += 1;
     *     } finally {
     *       a += 2;
     *       break;
     *     }
     *   }
     * }
     * 
*/ public void testImplicitExit() { { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); // L5: while loop header LABEL(L5); ACONST_NULL(); IFNONNULL(L4); // L0: try block LABEL(L0); IINC(1, 1); JSR(L1); GOTO(L2); // L3: implicit catch block LABEL(L3); ASTORE(2); JSR(L1); ALOAD(2); ATHROW(); // L1: subroutine ... LABEL(L1); ASTORE(3); IINC(1, 2); GOTO(L4); // ...not that it does not return! // L2: end of the loop... goes back to the top! LABEL(L2); GOTO(L0); // L4: LABEL(L4); RETURN(); TRYCATCH(L0, L3, L3); END(1, 4); } { Label L0 = new Label(); Label L1_1a = new Label(); Label L1_1b = new Label(); Label L1_2a = new Label(); Label L1_2b = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // L5: while loop header LABEL(L5); ACONST_NULL(); IFNONNULL(L4); // L0: while loop header/try block LABEL(L0); IINC(1, 1); ACONST_NULL(); GOTO(L1_1a); LABEL(L1_1b); // L1_1b GOTO(L2); // L3: implicit catch block LABEL(L3); ASTORE(2); ACONST_NULL(); GOTO(L1_2a); LABEL(L1_2b); // L1_2b ALOAD(2); ATHROW(); // L2: end of the loop... goes back to the top! LABEL(L2); GOTO(L0); // L4: exit, not part of subroutine // Note that the two subroutine instantiations branch here LABEL(L4); RETURN(); // L1_1a: first instantiation of subroutine ... LABEL(L1_1a); ASTORE(3); IINC(1, 2); GOTO(L4); // ...note that it does not return! LABEL(new Label()); // extra label emitted due to impl quirks // L1_2a: second instantiation of subroutine ... LABEL(L1_2a); ASTORE(3); IINC(1, 2); GOTO(L4); // ...note that it does not return! LABEL(new Label()); // extra label emitted due to impl quirks TRYCATCH(L0, L3, L3); END(1, 4); } assertEquals(exp, jsr); } /** * Tests a nested try/finally with implicit exit from one subroutine to the * other subroutine. Equivalent to the following java code: * *
     * void m(boolean b) {
     *   try {
     *     return;
     *   } finally {
     *     while (b) {
     *       try {
     *         return;
     *       } finally {
     *         // NOTE --- this break avoids the second return above (weird)
     *         if (b) break;
     *       }
     *     }
     *   }
     * }
     * 
* * This example is from the paper, "Subroutine Inlining and Bytecode * Abstraction to Simplify Static and Dynamic Analysis" by Cyrille Artho and * Armin Biere. */ public void testImplicitExitToAnotherSubroutine() { { Label T1 = new Label(); Label C1 = new Label(); Label S1 = new Label(); Label L = new Label(); Label C2 = new Label(); Label S2 = new Label(); Label W = new Label(); Label X = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; setCurrent(jsr); ICONST_0(); ISTORE(1); // T1: first try: LABEL(T1); JSR(S1); RETURN(); // C1: exception handler for first try LABEL(C1); ASTORE(e1); JSR(S1); ALOAD(e1); ATHROW(); // S1: first finally handler LABEL(S1); ASTORE(r1); GOTO(W); // L: body of while loop, also second try LABEL(L); JSR(S2); RETURN(); // C2: exception handler for second try LABEL(C2); ASTORE(e2); JSR(S2); ALOAD(e2); ATHROW(); // S2: second finally handler LABEL(S2); ASTORE(r2); ILOAD(b); IFNE(X); RET(r2); // W: test for the while loop LABEL(W); ILOAD(b); IFNE(L); // falls through to X // X: exit from finally{} block LABEL(X); RET(r1); TRYCATCH(T1, C1, C1); TRYCATCH(L, C2, C2); END(1, 6); } { Label T1 = new Label(); Label C1 = new Label(); Label S1_1a = new Label(); Label S1_1b = new Label(); Label S1_2a = new Label(); Label S1_2b = new Label(); Label L_1 = new Label(); Label L_2 = new Label(); Label C2_1 = new Label(); Label C2_2 = new Label(); Label S2_1_1a = new Label(); Label S2_1_1b = new Label(); Label S2_1_2a = new Label(); Label S2_1_2b = new Label(); Label S2_2_1a = new Label(); Label S2_2_1b = new Label(); Label S2_2_2a = new Label(); Label S2_2_2b = new Label(); Label W_1 = new Label(); Label W_2 = new Label(); Label X_1 = new Label(); Label X_2 = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; setCurrent(exp); // --- Main Subroutine --- ICONST_0(); ISTORE(1); // T1: first try: LABEL(T1); ACONST_NULL(); GOTO(S1_1a); LABEL(S1_1b); RETURN(); // C1: exception handler for first try LABEL(C1); ASTORE(e1); ACONST_NULL(); GOTO(S1_2a); LABEL(S1_2b); ALOAD(e1); ATHROW(); LABEL(new Label()); // extra label emitted due to impl quirks // --- First instantiation of first subroutine --- // S1: first finally handler LABEL(S1_1a); ASTORE(r1); GOTO(W_1); // L_1: body of while loop, also second try LABEL(L_1); ACONST_NULL(); GOTO(S2_1_1a); LABEL(S2_1_1b); RETURN(); // C2_1: exception handler for second try LABEL(C2_1); ASTORE(e2); ACONST_NULL(); GOTO(S2_1_2a); LABEL(S2_1_2b); ALOAD(e2); ATHROW(); // W_1: test for the while loop LABEL(W_1); ILOAD(b); IFNE(L_1); // falls through to X_1 // X_1: exit from finally{} block LABEL(X_1); GOTO(S1_1b); // --- Second instantiation of first subroutine --- // S1: first finally handler LABEL(S1_2a); ASTORE(r1); GOTO(W_2); // L_2: body of while loop, also second try LABEL(L_2); ACONST_NULL(); GOTO(S2_2_1a); LABEL(S2_2_1b); RETURN(); // C2_2: exception handler for second try LABEL(C2_2); ASTORE(e2); ACONST_NULL(); GOTO(S2_2_2a); LABEL(S2_2_2b); ALOAD(e2); ATHROW(); // W_2: test for the while loop LABEL(W_2); ILOAD(b); IFNE(L_2); // falls through to X_2 // X_2: exit from finally{} block LABEL(X_2); GOTO(S1_2b); // --- Second subroutine's 4 instantiations --- // S2_1_1a: LABEL(S2_1_1a); ASTORE(r2); ILOAD(b); IFNE(X_1); GOTO(S2_1_1b); LABEL(new Label()); // extra label emitted due to impl quirks // S2_1_2a: LABEL(S2_1_2a); ASTORE(r2); ILOAD(b); IFNE(X_1); GOTO(S2_1_2b); LABEL(new Label()); // extra label emitted due to impl quirks // S2_2_1a: LABEL(S2_2_1a); ASTORE(r2); ILOAD(b); IFNE(X_2); GOTO(S2_2_1b); LABEL(new Label()); // extra label emitted due to impl quirks // S2_2_2a: LABEL(S2_2_2a); ASTORE(r2); ILOAD(b); IFNE(X_2); GOTO(S2_2_2b); LABEL(new Label()); // extra label emitted due to impl quirks TRYCATCH(T1, C1, C1); TRYCATCH(L_1, C2_1, C2_1); // duplicated try/finally for each... TRYCATCH(L_2, C2_2, C2_2); // ...instantiation of first sub END(1, 6); } assertEquals(exp, jsr); } /** * This tests two subroutines, neither of which exit. Instead, they both * branch to a common set of code which returns from the method. This code * is not reachable except through these subroutines, and since they do not * invoke each other, it must be copied into both of them. * * I don't believe this can be represented in Java. */ public void testCommonCodeWhichMustBeDuplicated() { { Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); // Invoke the two subroutines, each twice: JSR(L1); JSR(L1); JSR(L2); JSR(L2); RETURN(); // L1: subroutine 1 LABEL(L1); IINC(1, 1); GOTO(L3); // ...note that it does not return! // L2: subroutine 2 LABEL(L2); IINC(1, 2); GOTO(L3); // ...note that it does not return! // L3: common code to both subroutines: exit method LABEL(L3); RETURN(); END(1, 2); } { Label L1_1a = new Label(); Label L1_1b = new Label(); Label L1_2a = new Label(); Label L1_2b = new Label(); Label L2_1a = new Label(); Label L2_1b = new Label(); Label L2_2a = new Label(); Label L2_2b = new Label(); Label L3_1 = new Label(); Label L3_2 = new Label(); Label L3_3 = new Label(); Label L3_4 = new Label(); setCurrent(exp); ICONST_0(); ISTORE(1); // Invoke the two subroutines, each twice: ACONST_NULL(); GOTO(L1_1a); LABEL(L1_1b); ACONST_NULL(); GOTO(L1_2a); LABEL(L1_2b); ACONST_NULL(); GOTO(L2_1a); LABEL(L2_1b); ACONST_NULL(); GOTO(L2_2a); LABEL(L2_2b); RETURN(); LABEL(new Label()); // extra label emitted due to impl quirks // L1_1a: instantiation 1 of subroutine 1 LABEL(L1_1a); IINC(1, 1); GOTO(L3_1); // ...note that it does not return! LABEL(L3_1); RETURN(); // L1_2a: instantiation 2 of subroutine 1 LABEL(L1_2a); IINC(1, 1); GOTO(L3_2); // ...note that it does not return! LABEL(L3_2); RETURN(); // L2_1a: instantiation 1 of subroutine 2 LABEL(L2_1a); IINC(1, 2); GOTO(L3_3); // ...note that it does not return! LABEL(L3_3); RETURN(); // L2_2a: instantiation 2 of subroutine 2 LABEL(L2_2a); IINC(1, 2); GOTO(L3_4); // ...note that it does not return! LABEL(L3_4); RETURN(); END(1, 2); } assertEquals(exp, jsr); } /** * This tests a simple subroutine where the control flow jumps back and * forth between the subroutine and the caller. * * This would not normally be produced by a java compiler. */ public void testInterleavedCode() { { Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); setCurrent(jsr); ICONST_0(); ISTORE(1); // Invoke the subroutine, each twice: JSR(L1); GOTO(L2); // L1: subroutine 1 LABEL(L1); ASTORE(2); IINC(1, 1); GOTO(L3); // L2: second part of main subroutine LABEL(L2); IINC(1, 2); GOTO(L4); // L3: second part of subroutine 1 LABEL(L3); IINC(1, 4); RET(2); // L4: third part of main subroutine LABEL(L4); JSR(L1); RETURN(); END(1, 3); } { Label L1_1a = new Label(); Label L1_1b = new Label(); Label L1_2a = new Label(); Label L1_2b = new Label(); Label L2 = new Label(); Label L3_1 = new Label(); Label L3_2 = new Label(); Label L4 = new Label(); setCurrent(exp); // Main routine: ICONST_0(); ISTORE(1); ACONST_NULL(); GOTO(L1_1a); LABEL(L1_1b); GOTO(L2); LABEL(L2); IINC(1, 2); GOTO(L4); LABEL(L4); ACONST_NULL(); GOTO(L1_2a); LABEL(L1_2b); RETURN(); // L1_1: instantiation #1 LABEL(L1_1a); ASTORE(2); IINC(1, 1); GOTO(L3_1); LABEL(L3_1); IINC(1, 4); GOTO(L1_1b); LABEL(new Label()); // extra label emitted due to impl quirks // L1_2: instantiation #2 LABEL(L1_2a); ASTORE(2); IINC(1, 1); GOTO(L3_2); LABEL(L3_2); IINC(1, 4); GOTO(L1_2b); LABEL(new Label()); // extra label emitted due to impl quirks END(1, 3); } assertEquals(exp, jsr); } /** * Tests a nested try/finally with implicit exit from one subroutine to the * other subroutine, and with a surrounding try/catch thrown in the mix. * Equivalent to the following java code: * *
     * void m(int b) {
     *   try {
     *     try {
     *       return;
     *     } finally {
     *       while (b) {
     *         try {
     *           return;
     *         } finally {
     *           // NOTE --- this break avoids the second return above (weird)
     *           if (b) break;
     *         }
     *       }
     *     } 
     *   } catch (Exception e) {
     *     b += 3;
     *     return;
     *   }
     * }
     * 
*/ public void testImplicitExitInTryCatch() { { Label T1 = new Label(); Label C1 = new Label(); Label S1 = new Label(); Label L = new Label(); Label C2 = new Label(); Label S2 = new Label(); Label W = new Label(); Label X = new Label(); Label OT = new Label(); Label OC = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; setCurrent(jsr); ICONST_0(); ISTORE(1); // OT: outermost try LABEL(OT); // T1: first try: LABEL(T1); JSR(S1); RETURN(); // C1: exception handler for first try LABEL(C1); ASTORE(e1); JSR(S1); ALOAD(e1); ATHROW(); // S1: first finally handler LABEL(S1); ASTORE(r1); GOTO(W); // L: body of while loop, also second try LABEL(L); JSR(S2); RETURN(); // C2: exception handler for second try LABEL(C2); ASTORE(e2); JSR(S2); ALOAD(e2); ATHROW(); // S2: second finally handler LABEL(S2); ASTORE(r2); ILOAD(b); IFNE(X); RET(r2); // W: test for the while loop LABEL(W); ILOAD(b); IFNE(L); // falls through to X // X: exit from finally{} block LABEL(X); RET(r1); // OC: outermost catch LABEL(OC); IINC(b, 3); RETURN(); TRYCATCH(T1, C1, C1); TRYCATCH(L, C2, C2); TRYCATCH(OT, OC, OC); END(1, 6); } { Label T1 = new Label(); Label C1 = new Label(); Label S1_1a = new Label(); Label S1_1b = new Label(); Label S1_2a = new Label(); Label S1_2b = new Label(); Label L_1 = new Label(); Label L_2 = new Label(); Label C2_1 = new Label(); Label C2_2 = new Label(); Label S2_1_1a = new Label(); Label S2_1_1b = new Label(); Label S2_1_2a = new Label(); Label S2_1_2b = new Label(); Label S2_2_1a = new Label(); Label S2_2_1b = new Label(); Label S2_2_2a = new Label(); Label S2_2_2b = new Label(); Label W_1 = new Label(); Label W_2 = new Label(); Label X_1 = new Label(); Label X_2 = new Label(); Label OT_1 = S1_1a; Label OT_2 = S1_2a; Label OT_1_1 = S2_1_1a; Label OT_1_2 = S2_1_2a; Label OT_2_1 = S2_2_1a; Label OT_2_2 = S2_2_2a; Label OC = new Label(); Label OC_1 = new Label(); Label OC_2 = new Label(); Label OC_1_1 = new Label(); Label OC_1_2 = new Label(); Label OC_2_1 = new Label(); Label OC_2_2 = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; setCurrent(exp); // --- Main Subroutine --- ICONST_0(); ISTORE(1); // T1: outermost try / first try: LABEL(T1); ACONST_NULL(); GOTO(S1_1a); LABEL(S1_1b); RETURN(); // C1: exception handler for first try LABEL(C1); ASTORE(e1); ACONST_NULL(); GOTO(S1_2a); LABEL(S1_2b); ALOAD(e1); ATHROW(); // OC: Outermost catch LABEL(OC); IINC(b, 3); RETURN(); // --- First instantiation of first subroutine --- // S1: first finally handler LABEL(S1_1a); ASTORE(r1); GOTO(W_1); // L_1: body of while loop, also second try LABEL(L_1); ACONST_NULL(); GOTO(S2_1_1a); LABEL(S2_1_1b); RETURN(); // C2_1: exception handler for second try LABEL(C2_1); ASTORE(e2); ACONST_NULL(); GOTO(S2_1_2a); LABEL(S2_1_2b); ALOAD(e2); ATHROW(); // W_1: test for the while loop LABEL(W_1); ILOAD(b); IFNE(L_1); // falls through to X_1 // X_1: exit from finally{} block LABEL(X_1); GOTO(S1_1b); LABEL(OC_1); // --- Second instantiation of first subroutine --- // S1: first finally handler LABEL(S1_2a); ASTORE(r1); GOTO(W_2); // L_2: body of while loop, also second try LABEL(L_2); ACONST_NULL(); GOTO(S2_2_1a); LABEL(S2_2_1b); RETURN(); // C2_2: exception handler for second try LABEL(C2_2); ASTORE(e2); ACONST_NULL(); GOTO(S2_2_2a); LABEL(S2_2_2b); ALOAD(e2); ATHROW(); // W_2: test for the while loop LABEL(W_2); ILOAD(b); IFNE(L_2); // falls through to X_2 // X_2: exit from finally{} block LABEL(X_2); GOTO(S1_2b); LABEL(OC_2); // --- Second subroutine's 4 instantiations --- // S2_1_1a: LABEL(S2_1_1a); ASTORE(r2); ILOAD(b); IFNE(X_1); GOTO(S2_1_1b); LABEL(OC_1_1); // S2_1_2a: LABEL(S2_1_2a); ASTORE(r2); ILOAD(b); IFNE(X_1); GOTO(S2_1_2b); LABEL(OC_1_2); // S2_2_1a: LABEL(S2_2_1a); ASTORE(r2); ILOAD(b); IFNE(X_2); GOTO(S2_2_1b); LABEL(OC_2_1); // S2_2_2a: LABEL(S2_2_2a); ASTORE(r2); ILOAD(b); IFNE(X_2); GOTO(S2_2_2b); LABEL(OC_2_2); // main subroutine handlers: TRYCATCH(T1, C1, C1); TRYCATCH(T1, OC, OC); // first instance of first sub try/catch handlers: TRYCATCH(L_1, C2_1, C2_1); TRYCATCH(OT_1, OC_1, OC); // note: reuses handler code from main // sub // second instance of first sub try/catch handlers: TRYCATCH(L_2, C2_2, C2_2); TRYCATCH(OT_2, OC_2, OC); // all 4 instances of second sub: TRYCATCH(OT_1_1, OC_1_1, OC); TRYCATCH(OT_1_2, OC_1_2, OC); TRYCATCH(OT_2_1, OC_2_1, OC); TRYCATCH(OT_2_2, OC_2_2, OC); END(1, 6); } assertEquals(exp, jsr); } /** * Tests a method which has line numbers and local variable declarations. * *
     *   public void a() {
     * 1    int a = 0;
     * 2    try {
     * 3      a++;
     * 4    } finally {
     * 5      a--;
     * 6    }
     *   }
     *   LV "a" from 1 to 6
     * 
*/ public void testBasicLineNumberAndLocalVars() { { Label LM1 = new Label(); Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); setCurrent(jsr); LABEL(LM1); LINE(1, LM1); ICONST_0(); ISTORE(1); /* L0: body of try block */ LABEL(L0); LINE(3, L0); IINC(1, 1); GOTO(L1); /* L2: exception handler */ LABEL(L2); ASTORE(3); JSR(L3); ALOAD(3); ATHROW(); /* L3: subroutine */ LABEL(L3); LINE(5, L3); ASTORE(2); IINC(1, -1); RET(2); /* L1: non-exceptional exit from try block */ LABEL(L1); JSR(L3); LABEL(L4); // L4 RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L4, L2); LOCALVAR("a", "I", 1, LM1, L4); END(1, 4); } { Label LM1 = new Label(); Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3_1a = new Label(); Label L3_1b = new Label(); Label L3_1c = new Label(); Label L3_2a = new Label(); Label L3_2b = new Label(); Label L3_2c = new Label(); Label L4 = new Label(); setCurrent(exp); LABEL(LM1); LINE(1, LM1); ICONST_0(); ISTORE(1); // L0: try/catch block LABEL(L0); LINE(3, L0); IINC(1, 1); GOTO(L1); // L2: Exception handler: LABEL(L2); ASTORE(3); ACONST_NULL(); GOTO(L3_1a); LABEL(L3_1b); // L3_1b; ALOAD(3); ATHROW(); // L1: On non-exceptional exit, try block leads here: LABEL(L1); ACONST_NULL(); GOTO(L3_2a); LABEL(L3_2b); // L3_2b LABEL(L4); // L4 RETURN(); // L3_1a: First instantiation of subroutine: LABEL(L3_1a); LINE(5, L3_1a); ASTORE(2); IINC(1, -1); GOTO(L3_1b); LABEL(L3_1c); // L3_2a: Second instantiation of subroutine: LABEL(L3_2a); LINE(5, L3_2a); ASTORE(2); IINC(1, -1); GOTO(L3_2b); LABEL(L3_2c); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L4, L2); LOCALVAR("a", "I", 1, LM1, L4); LOCALVAR("a", "I", 1, L3_1a, L3_1c); LOCALVAR("a", "I", 1, L3_2a, L3_2c); END(1, 4); } assertEquals(exp, jsr); } public void assertEquals(final MethodNode exp, final MethodNode actual) { String textexp = getText(exp); String textact = getText(actual); System.err.println("Expected=" + textexp); System.err.println("Actual=" + textact); assertEquals(textexp, textact); } private String getText(final MethodNode mn) { TraceMethodVisitor tmv = new TraceMethodVisitor(null); mn.accept(tmv); StringBuffer sb = new StringBuffer(); for (int i = 0; i < tmv.text.size(); i++) { sb.append(tmv.text.get(i)); } return sb.toString(); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/JSRInlinerAdapterTest.java0000644000175000017500000000671110452754520026641 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; /** * JSRInliner tests. * * @author Eric Bruneton */ public class JSRInlinerAdapterTest extends AbstractTest { private final static TestClassLoader LOADER = new TestClassLoader(); public static TestSuite suite() throws Exception { return new JSRInlinerAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); cr.accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return new JSRInlinerAdapter(mv, access, name, desc, signature, exceptions); } }, 0); byte[] b = cw.toByteArray(); try { LOADER.defineClass(n, b); } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (Throwable ignored) { } } // ------------------------------------------------------------------------ static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/GASMifierClassVisitor.java0000644000175000017500000001261210635277351026637 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.FileInputStream; import java.io.PrintWriter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.util.ASMifierClassVisitor; /** * Sub class of the ASMifier class visitor used to test GeneratorAdapter. * * @author Eric Bruneton */ public class GASMifierClassVisitor extends ASMifierClassVisitor { /** * Prints the ASM source code to generate the given class to the standard * output.

Usage: ASMifierClassVisitor [-debug] <fully qualified * class name or class file name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main(final String[] args) throws Exception { int i = 0; int flags = ClassReader.SKIP_DEBUG; boolean ok = true; if (args.length < 1 || args.length > 2) { ok = false; } if (ok && args[0].equals("-debug")) { i = 1; flags = 0; if (args.length != 2) { ok = false; } } if (!ok) { System.err.println("Prints the ASM code to generate the given class."); System.err.println("Usage: GASMifierClassVisitor [-debug] " + ""); System.exit(-1); } ClassReader cr; if (args[i].endsWith(".class")) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new GASMifierClassVisitor(new PrintWriter(System.out)), getDefaultAttributes(), ClassReader.EXPAND_FRAMES | flags); } public GASMifierClassVisitor(final PrintWriter pw) { super(pw); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); int n; if (name.lastIndexOf('/') != -1) { n = 1; } else { n = 0; } text.set(n + 5, "ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);\n"); text.set(n + 7, "GeneratorAdapter mg;\n"); text.add(n + 1, "import org.objectweb.asm.commons.*;\n"); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append("{\n"); buf.append("mg = new GeneratorAdapter("); buf.append(access); buf.append(", "); buf.append(GASMifierMethodVisitor.getMethod(name, desc)); buf.append(", "); if (signature == null) { buf.append("null"); } else { buf.append('"').append(signature).append('"'); } buf.append(", "); if (exceptions != null && exceptions.length > 0) { buf.append("new Type[] {"); for (int i = 0; i < exceptions.length; ++i) { buf.append(i == 0 ? " " : ", "); buf.append(GASMifierMethodVisitor.getType(exceptions[i])); } buf.append(" }"); } else { buf.append("null"); } buf.append(", cw);\n"); text.add(buf.toString()); GASMifierMethodVisitor acv = new GASMifierMethodVisitor(access, desc); text.add(acv.getText()); text.add("}\n"); return new LocalVariablesSorter(access, desc, acv); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/LocalVariablesSorterTest2.java0000644000175000017500000001216411224532001027506 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.util.TraceClassVisitor; /** * LocalVariablesSorter tests. * * @author Eric Bruneton */ public class LocalVariablesSorterTest2 extends AbstractTest { public static void premain( final String agentArgs, final Instrumentation inst) { inst.addTransformer(new ClassFileTransformer() { public byte[] transform( final ClassLoader loader, final String className, final Class classBeingRedefined, final ProtectionDomain domain, final byte[] classFileBuffer) throws IllegalClassFormatException { String n = className.replace('/', '.'); if (agentArgs.length() == 0 || n.indexOf(agentArgs) != -1) { return transformClass(classFileBuffer); } else { return null; } } }); } static byte[] transformClass(final byte[] clazz) { ClassReader cr = new ClassReader(clazz); ClassWriter cw = new ClassWriter(0); cr.accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new LocalVariablesSorter(access, desc, cv.visitMethod(access, name, desc, signature, exceptions)); } }, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); } public static TestSuite suite() throws Exception { return new LocalVariablesSorterTest2().getSuite(); } public void test() throws Exception { try { Class.forName(n, true, getClass().getClassLoader()); } catch (NoClassDefFoundError ncdfe) { // ignored } catch (UnsatisfiedLinkError ule) { // ignored } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (VerifyError ve) { String s = n.replace('.', '/') + ".class"; InputStream is = getClass().getClassLoader().getResourceAsStream(s); ClassReader cr = new ClassReader(is); byte[] b = transformClass(cr.b); StringWriter sw1 = new StringWriter(); StringWriter sw2 = new StringWriter(); sw2.write(ve.toString() + "\n"); ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1)); ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2)); cr.accept(cv1, 0); new ClassReader(b).accept(cv2, 0); String s1 = sw1.toString(); String s2 = sw2.toString(); assertEquals("different data", s1, s2); } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/AdviceAdapterTest.java0000644000175000017500000001132510452754520026052 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import junit.textui.TestRunner; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * AdviceAdapter tests. * * @author Eugene Kuleshov */ public class AdviceAdapterTest extends AbstractTest { public static void main(final String[] args) throws Exception { TestRunner.run(AdviceAdapterTest.suite()); } public static TestSuite suite() throws Exception { return new AdviceAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw1 = new ClassWriter(0); ClassWriter cw2 = new ClassWriter(0); cr.accept(new ReferenceClassAdapter(cw1), ClassReader.EXPAND_FRAMES); cr.accept(new AdviceClassAdapter(cw2), ClassReader.EXPAND_FRAMES); assertEquals(new ClassReader(cw1.toByteArray()), new ClassReader(cw2.toByteArray())); } static class ReferenceClassAdapter extends ClassAdapter { public ReferenceClassAdapter(final ClassVisitor cv) { super(cv); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv == null || (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) > 0) { return mv; } return new LocalVariablesSorter(access, desc, mv); } } static class AdviceClassAdapter extends ClassAdapter { public AdviceClassAdapter(final ClassVisitor cv) { super(cv); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv == null || (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) > 0) { return mv; } return new AdviceAdapter(mv, access, name, desc) { protected void onMethodEnter() { // mv.visitInsn(NOP); // mv.visitInsn(NOP); // mv.visitInsn(NOP); } protected void onMethodExit(final int opcode) { // mv.visitInsn(NOP); // mv.visitInsn(NOP); // mv.visitInsn(NOP); // mv.visitInsn(NOP); } }; } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/GASMifierMethodVisitor.java0000644000175000017500000011507511347404001027002 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.util.ASMifierAbstractVisitor; import org.objectweb.asm.util.ASMifierAnnotationVisitor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A {@link MethodVisitor} that prints the ASM code that generates the methods * it visits by using the GeneratorAdapter class. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class GASMifierMethodVisitor extends ASMifierAbstractVisitor implements MethodVisitor, Opcodes { int access; Type[] argumentTypes; int firstLocal; Map locals; List localTypes; int lastOpcode = -1; HashMap labelNames; public GASMifierMethodVisitor(final int access, final String desc) { super("mg"); this.access = access; this.labelNames = new HashMap(); this.argumentTypes = Type.getArgumentTypes(desc); int nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1; for (int i = 0; i < argumentTypes.length; i++) { nextLocal += argumentTypes[i].getSize(); } this.firstLocal = nextLocal; this.locals = new HashMap(); this.localTypes = new ArrayList(); } public AnnotationVisitor visitAnnotationDefault() { buf.setLength(0); buf.append("{\n").append("av0 = mg.visitAnnotationDefault();\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible) { buf.setLength(0); buf.append("{\n") .append("av0 = mg.visitParameterAnnotation(") .append(parameter) .append(", \""); buf.append(desc); buf.append("\", ").append(visible).append(");\n"); text.add(buf.toString()); ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); text.add(av.getText()); text.add("}\n"); return av; } public void visitCode() { text.add("mg.visitCode();\n"); } public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { buf.setLength(0); switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: declareFrameTypes(nLocal, local); declareFrameTypes(nStack, stack); if (type == Opcodes.F_NEW) { buf.append("mg.visitFrame(Opcodes.F_NEW, "); } else { buf.append("mg.visitFrame(Opcodes.F_FULL, "); } buf.append(nLocal).append(", new Object[] {"); appendFrameTypes(nLocal, local); buf.append("}, ").append(nStack).append(", new Object[] {"); appendFrameTypes(nStack, stack); buf.append("}"); break; case Opcodes.F_APPEND: declareFrameTypes(nLocal, local); buf.append("mg.visitFrame(Opcodes.F_APPEND,") .append(nLocal) .append(", new Object[] {"); appendFrameTypes(nLocal, local); buf.append("}, 0, null"); break; case Opcodes.F_CHOP: buf.append("mg.visitFrame(Opcodes.F_CHOP,") .append(nLocal) .append(", null, 0, null"); break; case Opcodes.F_SAME: buf.append("mg.visitFrame(Opcodes.F_SAME, 0, null, 0, null"); break; case Opcodes.F_SAME1: declareFrameTypes(1, stack); buf.append("mg.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); appendFrameTypes(1, stack); buf.append("}"); break; } buf.append(");\n"); text.add(buf.toString()); } public void visitInsn(final int opcode) { buf.setLength(0); switch (opcode) { case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: buf.append("mg.returnValue();\n"); break; case NOP: buf.append("mg.visitInsn(Opcodes.NOP);\n"); break; case ACONST_NULL: buf.append("mg.push((String)null);\n"); break; case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: buf.append("mg.push(").append(opcode - ICONST_0).append(");\n"); break; case LCONST_0: case LCONST_1: buf.append("mg.push(") .append(opcode - LCONST_0) .append("L);\n"); break; case FCONST_0: case FCONST_1: case FCONST_2: buf.append("mg.push(") .append(opcode - FCONST_0) .append("f);\n"); break; case DCONST_0: case DCONST_1: buf.append("mg.push(") .append(opcode - DCONST_0) .append("d);\n"); break; case POP: buf.append("mg.pop();\n"); break; case POP2: buf.append("mg.pop2();\n"); break; case DUP: buf.append("mg.dup();\n"); break; case DUP_X1: buf.append("mg.dupX1();\n"); break; case DUP_X2: buf.append("mg.dupX2();\n"); break; case DUP2: buf.append("mg.dup2();\n"); break; case DUP2_X1: buf.append("mg.dup2X1();\n"); break; case DUP2_X2: buf.append("mg.dup2X2();\n"); break; case SWAP: buf.append("mg.swap();\n"); break; case MONITORENTER: buf.append("mg.monitorEnter();\n"); break; case MONITOREXIT: buf.append("mg.monitorExit();\n"); break; case ARRAYLENGTH: buf.append("mg.arrayLength();\n"); break; case IALOAD: buf.append("mg.arrayLoad(Type.INT_TYPE);\n"); break; case LALOAD: buf.append("mg.arrayLoad(Type.LONG_TYPE);\n"); break; case FALOAD: buf.append("mg.arrayLoad(Type.FLOAT_TYPE);\n"); break; case DALOAD: buf.append("mg.arrayLoad(Type.DOUBLE_TYPE);\n"); break; case AALOAD: buf.append("mg.arrayLoad(" + getType("java/lang/Object") + ");\n"); break; case BALOAD: buf.append("mg.arrayLoad(Type.BYTE_TYPE);\n"); break; case CALOAD: buf.append("mg.arrayLoad(Type.CHAR_TYPE);\n"); break; case SALOAD: buf.append("mg.arrayLoad(Type.SHORT_TYPE);\n"); break; case IASTORE: buf.append("mg.arrayStore(Type.INT_TYPE);\n"); break; case LASTORE: buf.append("mg.arrayStore(Type.LONG_TYPE);\n"); break; case FASTORE: buf.append("mg.arrayStore(Type.FLOAT_TYPE);\n"); break; case DASTORE: buf.append("mg.arrayStore(Type.DOUBLE_TYPE);\n"); break; case AASTORE: buf.append("mg.arrayStore(" + getType("java/lang/Object") + ");\n"); break; case BASTORE: buf.append("mg.arrayStore(Type.BYTE_TYPE);\n"); break; case CASTORE: buf.append("mg.arrayStore(Type.CHAR_TYPE);\n"); break; case SASTORE: buf.append("mg.arrayStore(Type.SHORT_TYPE);\n"); break; case IADD: buf.append("mg.math(GeneratorAdapter.ADD, Type.INT_TYPE);\n"); break; case LADD: buf.append("mg.math(GeneratorAdapter.ADD, Type.LONG_TYPE);\n"); break; case FADD: buf.append("mg.math(GeneratorAdapter.ADD, Type.FLOAT_TYPE);\n"); break; case DADD: buf.append("mg.math(GeneratorAdapter.ADD, Type.DOUBLE_TYPE);\n"); break; case ISUB: buf.append("mg.math(GeneratorAdapter.SUB, Type.INT_TYPE);\n"); break; case LSUB: buf.append("mg.math(GeneratorAdapter.SUB, Type.LONG_TYPE);\n"); break; case FSUB: buf.append("mg.math(GeneratorAdapter.SUB, Type.FLOAT_TYPE);\n"); break; case DSUB: buf.append("mg.math(GeneratorAdapter.SUB, Type.DOUBLE_TYPE);\n"); break; case IMUL: buf.append("mg.math(GeneratorAdapter.MUL, Type.INT_TYPE);\n"); break; case LMUL: buf.append("mg.math(GeneratorAdapter.MUL, Type.LONG_TYPE);\n"); break; case FMUL: buf.append("mg.math(GeneratorAdapter.MUL, Type.FLOAT_TYPE);\n"); break; case DMUL: buf.append("mg.math(GeneratorAdapter.MUL, Type.DOUBLE_TYPE);\n"); break; case IDIV: buf.append("mg.math(GeneratorAdapter.DIV, Type.INT_TYPE);\n"); break; case LDIV: buf.append("mg.math(GeneratorAdapter.DIV, Type.LONG_TYPE);\n"); break; case FDIV: buf.append("mg.math(GeneratorAdapter.DIV, Type.FLOAT_TYPE);\n"); break; case DDIV: buf.append("mg.math(GeneratorAdapter.DIV, Type.DOUBLE_TYPE);\n"); break; case IREM: buf.append("mg.math(GeneratorAdapter.REM, Type.INT_TYPE);\n"); break; case LREM: buf.append("mg.math(GeneratorAdapter.REM, Type.LONG_TYPE);\n"); break; case FREM: buf.append("mg.math(GeneratorAdapter.REM, Type.FLOAT_TYPE);\n"); break; case DREM: buf.append("mg.math(GeneratorAdapter.REM, Type.DOUBLE_TYPE);\n"); break; case INEG: buf.append("mg.math(GeneratorAdapter.NEG, Type.INT_TYPE);\n"); break; case LNEG: buf.append("mg.math(GeneratorAdapter.NEG, Type.LONG_TYPE);\n"); break; case FNEG: buf.append("mg.math(GeneratorAdapter.NEG, Type.FLOAT_TYPE);\n"); break; case DNEG: buf.append("mg.math(GeneratorAdapter.NEG, Type.DOUBLE_TYPE);\n"); break; case ISHL: buf.append("mg.math(GeneratorAdapter.SHL, Type.INT_TYPE);\n"); break; case LSHL: buf.append("mg.math(GeneratorAdapter.SHL, Type.LONG_TYPE);\n"); break; case ISHR: buf.append("mg.math(GeneratorAdapter.SHR, Type.INT_TYPE);\n"); break; case LSHR: buf.append("mg.math(GeneratorAdapter.SHR, Type.LONG_TYPE);\n"); break; case IUSHR: buf.append("mg.math(GeneratorAdapter.USHR, Type.INT_TYPE);\n"); break; case LUSHR: buf.append("mg.math(GeneratorAdapter.USHR, Type.LONG_TYPE);\n"); break; case IAND: buf.append("mg.math(GeneratorAdapter.AND, Type.INT_TYPE);\n"); break; case LAND: buf.append("mg.math(GeneratorAdapter.AND, Type.LONG_TYPE);\n"); break; case IOR: buf.append("mg.math(GeneratorAdapter.OR, Type.INT_TYPE);\n"); break; case LOR: buf.append("mg.math(GeneratorAdapter.OR, Type.LONG_TYPE);\n"); break; case IXOR: buf.append("mg.math(GeneratorAdapter.XOR, Type.INT_TYPE);\n"); break; case LXOR: buf.append("mg.math(GeneratorAdapter.XOR, Type.LONG_TYPE);\n"); break; case ATHROW: buf.append("mg.throwException();\n"); break; case I2L: buf.append("mg.cast(Type.INT_TYPE, Type.LONG_TYPE);\n"); break; case I2F: buf.append("mg.cast(Type.INT_TYPE, Type.FLOAT_TYPE);\n"); break; case I2D: buf.append("mg.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);\n"); break; case L2I: buf.append("mg.cast(Type.LONG_TYPE, Type.INT_TYPE);\n"); break; case L2F: buf.append("mg.cast(Type.LONG_TYPE, Type.FLOAT_TYPE);\n"); break; case L2D: buf.append("mg.cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);\n"); break; case F2I: buf.append("mg.cast(Type.FLOAT_TYPE, Type.INT_TYPE);\n"); break; case F2L: buf.append("mg.cast(Type.FLOAT_TYPE, Type.LONG_TYPE);\n"); break; case F2D: buf.append("mg.cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);\n"); break; case D2I: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.INT_TYPE);\n"); break; case D2L: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);\n"); break; case D2F: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);\n"); break; case I2B: // TODO detect if previous element in 'text' is a cast, // for possible optimisations (e.g. cast(F,I) cast(I,B) = // cast(F,B)) buf.append("mg.cast(Type.INT_TYPE, Type.BYTE_TYPE);\n"); break; case I2C: // idem buf.append("mg.cast(Type.INT_TYPE, Type.CHAR_TYPE);\n"); break; case I2S: // idem buf.append("mg.cast(Type.INT_TYPE, Type.SHORT_TYPE);\n"); break; case LCMP: case FCMPL: case FCMPG: case DCMPL: case DCMPG: // TODO detect xCMPy IF_ICMP -> ifCmp(..., ..., label) buf.append("mg.visitInsn(") .append(OPCODES[opcode]) .append(");\n"); break; default: throw new RuntimeException("unexpected case"); } text.add(buf.toString()); lastOpcode = opcode; } public void visitIntInsn(final int opcode, final int operand) { buf.setLength(0); if (opcode == NEWARRAY) { String type; switch (operand) { case T_BOOLEAN: type = "Type.BOOLEAN_TYPE"; break; case T_CHAR: type = "Type.CHAR_TYPE"; break; case T_FLOAT: type = "Type.FLOAT_TYPE"; break; case T_DOUBLE: type = "Type.DOUBLE_TYPE"; break; case T_BYTE: type = "Type.BYTE_TYPE"; break; case T_SHORT: type = "Type.SHORT_TYPE"; break; case T_INT: type = "Type.INT_TYPE"; break; case T_LONG: type = "Type.LONG_TYPE"; break; default: throw new RuntimeException("unexpected case"); } buf.append("mg.newArray(").append(type).append(");\n"); } else { buf.append("mg.push(").append(operand).append(");\n"); } text.add(buf.toString()); lastOpcode = opcode; } public void visitVarInsn(final int opcode, final int var) { buf.setLength(0); try { switch (opcode) { case RET: if (var < firstLocal) { buf.append("mg.ret("); buf.append(var); buf.append(");\n"); } else { int v = generateNewLocal(var, "Type.INT_TYPE"); buf.append("mg.ret("); buf.append("local").append(v); buf.append(");\n"); } break; case ILOAD: generateLoadLocal(var, "Type.INT_TYPE"); break; case LLOAD: generateLoadLocal(var, "Type.LONG_TYPE"); break; case FLOAD: generateLoadLocal(var, "Type.FLOAT_TYPE"); break; case DLOAD: generateLoadLocal(var, "Type.DOUBLE_TYPE"); break; case ALOAD: generateLoadLocal(var, getType("java/lang/Object")); break; case ISTORE: generateStoreLocal(var, "Type.INT_TYPE"); break; case LSTORE: generateStoreLocal(var, "Type.LONG_TYPE"); break; case FSTORE: generateStoreLocal(var, "Type.FLOAT_TYPE"); break; case DSTORE: generateStoreLocal(var, "Type.DOUBLE_TYPE"); break; case ASTORE: generateStoreLocal(var, getType("java/lang/Object")); break; default: throw new RuntimeException("unexpected case"); } } catch (Exception e) { buf.append("mg.visitVarInsn(" + OPCODES[opcode] + ", " + var + ");\n"); } text.add(buf.toString()); lastOpcode = opcode; } private void generateLoadLocal(final int var, final String type) { if (var < firstLocal) { if (var == 0 && (access & ACC_STATIC) == 0) { buf.append("mg.loadThis();\n"); } else { int index = getArgIndex(var); buf.append("mg.loadArg(").append(index).append(");\n"); } } else { int local = generateNewLocal(var, type); buf.append("mg.loadLocal(local").append(local); if (!type.equals(localTypes.get(local))) { localTypes.set(local, type); buf.append(", ").append(type); } buf.append(");\n"); } } private void generateStoreLocal(final int var, final String type) { if (var < firstLocal) { if (var == 0 && (access & ACC_STATIC) == 0) { buf.append("mg.visitVarInsn(ASTORE, " + var + ");\n"); } else { int index = getArgIndex(var); buf.append("mg.storeArg(").append(index).append(");\n"); } } else { int local = generateNewLocal(var, type); buf.append("mg.storeLocal(local").append(local); if (!type.equals(localTypes.get(local))) { localTypes.set(local, type); buf.append(", ").append(type); } buf.append(");\n"); } } private int generateNewLocal(final int var, final String type) { Integer i = (Integer) locals.get(new Integer(var)); if (i == null) { int local = locals.size(); locals.put(new Integer(var), new Integer(local)); localTypes.add(type); buf.append("int local" + local + " = mg.newLocal(" + type + ");\n"); return local; } return i.intValue(); } private int getArgIndex(final int var) { int nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1; int i = 0; while (nextLocal != var) { nextLocal += argumentTypes[i++].getSize(); } return i; } public void visitTypeInsn(final int opcode, final String type) { String typ = getType(type); buf.setLength(0); if (opcode == NEW) { buf.append("mg.newInstance(").append(typ).append(");\n"); } else if (opcode == ANEWARRAY) { buf.append("mg.newArray(").append(typ).append(");\n"); } else if (opcode == CHECKCAST) { buf.append("mg.checkCast(").append(typ).append(");\n"); } else if (opcode == INSTANCEOF) { buf.append("mg.instanceOf(").append(typ).append(");\n"); } text.add(buf.toString()); lastOpcode = opcode; } public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); switch (opcode) { case GETFIELD: buf.append("mg.getField("); break; case PUTFIELD: buf.append("mg.putField("); break; case GETSTATIC: buf.append("mg.getStatic("); break; case PUTSTATIC: buf.append("mg.putStatic("); break; default: throw new RuntimeException("unexpected case"); } buf.append(getType(owner)); buf.append(", \""); buf.append(name); buf.append("\", "); buf.append(getDescType(desc)); buf.append(");\n"); text.add(buf.toString()); lastOpcode = opcode; } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { buf.setLength(0); switch (opcode) { case INVOKEVIRTUAL: buf.append("mg.invokeVirtual("); break; case INVOKESPECIAL: buf.append("mg.invokeConstructor("); break; case INVOKESTATIC: buf.append("mg.invokeStatic("); break; case INVOKEINTERFACE: buf.append("mg.invokeInterface("); break; case INVOKEDYNAMIC: buf.append("mg.invokeDynamic("); break; default: throw new RuntimeException("unexpected case"); } if (opcode != INVOKEDYNAMIC) { if (owner.charAt(0) == '[') { buf.append(getDescType(owner)); } else { buf.append(getType(owner)); } buf.append(", "); } buf.append(getMethod(name, desc)); buf.append(");\n"); text.add(buf.toString()); lastOpcode = opcode; } public void visitJumpInsn(final int opcode, final Label label) { buf.setLength(0); declareLabel(label); if (opcode == GOTO || opcode == IFNULL || opcode == IFNONNULL) { if (opcode == GOTO) { buf.append("mg.goTo("); } if (opcode == IFNULL) { buf.append("mg.ifNull("); } if (opcode == IFNONNULL) { buf.append("mg.ifNonNull("); } appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPEQ) { buf.append("mg.ifICmp(GeneratorAdapter.EQ, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPNE) { buf.append("mg.ifICmp(GeneratorAdapter.NE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPLT) { buf.append("mg.ifICmp(GeneratorAdapter.LT, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPGE) { buf.append("mg.ifICmp(GeneratorAdapter.GE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPGT) { buf.append("mg.ifICmp(GeneratorAdapter.GT, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ICMPLE) { buf.append("mg.ifICmp(GeneratorAdapter.LE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ACMPEQ) { buf.append("mg.ifCmp("); buf.append(getType("java/lang/Object")) .append(", ") .append("GeneratorAdapter.EQ, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IF_ACMPNE) { buf.append("mg.ifCmp("); buf.append(getType("java/lang/Object")) .append(", ") .append("GeneratorAdapter.NE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFEQ) { buf.append("mg.ifZCmp(GeneratorAdapter.EQ, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFNE) { buf.append("mg.ifZCmp(GeneratorAdapter.NE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFLT) { buf.append("mg.ifZCmp(GeneratorAdapter.LT, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFGE) { buf.append("mg.ifZCmp(GeneratorAdapter.GE, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFGT) { buf.append("mg.ifZCmp(GeneratorAdapter.GT, "); appendLabel(label); buf.append(");\n"); } else if (opcode == IFLE) { buf.append("mg.ifZCmp(GeneratorAdapter.LE, "); appendLabel(label); buf.append(");\n"); } else { buf.append("mg.visitJumpInsn(") .append(OPCODES[opcode]) .append(", "); appendLabel(label); buf.append(");\n"); } text.add(buf.toString()); lastOpcode = opcode; } public void visitLabel(final Label label) { buf.setLength(0); declareLabel(label); buf.append("mg.mark("); appendLabel(label); buf.append(");\n"); text.add(buf.toString()); lastOpcode = -1; } public void visitLdcInsn(final Object cst) { buf.setLength(0); buf.append("mg.push("); if (cst == null) { buf.append("(String)null"); } else if (cst instanceof Long) { buf.append(cst + "L"); } else if (cst instanceof Float) { float f = ((Float) cst).floatValue(); if (Float.isNaN(f)) { buf.append("Float.NaN"); } else if (Float.isInfinite(f)) { buf.append(f > 0 ? "Float.POSITIVE_INFINITY" : "Float.NEGATIVE_INFINITY"); } else { buf.append(cst + "f"); } } else if (cst instanceof Double) { double d = ((Double) cst).doubleValue(); if (Double.isNaN(d)) { buf.append("Double.NaN"); } else if (Double.isInfinite(d)) { buf.append(d > 0 ? "Double.POSITIVE_INFINITY" : "Double.NEGATIVE_INFINITY"); } else { buf.append(cst + "d"); } } else if (cst instanceof String) { appendString(buf, (String) cst); } else if (cst instanceof Type) { buf.append("Type.getType(\"").append(cst).append("\")"); } else { buf.append(cst); } buf.append(");\n"); text.add(buf.toString()); lastOpcode = LDC; } public void visitIincInsn(final int var, final int increment) { buf.setLength(0); if (var < firstLocal) { buf.append("mg.iinc(").append(var); } else { int v = generateNewLocal(var, "Type.INT_TYPE"); buf.append("mg.iinc(local").append(v); } buf.append(", ").append(increment).append(");\n"); text.add(buf.toString()); lastOpcode = IINC; } public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label labels[]) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("mg.visitTableSwitchInsn(") .append(min) .append(", ") .append(max) .append(", "); appendLabel(dflt); buf.append(", new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" }); // TODO\n"); text.add(buf.toString()); lastOpcode = TABLESWITCH; } public void visitLookupSwitchInsn( final Label dflt, final int keys[], final Label labels[]) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("mg.visitLookupSwitchInsn("); appendLabel(dflt); buf.append(", new int[] {"); for (int i = 0; i < keys.length; ++i) { buf.append(i == 0 ? " " : ", ").append(keys[i]); } buf.append(" }, new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" }); // TODO\n"); text.add(buf.toString()); lastOpcode = LOOKUPSWITCH; } public void visitMultiANewArrayInsn(final String desc, final int dims) { buf.setLength(0); buf.append("mg.visitMultiANewArrayInsn(\""); buf.append(desc); buf.append("\", ").append(dims).append(");\n"); text.add(buf.toString()); lastOpcode = MULTIANEWARRAY; } public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type) { buf.setLength(0); declareLabel(start); declareLabel(end); declareLabel(handler); buf.append("mg.visitTryCatchBlock("); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", "); appendLabel(handler); buf.append(", "); if (type == null) { buf.append("null"); } else { buf.append('"').append(type).append('"'); } buf.append("); // TODO\n"); text.add(buf.toString()); lastOpcode = -1; } public void visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index) { buf.setLength(0); buf.append("mg.visitLocalVariable(\""); buf.append(name); buf.append("\", \""); buf.append(desc); buf.append("\", "); if (signature == null) { buf.append("null"); } else { buf.append('"').append(signature).append('"'); } buf.append(", "); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", ").append(index).append(");\n"); text.add(buf.toString()); lastOpcode = -1; } public void visitLineNumber(final int line, final Label start) { buf.setLength(0); buf.append("mg.visitLineNumber(").append(line).append(", "); appendLabel(start); buf.append(");\n"); text.add(buf.toString()); lastOpcode = -1; } public void visitMaxs(final int maxStack, final int maxLocals) { text.add("mg.endMethod();\n"); lastOpcode = -1; } public void visitEnd() { // does nothing } static String getType(final String internalName) { return "Type.getObjectType(\"" + internalName + "\")"; } static String getDescType(final String desc) { if (desc.equals("Z")) { return "Type.BOOLEAN_TYPE"; } if (desc.equals("B")) { return "Type.BYTE_TYPE"; } if (desc.equals("C")) { return "Type.CHAR_TYPE"; } if (desc.equals("D")) { return "Type.DOUBLE_TYPE"; } if (desc.equals("F")) { return "Type.FLOAT_TYPE"; } if (desc.equals("I")) { return "Type.INT_TYPE"; } if (desc.equals("J")) { return "Type.LONG_TYPE"; } if (desc.equals("S")) { return "Type.SHORT_TYPE"; } if (desc.equals("V")) { return "Type.VOID_TYPE"; } return "Type.getType(\"" + desc + "\")"; } static String getMethod(final String name, final String desc) { Type rt = Type.getReturnType(desc); Type[] argt = Type.getArgumentTypes(desc); StringBuffer buf = new StringBuffer(); buf.append("Method.getMethod(\""); buf.append(rt.getClassName()).append(' '); buf.append(name).append('('); for (int i = 0; i < argt.length; ++i) { if (i > 0) { buf.append(','); } buf.append(argt[i].getClassName()); } buf.append(")\")"); return buf.toString(); } private void declareFrameTypes(final int n, final Object[] o) { for (int i = 0; i < n; ++i) { if (o[i] instanceof Label) { declareLabel((Label) o[i]); } } } private void appendFrameTypes(final int n, final Object[] o) { for (int i = 0; i < n; ++i) { if (i > 0) { buf.append(", "); } if (o[i] instanceof String) { buf.append('"').append(o[i]).append('"'); } else if (o[i] instanceof Integer) { switch (((Integer) o[i]).intValue()) { case 0: buf.append("Opcodes.TOP"); break; case 1: buf.append("Opcodes.INTEGER"); break; case 2: buf.append("Opcodes.FLOAT"); break; case 3: buf.append("Opcodes.DOUBLE"); break; case 4: buf.append("Opcodes.LONG"); break; case 5: buf.append("Opcodes.NULL"); break; case 6: buf.append("Opcodes.UNINITIALIZED_THIS"); break; } } else { appendLabel((Label) o[i]); } } } /** * Appends a declaration of the given label to {@link #buf buf}. This * declaration is of the form "Label lXXX = new Label();". Does nothing if * the given label has already been declared. * * @param l a label. */ private void declareLabel(final Label l) { String name = (String) labelNames.get(l); if (name == null) { name = "label" + labelNames.size(); labelNames.put(l, name); buf.append("Label ").append(name).append(" = mg.newLabel();\n"); } } /** * Appends the name of the given label to {@link #buf buf}. The given label * must already have a name. One way to ensure this is to always * call {@link #declareLabel declared} before calling this method. * * @param l a label. */ private void appendLabel(final Label l) { buf.append((String) labelNames.get(l)); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/SerialVersionUIDAdderUnitTest.java0000644000175000017500000000534710452754520030314 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.IOException; import java.io.Serializable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import junit.framework.TestCase; /** * Test for the SerialVerionUid computation. * * @author Alexandre Vasseur * @author Eric Bruneton */ public class SerialVersionUIDAdderUnitTest extends TestCase implements Serializable { protected final static int aField = 32; static { System.gc(); } public Object[] aMethod() { return null; } private long computeSerialVersionUID(final String className) throws IOException { final long[] svuid = new long[1]; ClassVisitor cv = new SerialVersionUIDAdder(new EmptyVisitor()) { protected long computeSVUID() throws IOException { svuid[0] = super.computeSVUID(); return svuid[0]; } }; new ClassReader(className).accept(cv, 0); return svuid[0]; } public void test() throws Throwable { long UID = computeSerialVersionUID(getClass().getName()); assertEquals(194753646298127968L, UID); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/AnalyzerAdapterTest.java0000644000175000017500000000735510452754520026454 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * AnalyzerAdapter tests. * * @author Eric Bruneton */ public class AnalyzerAdapterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new AnalyzerAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); if (cr.readInt(4) != Opcodes.V1_6) { try { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cr.accept(cw, 0); cr = new ClassReader(cw.toByteArray()); } catch (Exception e) { return; } } ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new ClassAdapter(cw) { private String owner; public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { owner = name; cv.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); return new AnalyzerAdapter(owner, access, name, desc, mv); } }; cr.accept(cv, ClassReader.EXPAND_FRAMES); } } asm-3.3.2/test/conform/org/objectweb/asm/commons/AdviceAdapterUnitTest.java0000644000175000017500000001650411224532001026700 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * Simple example of using AdviceAdapter to implement tracing callback * * @author Eugene Kuleshov */ public class AdviceAdapterUnitTest extends AbstractTest { public void test() throws Exception { Class c = getClass(); String name = c.getName(); AdvisingClassLoader cl = new AdvisingClassLoader(name + "$"); Class cc = cl.loadClass(name + "$B"); Method m = cc.getMethod("run", new Class[] { Integer.TYPE }); try { m.invoke(null, new Object[] { new Integer(0) }); } catch (InvocationTargetException e) { throw (Exception) e.getTargetException(); } } private static class AdvisingClassLoader extends ClassLoader { private String prefix; public AdvisingClassLoader(final String prefix) throws IOException { this.prefix = prefix; } public Class loadClass(final String name) throws ClassNotFoundException { if (name.startsWith(prefix)) { try { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassReader cr = new ClassReader(getClass().getResourceAsStream("/" + name.replace('.', '/') + ".class")); cr.accept(new AdviceClassAdapter(cw), ClassReader.EXPAND_FRAMES); byte[] bytecode = cw.toByteArray(); return super.defineClass(name, bytecode, 0, bytecode.length); } catch (IOException ex) { throw new ClassNotFoundException("Load error: " + ex.toString(), ex); } } return super.loadClass(name); } } // test callback private static int n = 0; public static void enter(final String msg) { System.err.println(off().append("enter ").append(msg).toString()); n++; } public static void exit(final String msg) { n--; System.err.println(off().append("<").toString()); } private static StringBuffer off() { StringBuffer sb = new StringBuffer(); for (int i = 0; i < n; i++) { sb.append(" "); } return sb; } static class AdviceClassAdapter extends ClassAdapter implements Opcodes { String cname; public AdviceClassAdapter(final ClassVisitor cv) { super(cv); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { this.cname = name; super.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv == null || (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) > 0) { return mv; } return new AdviceAdapter(mv, access, name, desc) { protected void onMethodEnter() { mv.visitLdcInsn(cname + "." + name + desc); mv.visitMethodInsn(INVOKESTATIC, "org/objectweb/asm/commons/AdviceAdapterUnitTest", "enter", "(Ljava/lang/String;)V"); } protected void onMethodExit(final int opcode) { mv.visitLdcInsn(cname + "." + name + desc); mv.visitMethodInsn(INVOKESTATIC, "org/objectweb/asm/commons/AdviceAdapterUnitTest", "exit", "(Ljava/lang/String;)V"); } }; } } // TEST CLASSES public static class A { final String s; public A(final String s) { this.s = s; } public A(final A a) { this.s = a.s; } } public static class B extends A { public B() { super(new B("")); test(this); } public B(final A a) { super(a); test(this); } public B(final String s) { super(s == null ? new A("") : new A(s)); test(this); } private static A aa; public B(final String s, final A a) { this(s == null ? aa = new A(s) : a); A aa = new A(""); test(aa); } public B(final String s, final String s1) { super(s != null ? new A(getA(s1).s) : new A(s)); test(this); } private void test(final Object b) { } private static A getA(final String s) { return new A(s); } // execute all public static void run(final int n) { new B(); new B(new A("")); new B(new B()); new B("", new A("")); new B("", ""); } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/GASMifierTest.java0000644000175000017500000001476611224532001025122 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import junit.framework.TestSuite; import org.codehaus.janino.ClassLoaderIClassLoader; import org.codehaus.janino.DebuggingInformation; import org.codehaus.janino.IClassLoader; import org.codehaus.janino.Parser; import org.codehaus.janino.Scanner; import org.codehaus.janino.UnitCompiler; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.attrs.CodeComment; import org.objectweb.asm.attrs.Comment; /** * GASMifier tests. * * @author Eugene Kuleshov * @author Eric Bruneton */ public class GASMifierTest extends AbstractTest { public static final Compiler COMPILER = new Compiler(); private final static TestClassLoader LOADER = new TestClassLoader(); public static TestSuite suite() throws Exception { return new GASMifierTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); if (cr.b.length > 20000) { return; } StringWriter sw = new StringWriter(); GASMifierClassVisitor cv = new GASMifierClassVisitor(new PrintWriter(sw)); cr.accept(cv, new Attribute[] { new Comment(), new CodeComment() }, ClassReader.EXPAND_FRAMES); String generated = sw.toString(); byte[] generatorClassData; try { generatorClassData = COMPILER.compile(n, generated); } catch (Exception ex) { trace(generated); throw ex; } ClassWriter cw = new ClassWriter(0); cr.accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new LocalVariablesSorter(access, desc, super.visitMethod(access, name, desc, signature, exceptions)); } }, new Attribute[] { new Comment(), new CodeComment() }, ClassReader.EXPAND_FRAMES); cr = new ClassReader(cw.toByteArray()); String nd = n + "Dump"; if (n.indexOf('.') != -1) { nd = "asm." + nd; } Class c = LOADER.defineClass(nd, generatorClassData); Method m = c.getMethod("dump", new Class[0]); byte[] b; try { b = (byte[]) m.invoke(null, new Object[0]); } catch (InvocationTargetException ex) { trace(generated); throw (Exception) ex.getTargetException(); } try { assertEquals(cr, new ClassReader(b), new Filter(), new Filter()); } catch (Throwable e) { trace(generated); assertEquals(cr, new ClassReader(b), new Filter(), new Filter()); } } private void trace(final String generated) { if (System.getProperty("asm.test.class") != null) { System.err.println(generated); } } static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } static class Compiler { final static IClassLoader CL = new ClassLoaderIClassLoader(new URLClassLoader(new URL[0])); public byte[] compile(final String name, final String source) throws Exception { Parser p = new Parser(new Scanner(name, new StringReader(source))); UnitCompiler uc = new UnitCompiler(p.parseCompilationUnit(), CL); return uc.compileUnit(DebuggingInformation.ALL)[0].toByteArray(); } } static class Filter extends ClassAdapter { public Filter() { super(null); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodAdapter(super.visitMethod(access, name, desc, signature, exceptions)) { public void visitMaxs(final int maxStack, final int maxLocals) { super.visitMaxs(0, 0); } }; } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/StaticInitMergerTest.java0000644000175000017500000000701510452754520026574 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import junit.framework.TestCase; /** * StaticInitMerger tests. * * @author Eric Bruneton */ public class StaticInitMergerTest extends TestCase implements Opcodes { private final static TestClassLoader LOADER = new TestClassLoader(); public void test() throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor cv = new StaticInitMerger("$clinit$", cw); cv.visit(V1_1, ACC_PUBLIC, "A", null, "java/lang/Object", null); cv.visitField(ACC_PUBLIC + ACC_STATIC, "counter", "I", null, null); for (int i = 0; i < 5; ++i) { MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitFieldInsn(GETSTATIC, "A", "counter", "I"); mv.visitInsn(ICONST_1); mv.visitInsn(IADD); mv.visitFieldInsn(PUTSTATIC, "A", "counter", "I"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); } MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); cv.visitEnd(); Class c = LOADER.defineClass("A", cw.toByteArray()); assertEquals(c.getField("counter").getInt(c.newInstance()), 5); } // ------------------------------------------------------------------------ static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } } asm-3.3.2/test/conform/org/objectweb/asm/commons/RemappingClassAdapterTest.java0000644000175000017500000002244210635277351027576 0ustar twernertwerner/*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import junit.framework.TestCase; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.MultiANewArrayInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.TypeInsnNode; public class RemappingClassAdapterTest extends TestCase implements Opcodes { public void testRemappingClassAdapter() throws Exception { Map map = new HashMap(); map.put("Boo", "B1"); map.put("Coo", "C1"); map.put("Doo", "D1"); Remapper remapper = new SimpleRemapper(map); ClassNode cn = new ClassNode(); dump(new RemappingClassAdapter(cn, remapper)); assertEquals("D1", cn.name); assertEquals("B1", cn.superName); assertEquals(Arrays.asList(new String[] {"I", "I", "C1", "J", "B1"}), cn.interfaces); assertEquals("LB1;", field(cn, 0).desc); assertEquals("[LB1;", field(cn, 1).desc); assertEquals("D1", innerClass(cn, 0).name); assertEquals("B1", innerClass(cn, 0).outerName); // assertEquals("Doo", innerClass(cn, 0).innerName); assertEquals("B1", cn.outerClass); assertEquals("([[LB1;LC1;LD1;)LC1;", cn.outerMethodDesc); MethodNode mn0 = (MethodNode) cn.methods.get(0); Iterator it = mn0.instructions.iterator(); FieldInsnNode n0 = (FieldInsnNode) it.next(); assertEquals("D1", n0.owner); assertEquals("LB1;", n0.desc); assertEquals(Type.getType("LB1;"), ((LdcInsnNode) it.next()).cst); assertEquals(Type.getType("[LD1;"), ((LdcInsnNode) it.next()).cst); assertEquals(Type.getType("[I"), ((LdcInsnNode) it.next()).cst); assertEquals(Type.getType("J"), ((LdcInsnNode) it.next()).cst); assertEquals("B1", ((TypeInsnNode) it.next()).desc); assertEquals("[LD1;", ((TypeInsnNode) it.next()).desc); assertEquals("[I", ((TypeInsnNode) it.next()).desc); assertEquals("J", ((TypeInsnNode) it.next()).desc); MultiANewArrayInsnNode n3 = (MultiANewArrayInsnNode) it.next(); assertEquals("[[LB1;", n3.desc); MethodInsnNode n4 = (MethodInsnNode) it.next(); assertEquals("D1", n4.owner); assertEquals("([[LB1;LC1;LD1;)LC1;", n4.desc); FrameNode fn0 = (FrameNode) it.next(); assertEquals(Collections.EMPTY_LIST, fn0.local); assertEquals(Collections.EMPTY_LIST, fn0.stack); assertEquals(Arrays.asList(new Object[] {"B1", "C1", "D1"}), ((FrameNode) it.next()).local); assertEquals(Arrays.asList(new Object[] {Opcodes.INTEGER, "C1", Opcodes.INTEGER, "D1"}), ((FrameNode) it.next()).local); assertEquals(Arrays.asList(new Object[] {Opcodes.INTEGER, Opcodes.INTEGER}), ((FrameNode) it.next()).local); // assertEquals(Collections.EMPTY_LIST, fn0.stack); TryCatchBlockNode tryCatchBlockNode = (TryCatchBlockNode) mn0.tryCatchBlocks.get(0); assertEquals("C1", tryCatchBlockNode.type); MethodNode mn1 = (MethodNode) cn.methods.get(1); assertEquals("([[LB1;LC1;LD1;)V", mn1.desc); assertEquals(Arrays.asList(new String[] {"I", "J"}), mn1.exceptions); } private FieldNode field(ClassNode cn, int n) { return (FieldNode) cn.fields.get(n); } private InnerClassNode innerClass(ClassNode cn, int n) { return (InnerClassNode) cn.innerClasses.get(n); } public static void dump(ClassVisitor cv) throws Exception { cv.visit(V1_5, 0, "Doo", null, "Boo", new String[] { "I", "I", "Coo", "J", "Boo"}); cv.visitInnerClass("Doo", "Boo", "Doo", 0); cv.visitOuterClass("Boo", "foo", "([[LBoo;LCoo;LDoo;)LCoo;"); cv.visitField(0, "boo", "LBoo;", null, null).visitEnd(); cv.visitField(0, "boo1", "[LBoo;", null, null).visitEnd(); cv.visitField(0, "s", "Ljava/lang/String;", null, null).visitEnd(); cv.visitField(0, "i", "I", null, null).visitEnd(); MethodVisitor mv; mv = cv.visitMethod(0, "foo", "()V", null, null); mv.visitCode(); mv.visitFieldInsn(GETFIELD, "Doo", "boo", "LBoo;"); mv.visitLdcInsn(Type.getType("LBoo;")); mv.visitLdcInsn(Type.getType("[LDoo;")); mv.visitLdcInsn(Type.getType("[I")); mv.visitLdcInsn(Type.getType("J")); mv.visitTypeInsn(ANEWARRAY, "Boo"); mv.visitTypeInsn(ANEWARRAY, "[LDoo;"); mv.visitTypeInsn(ANEWARRAY, "[I"); mv.visitTypeInsn(ANEWARRAY, "J"); mv.visitMultiANewArrayInsn("[[LBoo;", 2); mv.visitMethodInsn(INVOKEVIRTUAL, "Doo", "goo", "([[LBoo;LCoo;LDoo;)LCoo;"); mv.visitFrame(Opcodes.F_NEW, 0, new Object[5], 0, new Object[10]); mv.visitFrame(Opcodes.F_NEW, 3, new Object[] { "Boo", "Coo", "Doo" }, 0, new Object[0]); mv.visitFrame(Opcodes.F_NEW, 4, new Object[] {Opcodes.INTEGER, "Coo", Opcodes.INTEGER, "Doo" }, 0, new Object[0]); mv.visitFrame(Opcodes.F_NEW, 2, new Object[] {Opcodes.INTEGER, Opcodes.INTEGER }, 0, new Object[0]); Label l = new Label(); mv.visitLocalVariable("boo", "LBoo;", null, l, l, 1); mv.visitLocalVariable("boo1", "[LBoo;", null, l, l, 3); mv.visitLocalVariable("boo2", "[[LBoo;", null, l, l, 4); mv.visitMaxs(0, 0); mv.visitTryCatchBlock(l, l, l, "Coo"); mv.visitEnd(); mv = cv.visitMethod(0, "goo", "([[LBoo;LCoo;LDoo;)V", null, new String[] { "I", "J" }); mv.visitEnd(); cv.visitEnd(); } // /* public static class Boo { } public static interface Coo { } public static class Doo extends Boo implements Coo { Boo boo = new Boo(); Boo[] boo1 = new Boo[2]; String s = ""; int i = 5; static final Class c1 = Boo.class; static final Class c2 = Boo[].class; public Doo() { } public Doo(int i, Coo coo, Boo boo) { } void foo() { class Eoo { String s; } Eoo e = new Eoo(); e.s = "aaa"; // visitFieldInsn(int, String, String, String) // visitLocalVariable(String, String, String, Label, Label, int) Boo boo = this.boo; // visitLdcInsn(Object) Class cc = Boo.class; // visitTypeInsn(int, String) Boo[] boo1 = new Boo[2]; // visitMultiANewArrayInsn(String, int) Boo[][] boo2 = new Boo[2][2]; // visitMethodInsn(int, String, String, String) goo(boo2, this, this); } Coo goo(Boo[][] boo2, Coo coo, Doo doo) { return null; } } // */ } asm-3.3.2/test/conform/org/objectweb/asm/commons/LocalVariablesSorterTest.java0000644000175000017500000000660710452754520027447 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.commons; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; /** * LocalVariableSorter tests. * * @author Eric Bruneton */ public class LocalVariablesSorterTest extends AbstractTest { private final static TestClassLoader LOADER = new TestClassLoader(); public static TestSuite suite() throws Exception { return new LocalVariablesSorterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); cr.accept(new ClassAdapter(cw) { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new LocalVariablesSorter(access, desc, super.visitMethod(access, name, desc, signature, exceptions)); } }, ClassReader.EXPAND_FRAMES); byte[] b = cw.toByteArray(); try { LOADER.defineClass(n, b); } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (Throwable ignored) { } } // ------------------------------------------------------------------------ static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } } asm-3.3.2/test/conform/org/objectweb/asm/AnnotationsTest.java0000644000175000017500000001170710522056320024173 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import org.objectweb.asm.commons.EmptyVisitor; import junit.framework.TestSuite; /** * Annotations tests. * * @author Eric Bruneton */ public class AnnotationsTest extends AbstractTest { public static TestSuite suite() throws Exception { return new AnnotationsTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw1 = new ClassWriter(0); ClassWriter cw2 = new ClassWriter(0); cr.accept(new RemoveAnnotationsAdapter1(cw1), 0); cr.accept(new RemoveAnnotationsAdapter2(cw2), 0); assertEquals(new ClassReader(cw2.toByteArray()), new ClassReader(cw1.toByteArray())); } static class RemoveAnnotationsAdapter1 extends ClassAdapter { public RemoveAnnotationsAdapter1(final ClassVisitor cv) { super(cv); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return new EmptyVisitor(); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodAdapter(cv.visitMethod(access, name, desc, signature, exceptions)) { public AnnotationVisitor visitAnnotationDefault() { return new EmptyVisitor(); } public AnnotationVisitor visitAnnotation( String desc, boolean visible) { return new EmptyVisitor(); } public AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { return new EmptyVisitor(); } }; } } static class RemoveAnnotationsAdapter2 extends ClassAdapter { public RemoveAnnotationsAdapter2(final ClassVisitor cv) { super(cv); } public AnnotationVisitor visitAnnotation( final String desc, final boolean visible) { return null; } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodAdapter(cv.visitMethod(access, name, desc, signature, exceptions)) { public AnnotationVisitor visitAnnotationDefault() { return null; } public AnnotationVisitor visitAnnotation( String desc, boolean visible) { return null; } public AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { return null; } }; } } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterTest.java0000644000175000017500000000410110452754520024137 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestSuite; /** * ClassWriter tests. * * @author Eric Bruneton */ public class ClassWriterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new ClassWriterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); cr.accept(cw, 0); assertEquals(cr, new ClassReader(cw.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassAdapterTest.java0000644000175000017500000000514610452754520024255 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestSuite; /** * ClassAdapter tests. * * @author Eric Bruneton */ public class ClassAdapterTest extends AbstractTest { private final static TestClassLoader LOADER = new TestClassLoader(); public static TestSuite suite() throws Exception { return new ClassAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cr.accept(new ClassAdapter(cw), 0); byte[] b = cw.toByteArray(); try { LOADER.defineClass(n, b); } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (Throwable ignored) { } } // ------------------------------------------------------------------------ static class TestClassLoader extends ClassLoader { public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } } asm-3.3.2/test/conform/org/objectweb/asm/AbstractTest.java0000644000175000017500000001415510574730010023443 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.objectweb.asm.util.TraceClassVisitor; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Super class for test suites based on a jar file. * * @author Eugene Kuleshov * @author Eric Bruneton */ public abstract class AbstractTest extends TestCase { protected String n; protected InputStream is; public AbstractTest() { super("test"); } protected void init(final String n, final InputStream is) { this.n = n; this.is = is; } protected TestSuite getSuite() throws Exception { TestSuite suite = new TestSuite(getClass().getName()); String files = System.getProperty("asm.test") + ","; String clazz = System.getProperty("asm.test.class"); String partcount = System.getProperty("parts"); String partid = System.getProperty("part"); int parts = partcount == null ? 1 : Integer.parseInt(partcount); int part = partid == null ? 0 : Integer.parseInt(partid); int id = 0; while (files.indexOf(',') != -1) { String file = files.substring(0, files.indexOf(',')); files = files.substring(files.indexOf(',') + 1); File f = new File(file); if (f.isDirectory()) { scanDirectory("", f, suite, clazz); } else { ZipFile zip = new ZipFile(file); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry e = (ZipEntry) entries.nextElement(); String n = e.getName(); String p = n.replace('/', '.'); if (n.endsWith(".class") && (clazz == null || p.indexOf(clazz) != -1)) { n = p.substring(0, p.length() - 6); if (id % parts == part) { InputStream is = zip.getInputStream(e); AbstractTest t = (AbstractTest) getClass().newInstance(); t.init(n, is); suite.addTest(t); } ++id; } } } } return suite; } private void scanDirectory( final String path, final File f, final TestSuite suite, final String clazz) throws Exception { File[] fs = f.listFiles(); for (int i = 0; i < fs.length; ++i) { String n = fs[i].getName(); String qn = path.length() == 0 ? n : path + "." + n; if (fs[i].isDirectory()) { scanDirectory(qn, fs[i], suite, clazz); } else if (qn.endsWith(".class") && (clazz == null || qn.indexOf(clazz) != -1)) { qn = qn.substring(0, qn.length() - 6); InputStream is = new FileInputStream(fs[i]); AbstractTest t = (AbstractTest) getClass().newInstance(); t.init(qn, is); suite.addTest(t); } } } public abstract void test() throws Exception; public void assertEquals(final ClassReader cr1, final ClassReader cr2) throws Exception { assertEquals(cr1, cr2, null, null); } public void assertEquals( final ClassReader cr1, final ClassReader cr2, final ClassAdapter filter1, final ClassAdapter filter2) throws Exception { if (!Arrays.equals(cr1.b, cr2.b)) { StringWriter sw1 = new StringWriter(); StringWriter sw2 = new StringWriter(); ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1)); ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2)); if (filter1 != null) { filter1.cv = cv1; } if (filter2 != null) { filter2.cv = cv2; } cr1.accept(filter1 == null ? cv1 : filter1, 0); cr2.accept(filter2 == null ? cv2 : filter2, 0); String s1 = sw1.toString(); String s2 = sw2.toString(); assertEquals("different data", s1, s2); } } public String getName() { return super.getName() + ": " + n; } } asm-3.3.2/test/conform/org/objectweb/asm/xml/0000755000175000017500000000000011633370174020777 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/xml/SAXAdapterUnitTest.java0000644000175000017500000000652210452754520025302 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import junit.framework.TestCase; /** * SAXAdapter unit tests * * @author Eric Bruneton */ public class SAXAdapterUnitTest extends TestCase { SAXAdapter sa; protected void setUp() { sa = new SAXAdapter(new DefaultHandler() { public void startDocument() throws SAXException { throw new SAXException(); } public void endDocument() throws SAXException { throw new SAXException(); } public void startElement( final String arg0, final String arg1, final String arg2, final Attributes arg3) throws SAXException { throw new SAXException(); } public void endElement( final String arg0, final String arg1, final String arg2) throws SAXException { throw new SAXException(); } }) { }; } public void testInvalidAddDocumentStart() { try { sa.addDocumentStart(); fail(); } catch (Exception e) { } } public void testInvalidAddDocumentEnd() { try { sa.addDocumentEnd(); fail(); } catch (Exception e) { } } public void testInvalidAddStart() { try { sa.addStart("name", null); fail(); } catch (Exception e) { } } public void testInvalidAddEnd() { try { sa.addEnd("name"); fail(); } catch (Exception e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/xml/ASMContentHandlerUnitTest.java0000644000175000017500000000771210452754520026621 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import junit.framework.TestCase; /** * ASMContentHandler unit tests * * @author Eric Bruneton */ public class ASMContentHandlerUnitTest extends TestCase implements Opcodes { ASMContentHandler h; ClassVisitor cv; MethodVisitor mv; protected void setUp() throws Exception { h = new ASMContentHandler(new ByteArrayOutputStream() { public void write(final byte[] b) throws IOException { throw new IOException(); } }, false); cv = new SAXClassAdapter(h, true); cv.visit(V1_5, ACC_PUBLIC, "C", null, "java/lang/Object", null); } protected void methodSetUp() { mv = cv.visitMethod(0, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); } public void testInvalidOpcode() { methodSetUp(); AttributesImpl attrs = new AttributesImpl(); try { h.startElement("", "opcode", "", attrs); h.endElement("", "opcode", ""); fail(); } catch (SAXException e) { } } public void testInvalidValueDescriptor() { methodSetUp(); AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "desc", "desc", "", "desc"); attrs.addAttribute("", "cst", "cst", "", ""); try { h.startElement("", "LDC", "", attrs); h.endElement("", "LDC", ""); fail(); } catch (SAXException e) { } } public void testInvalidValue() { methodSetUp(); AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "desc", "desc", "", "Ljava/lang/String;"); attrs.addAttribute("", "cst", "cst", "", "\\"); try { h.startElement("", "LDC", "", attrs); h.endElement("", "LDC", ""); fail(); } catch (SAXException e) { } } public void testIOException() { cv.visitEnd(); try { h.endDocument(); } catch (SAXException e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/xml/SAXAdapterTest.java0000644000175000017500000000736210452754520024445 0ustar twernertwerner/*** * ASM XML Adapter * Copyright (c) 2004, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.ByteArrayOutputStream; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; /** * SAXAdapter tests * * @author Eugene Kuleshov */ public class SAXAdapterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new SAXAdapterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ByteArrayOutputStream bos = new ByteArrayOutputStream(); SAXTransformerFactory saxtf = (SAXTransformerFactory) TransformerFactory.newInstance(); TransformerHandler handler = saxtf.newTransformerHandler(); handler.setResult(new SAXResult(new ASMContentHandler(bos, false))); handler.startDocument(); cr.accept(new SAXClassAdapter(handler, false), 0); handler.endDocument(); ClassWriter cw = new ClassWriter(0); cr.accept(cw, new Attribute[] { new Attribute("Comment") { protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return null; // skip these attributes } }, new Attribute("CodeComment") { protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return null; // skip these attributes } } }, 0); assertEquals(new ClassReader(cw.toByteArray()), new ClassReader(bos.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterResizeInsnsTest.java0000644000175000017500000001543511224532001026332 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; import java.util.HashSet; import org.objectweb.asm.attrs.CodeComment; import junit.framework.TestSuite; public class ClassWriterResizeInsnsTest extends AbstractTest { public static void premain( final String agentArgs, final Instrumentation inst) { inst.addTransformer(new ClassFileTransformer() { public byte[] transform( final ClassLoader loader, final String className, final Class classBeingRedefined, final ProtectionDomain domain, byte[] b) throws IllegalClassFormatException { String n = className.replace('/', '.'); if (agentArgs.length() == 0 || n.indexOf(agentArgs) != -1) { try { b = transformClass(b, ClassWriter.COMPUTE_FRAMES); if (n.equals("pkg.FrameMap")) { transformClass(b, 0); } return b; } catch (Throwable e) { return transformClass(b, 0); } } else { return null; } } }); } static byte[] transformClass(final byte[] clazz, final int flags) { ClassReader cr = new ClassReader(clazz); ClassWriter cw = new ClassWriter(flags) { protected String getCommonSuperClass( final String type1, final String type2) { ClassInfo c, d; try { c = new ClassInfo(type1, getClass().getClassLoader()); d = new ClassInfo(type2, getClass().getClassLoader()); } catch (Throwable e) { throw new RuntimeException(e); } if (c.isAssignableFrom(d)) { return type1; } if (d.isAssignableFrom(c)) { return type2; } if (c.isInterface() || d.isInterface()) { return "java/lang/Object"; } else { do { c = c.getSuperclass(); } while (!c.isAssignableFrom(d)); return c.getType().getInternalName(); } } }; ClassAdapter ca = new ClassAdapter(cw) { boolean transformed = false; public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (flags == ClassWriter.COMPUTE_FRAMES) { version = Opcodes.V1_6; } super.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodAdapter(cv.visitMethod(access, name, desc, signature, exceptions)) { private HashSet labels = new HashSet(); public void visitLabel(final Label label) { super.visitLabel(label); labels.add(label); } public void visitJumpInsn( final int opcode, final Label label) { super.visitJumpInsn(opcode, label); if (opcode != Opcodes.GOTO) { if (!transformed && !labels.contains(label)) { transformed = true; for (int i = 0; i < 33000; ++i) { mv.visitInsn(Opcodes.NOP); } } } } }; } }; cr.accept(ca, new Attribute[] { new CodeComment() }, 0); return cw.toByteArray(); } public static TestSuite suite() throws Exception { return new ClassWriterResizeInsnsTest().getSuite(); } public void test() throws Exception { try { Class.forName(n, true, getClass().getClassLoader()); } catch (NoClassDefFoundError ncdfe) { // ignored } catch (UnsatisfiedLinkError ule) { // ignored } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (VerifyError ve) { fail(ve.toString()); } } } asm-3.3.2/test/conform/org/objectweb/asm/ClassReaderTest.java0000644000175000017500000000377210452754520024102 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestSuite; import org.objectweb.asm.commons.EmptyVisitor; /** * ClassReader tests. * * @author Eric Bruneton */ public class ClassReaderTest extends AbstractTest { public static TestSuite suite() throws Exception { return new ClassReaderTest().getSuite(); } public void test() throws Exception { new ClassReader(is).accept(new EmptyVisitor(), 0); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterComputeMaxsUnitTest.java0000644000175000017500000006061610504156672027204 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import junit.framework.TestCase; import org.objectweb.asm.commons.EmptyVisitor; /** * ClassWriter unit tests for COMPUTE_MAXS option with JSR instructions. * * @author Eric Bruneton */ public class ClassWriterComputeMaxsUnitTest extends TestCase { private Field successors; private Field successor; private Field succ; private Field next; protected ClassWriter cw; protected MethodVisitor mv; private Label start; protected void setUp() throws Exception { Class lClass = Label.class; Class eClass = Edge.class; try { successors = lClass.getDeclaredField("successors"); successor = lClass.getDeclaredField("successor"); succ = eClass.getDeclaredField("successor"); next = eClass.getDeclaredField("next"); } catch (Exception exception) { String f = "src/org/objectweb/asm/optimizer/shrink.properties"; Properties p = new Properties(); p.load(new FileInputStream(f)); String l = Type.getInternalName(lClass) + "."; String e = Type.getInternalName(eClass) + "."; successors = lClass.getDeclaredField(p.getProperty(l + "successors")); successor = lClass.getDeclaredField(p.getProperty(l + "successor")); succ = eClass.getDeclaredField(p.getProperty(e + "successor")); next = eClass.getDeclaredField(p.getProperty(e + "next")); } cw = new ClassWriter(isComputeMaxs() ? ClassWriter.COMPUTE_MAXS : 0); cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", null, null); mv.visitCode(); start = new Label(); LABEL(start); } protected boolean isComputeMaxs() { return true; } private void NOP() { mv.visitInsn(Opcodes.NOP); } private void PUSH() { mv.visitInsn(Opcodes.ICONST_0); } private void ICONST_0() { mv.visitInsn(Opcodes.ICONST_0); } private void ISTORE(final int var) { mv.visitVarInsn(Opcodes.ISTORE, var); } private void ALOAD(final int var) { mv.visitVarInsn(Opcodes.ALOAD, var); } private void ILOAD(final int var) { mv.visitVarInsn(Opcodes.ILOAD, var); } private void ASTORE(final int var) { mv.visitVarInsn(Opcodes.ASTORE, var); } private void RET(final int var) { mv.visitVarInsn(Opcodes.RET, var); } private void ATHROW() { mv.visitInsn(Opcodes.ATHROW); } private void ACONST_NULL() { mv.visitInsn(Opcodes.ACONST_NULL); } private void RETURN() { mv.visitInsn(Opcodes.RETURN); } private void LABEL(final Label l) { mv.visitLabel(l); } private void IINC(final int var, final int amnt) { mv.visitIincInsn(var, amnt); } private void GOTO(final Label l) { mv.visitJumpInsn(Opcodes.GOTO, l); } private void JSR(final Label l) { mv.visitJumpInsn(Opcodes.JSR, l); } private void IFNONNULL(final Label l) { mv.visitJumpInsn(Opcodes.IFNONNULL, l); } private void IFNE(final Label l) { mv.visitJumpInsn(Opcodes.IFNE, l); } private void TRYCATCH( final Label start, final Label end, final Label handler) { mv.visitTryCatchBlock(start, end, handler, null); } protected void assertMaxs(final int maxStack, final int maxLocals) { mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); byte[] b = cw.toByteArray(); ClassReader cr = new ClassReader(b); cr.accept(new EmptyVisitor() { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (name.equals("m")) { return new EmptyVisitor() { public void visitMaxs( final int realMaxStack, final int realMaxLocals) { assertEquals("maxStack", maxStack, realMaxStack); assertEquals("maxLocals", maxLocals, realMaxLocals); } }; } else { return new EmptyVisitor(); } } }, 0); try { TestClassLoader loader = new TestClassLoader(); Class c = loader.defineClass("C", b); c.newInstance(); } catch (Throwable t) { fail(t.getMessage()); } } protected void assertGraph(final String graph) { Map expected = new HashMap(); Properties p = new Properties(); try { p.load(new ByteArrayInputStream(graph.getBytes())); } catch (Exception e) { fail(); } Iterator i = p.keySet().iterator(); while (i.hasNext()) { String key = (String) i.next(); String value = p.getProperty(key); StringTokenizer st = new StringTokenizer(value, ","); Set s = new HashSet(); while (st.hasMoreTokens()) { s.add(st.nextToken()); } expected.put(key, s); } Map actual = new HashMap(); try { Label l = start; while (l != null) { String key = "N" + l.getOffset(); Set value = new HashSet(); Edge e = (Edge) successors.get(l); while (e != null) { value.add("N" + ((Label) succ.get(e)).getOffset()); e = (Edge) next.get(e); } actual.put(key, value); l = (Label) successor.get(l); } } catch (Exception e) { fail(); } assertEquals(expected, actual); } protected static class TestClassLoader extends ClassLoader { public TestClassLoader() { } public Class defineClass(final String name, final byte[] b) { return defineClass(name, b, 0, b.length); } } /** * Tests a method which has the most basic try{}finally form * imaginable: * *

     *   public void a() {
     *     int a = 0;
     *     try {
     *       a++;
     *     } finally {
     *       a--;
     *     }
     *   }
     * 
*/ public void testBasic() { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); ICONST_0(); // N0 ISTORE(1); /* L0: body of try block */ LABEL(L0); // N2 IINC(1, 1); GOTO(L1); /* L2: exception handler */ LABEL(L2); // N8 ASTORE(3); JSR(L3); ALOAD(3); // N12 ATHROW(); /* L3: subroutine */ LABEL(L3); // N14 ASTORE(2); IINC(1, -1); PUSH(); PUSH(); RET(2); /* L1: non-exceptional exit from try block */ LABEL(L1); // N22 JSR(L3); PUSH(); // N25 PUSH(); LABEL(L4); // N27 RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L4, L2); assertMaxs(4, 4); assertGraph("N0=N2\n" + "N2=N22,N8\n" + "N8=N14,N12\n" + "N12=\n" + "N14=N12,N25\n" + "N22=N14,N25,N8\n" + "N25=N27,N8\n" + "N27=\n"); } /** * Tests a method which has an if/else-if w/in the finally clause: * *
     *   public void a() {
     *     int a = 0;
     *     try {
     *       a++;
     *     } finally {
     *       if (a == 0)
     *         a+=2;
     *       else
     *         a+=3;
     *     }
     *   }
     * 
*/ public void testIfElseInFinally() { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); Label L6 = new Label(); ICONST_0(); // N0 ISTORE(1); /* L0: body of try block */ LABEL(L0); // N2 IINC(1, 1); GOTO(L1); /* L2: exception handler */ LABEL(L2); // N8 ASTORE(3); JSR(L3); PUSH(); // N12 PUSH(); ALOAD(3); ATHROW(); /* L3: subroutine */ LABEL(L3); // N16 ASTORE(2); PUSH(); PUSH(); ILOAD(1); IFNE(L4); IINC(1, 2); GOTO(L5); LABEL(L4); // N29 IINC(1, 3); LABEL(L5); // N32 common exit RET(2); /* L1: non-exceptional exit from try block */ LABEL(L1); // N34 JSR(L3); LABEL(L6); // N37 RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L1, L6, L2); assertMaxs(5, 4); assertGraph("N0=N2\n" + "N2=N34,N8\n" + "N8=N16,N12\n" + "N12=\n" + "N16=N29,N32\n" + "N29=N32\n" + "N32=N37,N12\n" + "N34=N16,N37,N8\n" + "N37=\n"); } /** * Tests a simple nested finally: * *
     * public void a1() {
     *   int a = 0;
     *   try {
     *     a += 1;
     *   } finally {
     *     try {
     *       a += 2;
     *     } finally {
     *       a += 3;
     *     }
     *   }
     * }
     * 
*/ public void testSimpleNestedFinally() { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); ICONST_0(); // N0 ISTORE(1); // L0: Body of try block: LABEL(L0); // N2 IINC(1, 1); JSR(L3); GOTO(L1); // N8 // L2: First exception handler: LABEL(L2); // N11 ASTORE(4); JSR(L3); ALOAD(4); // N16 ATHROW(); // L3: First subroutine: LABEL(L3); // N19 ASTORE(2); IINC(1, 2); JSR(L4); PUSH(); // N26 PUSH(); RET(2); // L5: Second exception handler: LABEL(L5); // N30 ASTORE(5); JSR(L4); ALOAD(5); // N35 ATHROW(); // L4: Second subroutine: LABEL(L4); // N38 ASTORE(3); PUSH(); PUSH(); IINC(1, 3); RET(3); // L1: On normal exit, try block jumps here: LABEL(L1); // N46 RETURN(); TRYCATCH(L0, L2, L2); TRYCATCH(L3, L5, L5); assertMaxs(5, 6); assertGraph("N0=N2\n" + "N2=N11,N19,N8\n" + "N8=N11,N46\n" + "N11=N19,N16\n" + "N16=\n" + "N19=N26,N30,N38\n" + "N26=N16,N30,N8\n" + "N30=N38,N35\n" + "N35=\n" + "N38=N26,N35\n" + "N46=\n"); } /** * This tests a subroutine which has no ret statement, but ends in a * "return" instead. * * We structure this as a try/finally with a break in the finally. Because * the while loop is infinite, it's clear from the byte code that the only * path which reaches the RETURN instruction is through the subroutine. * *
     * public void a1() {
     *   int a = 0;
     *   while (true) {
     *     try {
     *       a += 1;
     *     } finally {
     *       a += 2;
     *       break;
     *     }
     *   }
     * }
     * 
*/ public void testSubroutineWithNoRet() { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); ICONST_0(); // N0 ISTORE(1); // L0: while loop header/try block LABEL(L0); // N2 IINC(1, 1); JSR(L1); GOTO(L2); // N8 // L3: implicit catch block LABEL(L3); // N11 ASTORE(2); JSR(L1); PUSH(); // N15 PUSH(); ALOAD(2); ATHROW(); // L1: subroutine ... LABEL(L1); // N19 ASTORE(3); IINC(1, 2); GOTO(L4); // ...not that it does not return! // L2: end of the loop... goes back to the top! LABEL(L2); // N26 GOTO(L0); // L4: LABEL(L4); // N29 RETURN(); TRYCATCH(L0, L3, L3); assertMaxs(1, 4); assertGraph("N0=N2\n" + "N2=N11,N19,N8\n" + "N8=N11,N26\n" + "N11=N19,N15\n" + "N15=\n" + "N19=N29\n" + "N26=N2\n" + "N29=\n"); } /** * This tests a subroutine which has no ret statement, but ends in a * "return" instead. * *
     *   ACONST_NULL
     *   JSR L0
     * L0:
     *   ASTORE 0 
     *   ASTORE 0
     *   RETURN 
     * 
*/ public void testSubroutineWithNoRet2() { Label L0 = new Label(); Label L1 = new Label(); ACONST_NULL(); // N0 JSR(L0); NOP(); // N4 LABEL(L0); // N5 ASTORE(0); ASTORE(0); RETURN(); LABEL(L1); // N8 mv.visitLocalVariable("i", "I", null, L0, L1, 1); assertMaxs(2, 2); assertGraph("N0=N4,N5\n" + "N4=N5\n" + "N5=\n" + "N8=\n"); } /** * This tests a subroutine which has no ret statement, but instead exits * implicitely by branching to code which is not part of the subroutine. * (Sadly, this is legal) * * We structure this as a try/finally in a loop with a break in the finally. * The loop is not trivially infinite, so the RETURN statement is reachable * both from the JSR subroutine and from the main entry point. * *
     * public void a1() {
     *   int a = 0;
     *   while (null == null) {
     *     try {
     *       a += 1;
     *     } finally {
     *       a += 2;
     *       break;
     *     }
     *   }
     * }
     * 
*/ public void testImplicitExit() { Label L0 = new Label(); Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); Label L5 = new Label(); ICONST_0(); // N0 ISTORE(1); // L5: while loop header LABEL(L5); // N2 ACONST_NULL(); IFNONNULL(L4); // L0: try block LABEL(L0); // N6 IINC(1, 1); JSR(L1); GOTO(L2); // N12 // L3: implicit catch block LABEL(L3); // N15 ASTORE(2); JSR(L1); ALOAD(2); // N19 PUSH(); PUSH(); ATHROW(); // L1: subroutine ... LABEL(L1); // N23 ASTORE(3); IINC(1, 2); GOTO(L4); // ...not that it does not return! // L2: end of the loop... goes back to the top! LABEL(L2); // N30 GOTO(L0); // L4: LABEL(L4); // N33 RETURN(); TRYCATCH(L0, L3, L3); assertMaxs(1, 4); assertGraph("N0=N2\n" + "N2=N6,N33\n" + "N6=N23,N12,N15\n" + "N12=N30,N15\n" + "N15=N23,N19\n" + "N19=\n" + "N23=N33\n" + "N30=N6\n" + "N33=\n"); } /** * Tests a nested try/finally with implicit exit from one subroutine to the * other subroutine. Equivalent to the following java code: * *
     * void m(boolean b) {
     *   try {
     *     return;
     *   } finally {
     *     while (b) {
     *       try {
     *         return;
     *       } finally {
     *         // NOTE --- this break avoids the second return above (weird)
     *         if (b) break;
     *       }
     *     }
     *   }
     * }
     * 
* * This example is from the paper, "Subroutine Inlining and Bytecode * Abstraction to Simplify Static and Dynamic Analysis" by Cyrille Artho and * Armin Biere. */ public void testImplicitExitToAnotherSubroutine() { Label T1 = new Label(); Label C1 = new Label(); Label S1 = new Label(); Label L = new Label(); Label C2 = new Label(); Label S2 = new Label(); Label W = new Label(); Label X = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; ICONST_0(); // N0 ISTORE(1); // T1: first try: LABEL(T1); // N2 JSR(S1); RETURN(); // N5 // C1: exception handler for first try LABEL(C1); // N6 ASTORE(e1); JSR(S1); PUSH(); // N10 PUSH(); ALOAD(e1); ATHROW(); // S1: first finally handler LABEL(S1); // N14 ASTORE(r1); PUSH(); PUSH(); GOTO(W); // L: body of while loop, also second try LABEL(L); // N21 JSR(S2); RETURN(); // N24 // C2: exception handler for second try LABEL(C2); // N25 ASTORE(e2); PUSH(); PUSH(); JSR(S2); ALOAD(e2); // N31 ATHROW(); // S2: second finally handler LABEL(S2); // N33 ASTORE(r2); ILOAD(b); IFNE(X); RET(r2); // W: test for the while loop LABEL(W); // N41 ILOAD(b); IFNE(L); // falls through to X // X: exit from finally{} block LABEL(X); // N45 RET(r1); TRYCATCH(T1, C1, C1); TRYCATCH(L, C2, C2); assertMaxs(5, 6); assertGraph("N0=N2\n" + "N2=N6,N5,N14\n" + "N5=N6\n" + "N6=N14,N10\n" + "N10=\n" + "N14=N41\n" + "N21=N24,N25,N33\n" + "N24=N25\n" + "N25=N31,N33\n" + "N31=\n" + "N33=N31,N45,N24\n" + "N41=N45,N21\n" + "N45=N5,N10\n"); } public void testImplicitExitToAnotherSubroutine2() { Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); ICONST_0(); // N0 ISTORE(1); JSR(L1); RETURN(); // N5 LABEL(L1); // N6 ASTORE(2); JSR(L2); GOTO(L3); // N10 LABEL(L2); // N13 ASTORE(3); ILOAD(1); IFNE(L3); RET(3); LABEL(L3); // N20 RET(2); assertMaxs(1, 4); assertGraph("N0=N6,N5\n" + "N5=\n" + "N6=N10,N13\n" + "N10=N20\n" + "N13=N20,N10\n" + "N20=N5\n"); } /** * This tests a simple subroutine where the control flow jumps back and * forth between the subroutine and the caller. * * This would not normally be produced by a java compiler. */ public void testInterleavedCode() { Label L1 = new Label(); Label L2 = new Label(); Label L3 = new Label(); Label L4 = new Label(); ICONST_0(); // N0 ISTORE(1); JSR(L1); GOTO(L2); // N5 // L1: subroutine 1 LABEL(L1); // N8 ASTORE(2); IINC(1, 1); GOTO(L3); // L2: second part of main subroutine LABEL(L2); // N15 IINC(1, 2); GOTO(L4); // L3: second part of subroutine 1 LABEL(L3); // N21 IINC(1, 4); PUSH(); PUSH(); RET(2); // L4: third part of main subroutine LABEL(L4); // N28 PUSH(); PUSH(); RETURN(); assertMaxs(4, 3); assertGraph("N0=N5,N8\n" + "N5=N15\n" + "N8=N21\n" + "N15=N28\n" + "N21=N5\n" + "N28=\n"); } /** * Tests a nested try/finally with implicit exit from one subroutine to the * other subroutine, and with a surrounding try/catch thrown in the mix. * Equivalent to the following java code: * *
     * void m(int b) {
     *   try {
     *     try {
     *       return;
     *     } finally {
     *       while (b) {
     *         try {
     *           return;
     *         } finally {
     *           // NOTE --- this break avoids the second return above (weird)
     *           if (b) break;
     *         }
     *       }
     *     } 
     *   } catch (Exception e) {
     *     b += 3;
     *     return;
     *   }
     * }
     * 
*/ public void testImplicitExitInTryCatch() { Label T1 = new Label(); Label C1 = new Label(); Label S1 = new Label(); Label L = new Label(); Label C2 = new Label(); Label S2 = new Label(); Label W = new Label(); Label X = new Label(); Label OC = new Label(); // variable numbers: int b = 1; int e1 = 2; int e2 = 3; int r1 = 4; int r2 = 5; ICONST_0(); // N0 ISTORE(1); // T1: first try: LABEL(T1); // N2 JSR(S1); RETURN(); // N5 // C1: exception handler for first try LABEL(C1); // N6 ASTORE(e1); JSR(S1); ALOAD(e1); // N10 ATHROW(); // S1: first finally handler LABEL(S1); // N12 ASTORE(r1); GOTO(W); // L: body of while loop, also second try LABEL(L); // N17 JSR(S2); PUSH(); // N20 PUSH(); RETURN(); // C2: exception handler for second try LABEL(C2); // N23 ASTORE(e2); JSR(S2); ALOAD(e2); // N27 ATHROW(); // S2: second finally handler LABEL(S2); // N29 ASTORE(r2); ILOAD(b); IFNE(X); PUSH(); PUSH(); RET(r2); // W: test for the while loop LABEL(W); // N39 ILOAD(b); IFNE(L); // falls through to X // X: exit from finally{} block LABEL(X); // N43 RET(r1); // OC: outermost catch LABEL(OC); // N45 IINC(b, 3); RETURN(); TRYCATCH(T1, C1, C1); TRYCATCH(L, C2, C2); TRYCATCH(T1, OC, OC); assertMaxs(4, 6); assertGraph("N0=N2\n" + "N2=N6,N45,N5,N12\n" + "N5=N6,N45\n" + "N6=N45,N12,N10\n" + "N10=N45\n" + "N12=N39,N45\n" + "N17=N23,N45,N20,N29\n" + "N20=N23,N45\n" + "N23=N45,N27,N29\n" + "N27=N45\n" + "N29=N43,N45,N20,N27\n" + "N39=N43,N45,N17\n" + "N43=N45,N5,N10\n" + "N45=\n"); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterCopyPoolTest.java0000644000175000017500000000561110452754520025633 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestSuite; /** * ClassWriter tests for copyPool() optimization. * * @author Eugene Kuleshov */ public class ClassWriterCopyPoolTest extends AbstractTest { public static TestSuite suite() throws Exception { return new ClassWriterCopyPoolTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw1 = new ClassWriter(0); ClassWriter cw2 = new ClassWriter(cr, 0); cr.accept(new ChangeExceptionAdapter(cw1), 0); cr.accept(new ChangeExceptionAdapter(cw2), 0); assertEquals(new ClassReader(cw1.toByteArray()), new ClassReader(cw2.toByteArray())); } static class ChangeExceptionAdapter extends ClassAdapter { public ChangeExceptionAdapter(final ClassVisitor cv) { super(cv); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (exceptions != null && exceptions.length > 0) { exceptions[0] = "java/lang/Throwable"; } return super.visitMethod(access, name, desc, signature, exceptions); } } } asm-3.3.2/test/conform/org/objectweb/asm/AttributeUnitTest.java0000644000175000017500000000352010452754520024504 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestCase; /** * Attribute unit tests. * * @author Eric Bruneton */ public class AttributeUnitTest extends TestCase { public void testUnknown() { assertTrue(new Attribute("Comment").isUnknown()); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterComputeMaxsTest.java0000644000175000017500000000427310452754520026337 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestSuite; /** * ClassWriter tests. * * @author Eric Bruneton */ public class ClassWriterComputeMaxsTest extends AbstractTest { public static TestSuite suite() throws Exception { return new ClassWriterComputeMaxsTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cr.accept(cw, 0); // computed maxStack and maxLocals may differ from original class // assertEquals(cr, new ClassReader(cw.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/LabelUnitTest.java0000644000175000017500000000450210452754520023561 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestCase; /** * Label unit tests. * * @author Eric Bruneton */ public class LabelUnitTest extends TestCase { public void testToString() { new Label().toString(); } public void testGetOffset() { Label l = new Label(); ClassWriter cw = new ClassWriter(0); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", null, null); mv.visitCode(); mv.visitLabel(l); assertEquals(0, l.getOffset()); } public void testIllegalGetOffsetState() { try { new Label().getOffset(); fail(); } catch (RuntimeException e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/TypeUnitTest.java0000644000175000017500000001157310510363126023462 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; import junit.framework.TestCase; /** * Type unit tests. * * @author Eric Bruneton */ public class TypeUnitTest extends TestCase implements Opcodes { public void testConstants() { assertEquals(Type.INT_TYPE, Type.getType(Integer.TYPE)); assertEquals(Type.VOID_TYPE, Type.getType(Void.TYPE)); assertEquals(Type.BOOLEAN_TYPE, Type.getType(Boolean.TYPE)); assertEquals(Type.BYTE_TYPE, Type.getType(Byte.TYPE)); assertEquals(Type.CHAR_TYPE, Type.getType(Character.TYPE)); assertEquals(Type.SHORT_TYPE, Type.getType(Short.TYPE)); assertEquals(Type.DOUBLE_TYPE, Type.getType(Double.TYPE)); assertEquals(Type.FLOAT_TYPE, Type.getType(Float.TYPE)); assertEquals(Type.LONG_TYPE, Type.getType(Long.TYPE)); } public void testInternalName() { String s1 = Type.getType(TypeUnitTest.class).getInternalName(); String s2 = Type.getInternalName(TypeUnitTest.class); assertEquals(s1, s2); } public void testConstructorDescriptor() { for (int i = 0; i < String.class.getConstructors().length; ++i) { Constructor c = String.class.getConstructors()[i]; Type.getConstructorDescriptor(c); } } public void testMethodDescriptor() { for (int i = 0; i < Arrays.class.getMethods().length; ++i) { Method m = Arrays.class.getMethods()[i]; Type[] args = Type.getArgumentTypes(m); Type r = Type.getReturnType(m); String d1 = Type.getMethodDescriptor(r, args); String d2 = Type.getMethodDescriptor(m); assertEquals(d1, d2); } } public void testGetOpcode() { Type object = Type.getType("Ljava/lang/Object;"); assertEquals(BALOAD, Type.BOOLEAN_TYPE.getOpcode(IALOAD)); assertEquals(BALOAD, Type.BYTE_TYPE.getOpcode(IALOAD)); assertEquals(CALOAD, Type.CHAR_TYPE.getOpcode(IALOAD)); assertEquals(SALOAD, Type.SHORT_TYPE.getOpcode(IALOAD)); assertEquals(IALOAD, Type.INT_TYPE.getOpcode(IALOAD)); assertEquals(FALOAD, Type.FLOAT_TYPE.getOpcode(IALOAD)); assertEquals(LALOAD, Type.LONG_TYPE.getOpcode(IALOAD)); assertEquals(DALOAD, Type.DOUBLE_TYPE.getOpcode(IALOAD)); assertEquals(AALOAD, object.getOpcode(IALOAD)); assertEquals(IADD, Type.BOOLEAN_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.BYTE_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.CHAR_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.SHORT_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.INT_TYPE.getOpcode(IADD)); assertEquals(FADD, Type.FLOAT_TYPE.getOpcode(IADD)); assertEquals(LADD, Type.LONG_TYPE.getOpcode(IADD)); assertEquals(DADD, Type.DOUBLE_TYPE.getOpcode(IADD)); } public void testHashcode() { Type.getType("Ljava/lang/Object;").hashCode(); } public void testObjectType() throws Exception { Type t1 = Type.getObjectType("java/lang/Object"); Type t2 = Type.getType("Ljava/lang/Object;"); assertEquals(t2.getSort(), t1.getSort()); assertEquals(t2.getClassName(), t1.getClassName()); assertEquals(t2.getDescriptor(), t1.getDescriptor()); } } asm-3.3.2/test/conform/org/objectweb/asm/test/0000755000175000017500000000000011633370174021156 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/test/cases/0000755000175000017500000000000011633370174022254 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/test/cases/Wide.java0000644000175000017500000001033510507622260024004 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * Generates a class which uses a lot of locals and constant pool values. Covers * the 'wide' form of instructions that have one (xLOAD and xSTORE, LDC, IINC, * GOTO and IF instructions - these jump instructions are not directly generated * in their 'wide' form, but are transformed to this form by the method resizing * test). Also covers the V1_2 class version. * * @author Eric Bruneton */ public class Wide extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Wide.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; cw.visit(V1_2, ACC_PUBLIC, "pkg/Wide", null, "java/lang/Object", null); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); for (int i = 0; i < 256; ++i) { mv.visitLdcInsn(Integer.toString(i)); // wide form mv.visitInsn(POP); } mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "wideLocals", "(I)I", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); // will give GOTO_W mv.visitLabel(l0); mv.visitIincInsn(300, 1); // covers 'update maxlocals' in MethodWriter mv.visitVarInsn(ILOAD, 300); // will give wide form mv.visitJumpInsn(IFEQ, l1); // will give long forward jump // many NOPs will be introduced here by the method resizing test mv.visitVarInsn(ILOAD, 300); // will give wide form mv.visitInsn(IRETURN); mv.visitLabel(l1); for (int i = 1; i < 300; ++i) { mv.visitVarInsn(ILOAD, i); if (i <= 5) { mv.visitInsn(ICONST_0 + i); } else if (i <= Byte.MAX_VALUE) { mv.visitIntInsn(BIPUSH, i); } else { mv.visitIntInsn(SIPUSH, i); } mv.visitInsn(IADD); mv.visitVarInsn(ISTORE, i + 1); } mv.visitInsn(ICONST_0); mv.visitJumpInsn(IFEQ, l0); // will give long backward jump mv.visitJumpInsn(GOTO, l0); // will give long backward goto mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Frames.java0000644000175000017500000007273610452754520024352 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; /** * Generates classes with StackMap and StackMapTable attributes. Covers all * frame (FULL, SAME, etc.) and frame element types (TOP, NULL, INTEGER, etc.). * Also covers the V1_6 class version. * * @author Eric Bruneton */ public class Frames extends Generator { final static int M = ACC_STATIC; final static String I1 = "Ljava/io/Serializable;"; final static String I2 = "Ljava/lang/Comparable;"; public void generate(final String dir) throws IOException { byte[] b = dump(); ClassWriter cw = new ClassWriter(0); ClassReader cr = new ClassReader(b); cr.accept(new RenameAdapter(cw), ClassReader.EXPAND_FRAMES); generate(dir, "pkg/FrameTable.class", b); generate(dir, "pkg/FrameMap.class", cw.toByteArray()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; FieldVisitor fv; cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "pkg/FrameTable", null, "java/lang/Object", null); fv = cw.visitField(M, "long", "Ljava/lang/Long;", null, null); fv.visitEnd(); fv = cw.visitField(M, "double", "Ljava/lang/Double;", null, null); fv.visitEnd(); fv = cw.visitField(M, "number", "Ljava/lang/Number;", null, null); fv.visitEnd(); fv = cw.visitField(M, "serializable", I1, null, null); fv.visitEnd(); fv = cw.visitField(M, "comparable", I2, null, null); fv.visitEnd(); fv = cw.visitField(M, "longArray", "[Ljava/lang/Long;", null, null); fv.visitEnd(); fv = cw.visitField(M, "intArray", "[I", null, null); fv.visitEnd(); fv = cw.visitField(M, "floatArray", "[F", null, null); fv.visitEnd(); fv = cw.visitField(M, "objectArray", "[Ljava/lang/Object;", null, null); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "", "(Ljava/lang/Object;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); uninitializedThisType(cw); uninitializedLocalType(cw); uninitializedStackType(cw); nullType(cw); topType(cw); arrayTypes(cw); mergeTypes(cw); mergeStackTypes(cw); mergeNullArray(cw); appendAndChopFrame(cw); sameLocals1stackItemFrame(cw); sameLocals1stackItemFrame2(cw); sameLocals1stackItemFrameExtended(cw); sameFrameExtended(cw); deadCode(cw); cw.visitEnd(); return cw.toByteArray(); } private void uninitializedThisType(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "(I)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, "pkg/FrameTable"); mv.visitInsn(DUP); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IFNE, l1); mv.visitInsn(ACONST_NULL); Label l2 = new Label(); mv.visitJumpInsn(GOTO, l2); mv.visitFrame(F_FULL, 2, new Object[] { UNINITIALIZED_THIS, INTEGER }, 3, new Object[] { UNINITIALIZED_THIS, l0, l0 }); mv.visitLabel(l1); mv.visitTypeInsn(NEW, "java/lang/Object"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitFrame(F_FULL, 2, new Object[] { UNINITIALIZED_THIS, INTEGER }, 4, new Object[] { UNINITIALIZED_THIS, l0, l0, "java/lang/Object" }); mv.visitLabel(l2); mv.visitMethodInsn(INVOKESPECIAL, "pkg/FrameTable", "", "(Ljava/lang/Object;)V"); mv.visitMethodInsn(INVOKESPECIAL, "pkg/FrameTable", "", "(Ljava/lang/Object;)V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void uninitializedLocalType(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "uninitializedLocalType", "(Z)V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, "java/lang/Long"); mv.visitVarInsn(ASTORE, 2); mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IFEQ, l1); mv.visitInsn(LCONST_0); Label l2 = new Label(); mv.visitJumpInsn(GOTO, l2); mv.visitFrame(F_FULL, 3, new Object[] { "pkg/FrameTable", INTEGER, l0 }, 1, new Object[] { l0 }); mv.visitLabel(l1); mv.visitInsn(LCONST_1); mv.visitFrame(F_FULL, 3, new Object[] { "pkg/FrameTable", INTEGER, l0 }, 2, new Object[] { l0, LONG }); mv.visitLabel(l2); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Long", "", "(J)V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void uninitializedStackType(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "uninitializedStackType", "(Z)V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, "java/lang/Long"); mv.visitInsn(DUP); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IFEQ, l1); mv.visitInsn(LCONST_0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Long", "", "(J)V"); Label l2 = new Label(); mv.visitJumpInsn(GOTO, l2); mv.visitFrame(F_FULL, 1, new Object[] { "pkg/FrameTable" }, 2, new Object[] { l0, l0 }); mv.visitLabel(l1); mv.visitInsn(LCONST_1); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Long", "", "(J)V"); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Long" }); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void nullType(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "nullType", "(Ljava/lang/String;Ljava/lang/String;)V", null, null); mv.visitCode(); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 2); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ALOAD, 1); Label l0 = new Label(); mv.visitJumpInsn(IFNONNULL, l0); mv.visitVarInsn(ALOAD, 2); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); mv.visitFrame(F_FULL, 3, new Object[] { "pkg/FrameTable", "java/lang/String", NULL }, 2, new Object[] { "pkg/FrameTable", NULL }); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 1); mv.visitFrame(F_FULL, 3, new Object[] { "pkg/FrameTable", "java/lang/String", NULL }, 3, new Object[] { "pkg/FrameTable", NULL, "java/lang/String" }); mv.visitLabel(l1); mv.visitMethodInsn(INVOKEVIRTUAL, "pkg/FrameTable", "nullType", "(Ljava/lang/String;Ljava/lang/String;)V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void topType(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "topType", "(ZBCSIFJDLjava/lang/Object;)V", null, null); mv.visitCode(); mv.visitVarInsn(ILOAD, 5); mv.visitVarInsn(ISTORE, 13); mv.visitVarInsn(ILOAD, 1); Label l0 = new Label(); mv.visitJumpInsn(IFEQ, l0); mv.visitInsn(RETURN); mv.visitFrame(F_APPEND, 2, new Object[] { TOP, INTEGER }, 0, null); mv.visitLabel(l0); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void arrayTypes(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "fullFrame", "(Ljava/lang/String;[[Z[B[C[S[I[F[J[D[Ljava/lang/Object;)V", null, null); mv.visitCode(); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 11); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 13); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 15); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 17); mv.visitVarInsn(ALOAD, 1); Label l0 = new Label(); mv.visitJumpInsn(IFNONNULL, l0); mv.visitInsn(RETURN); mv.visitFrame(F_FULL, 15, new Object[] { "pkg/FrameTable", "java/lang/String", "[[Z", "[B", "[C", "[S", "[I", "[F", "[J", "[D", "[Ljava/lang/Object;", LONG, LONG, LONG, LONG }, 0, new Object[] {}); mv.visitLabel(l0); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void mergeTypes(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "mergeTypes", "(Z)V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "long", "Ljava/lang/Long;"); mv.visitVarInsn(ASTORE, 2); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "number", "Ljava/lang/Number;"); mv.visitVarInsn(ASTORE, 3); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "number", "Ljava/lang/Long;"); mv.visitVarInsn(ASTORE, 4); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "comparable", "Ljava/lang/Comparable;"); mv.visitVarInsn(ASTORE, 5); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 6); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "double", "Ljava/lang/Double;"); mv.visitVarInsn(ASTORE, 7); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 8); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "intArray", "[I"); mv.visitVarInsn(ASTORE, 9); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "double", "Ljava/lang/Double;"); mv.visitVarInsn(ASTORE, 10); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 11); mv.visitFrame(F_FULL, 12, new Object[] { "pkg/FrameTable", INTEGER, "java/lang/Number", "java/lang/Number", "java/lang/Number", "java/lang/Object", NULL, "java/lang/Double", TOP, "java/lang/Object", "java/lang/Object", "[Ljava/lang/Object;" }, 0, null); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 11); mv.visitInsn(ICONST_0); mv.visitInsn(ACONST_NULL); mv.visitInsn(AASTORE); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "double", "Ljava/lang/Double;"); mv.visitVarInsn(ASTORE, 2); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "double", "Ljava/lang/Double;"); mv.visitVarInsn(ASTORE, 3); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "number", "Ljava/lang/Number;"); mv.visitVarInsn(ASTORE, 4); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "serializable", "Ljava/io/Serializable;"); mv.visitVarInsn(ASTORE, 5); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 6); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 7); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 8); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "floatArray", "[F"); mv.visitVarInsn(ASTORE, 9); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "intArray", "[I"); mv.visitVarInsn(ASTORE, 10); mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitVarInsn(ASTORE, 11); mv.visitJumpInsn(GOTO, l0); mv.visitMaxs(0, 0); mv.visitEnd(); } private void mergeStackTypes(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "mergeStackTypes", "(Z)V", null, null); mv.visitCode(); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_1); mv.visitVarInsn(ILOAD, 1); Label l0 = new Label(); mv.visitJumpInsn(IFEQ, l0); mv.visitInsn(ICONST_0); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); mv.visitFrame(F_FULL, 1, new Object[] { "pkg/FrameTable" }, 2, new Object[] { INTEGER, INTEGER }); mv.visitLabel(l0); mv.visitInsn(DUP); mv.visitFrame(F_FULL, 1, new Object[] { "pkg/FrameTable" }, 3, new Object[] { INTEGER, INTEGER, INTEGER }); mv.visitLabel(l1); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void mergeNullArray(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "mergeNullArray", "(Z)I", null, null); mv.visitCode(); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IFEQ, l1); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 2); mv.visitVarInsn(ILOAD, 1); Label l2 = new Label(); mv.visitJumpInsn(IFEQ, l2); mv.visitFieldInsn(GETSTATIC, "pkg/FrameTable", "longArray", "[Ljava/lang/Long;"); mv.visitVarInsn(ASTORE, 2); mv.visitFrame(F_APPEND, 1, new Object[] { "[Ljava/lang/Long;" }, 0, null); mv.visitLabel(l2); mv.visitVarInsn(ALOAD, 2); Label l3 = new Label(); mv.visitJumpInsn(IFNULL, l3); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ARRAYLENGTH); Label l4 = new Label(); mv.visitJumpInsn(IFNE, l4); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l3); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 3); Label l5 = new Label(); mv.visitJumpInsn(GOTO, l5); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l4); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ICONST_0); mv.visitInsn(AALOAD); mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFNE, l5); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 3); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l5); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(IRETURN); mv.visitFrame(F_CHOP, 1, null, 0, null); mv.visitLabel(l1); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(IRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void appendAndChopFrame(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "appendAndChopFrame", "(I)V", null, null); mv.visitCode(); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 2); mv.visitFrame(F_APPEND, 1, new Object[] { INTEGER }, 0, null); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IF_ICMPGE, l1); mv.visitIincInsn(2, 1); mv.visitJumpInsn(GOTO, l0); mv.visitFrame(F_CHOP, 1, null, 0, null); mv.visitLabel(l1); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void sameLocals1stackItemFrame(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "sameLocals1stackItemFrame", "()I", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); mv.visitTryCatchBlock(l0, l1, l0, null); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); mv.visitLabel(l0); mv.visitVarInsn(ASTORE, 1); mv.visitLabel(l1); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void sameLocals1stackItemFrame2(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "sameLocals1stackItemFrame2", "()V", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, null); Label l4 = new Label(); mv.visitTryCatchBlock(l2, l4, l3, null); Label l5 = new Label(); mv.visitTryCatchBlock(l3, l5, l3, null); mv.visitLabel(l0); mv.visitTypeInsn(NEW, "java/lang/Object"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitVarInsn(ASTORE, 1); mv.visitLabel(l1); Label l6 = new Label(); mv.visitJumpInsn(GOTO, l6); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Exception" }); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); mv.visitLabel(l4); mv.visitJumpInsn(GOTO, l6); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 3); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 3); mv.visitInsn(ATHROW); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l6); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void sameLocals1stackItemFrameExtended(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "sameLocals1stackItemFrameExtended", "()I", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, null); Label l3 = new Label(); mv.visitTryCatchBlock(l2, l3, l2, null); mv.visitLabel(l0); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 1); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 3); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 5); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 7); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 9); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 11); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 13); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 15); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 17); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 19); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 21); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 23); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 25); mv.visitLabel(l1); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 27); mv.visitLabel(l3); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void sameFrameExtended(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "sameFrameExtended", "(Z)V", null, null); mv.visitCode(); mv.visitFrame(F_SAME, 0, null, 0, null); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 2); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 4); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 6); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 8); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 10); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 12); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 14); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 16); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 18); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 20); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 22); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 24); mv.visitLdcInsn(new Long(11L)); mv.visitVarInsn(LSTORE, 26); mv.visitVarInsn(ILOAD, 1); Label l1 = new Label(); mv.visitJumpInsn(IFEQ, l1); mv.visitInsn(RETURN); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l1); mv.visitJumpInsn(GOTO, l0); mv.visitMaxs(0, 0); mv.visitEnd(); } private void deadCode(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "deadCode", "(Z)V", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Exception"); mv.visitTryCatchBlock(l2, l3, l3, "java/lang/Exception"); mv.visitJumpInsn(GOTO, l2); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitLabel(l0); mv.visitInsn(RETURN); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Exception" }); mv.visitLabel(l1); mv.visitVarInsn(ASTORE, 2); mv.visitInsn(RETURN); mv.visitFrame(F_FULL, 0, new Object[] { "pkg/FrameTable", INTEGER }, 0, null); mv.visitLabel(l2); mv.visitInsn(RETURN); mv.visitFrame(F_SAME1, 0, null, 1, new Object[] { "java/lang/Exception" }); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 2); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } /** * Ad hoc class adapter used to rename the FrameTable class and to change * its class version. * * @author Eric Bruneton */ static class RenameAdapter extends ClassAdapter { public RenameAdapter(final ClassVisitor cv) { super(cv); } public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { super.visit(V1_5, access, "pkg/FrameMap", signature, superName, interfaces); } public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodAdapter(super.visitMethod(access, name, desc, signature, exceptions)) { public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { Object[] clocal = new Object[local.length]; for (int i = 0; i < clocal.length; ++i) { clocal[i] = local[i]; if ("pkg/FrameTable".equals(clocal[i])) { clocal[i] = "pkg/FrameMap"; } } Object[] cstack = new Object[stack.length]; for (int i = 0; i < cstack.length; ++i) { cstack[i] = stack[i]; if ("pkg/FrameTable".equals(cstack[i])) { cstack[i] = "pkg/FrameMap"; } } super.visitFrame(type, nLocal, clocal, nStack, cstack); } public void visitTypeInsn(final int opcode, final String desc) { if (desc.equals("pkg/FrameTable")) { super.visitTypeInsn(opcode, "pkg/FrameMap"); } else { super.visitTypeInsn(opcode, desc); } } public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc) { if (owner.equals("pkg/FrameTable")) { super.visitMethodInsn(opcode, "pkg/FrameMap", name, desc); } else { super.visitMethodInsn(opcode, owner, name, desc); } } }; } } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Debug.java0000644000175000017500000000711010452754520024143 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * Generates a class with debug information. Covers line number tables, local * variable tables, source file, source debug, etc. Also covers the * serialVersionUID field (to cover a branch in SerialVersionUIDAdder). * * @author Eric Bruneton */ public class Debug extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Debug.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "pkg/Debug", null, "java/lang/Object", new String[] { "java/io/Serializable" }); cw.visitSource("Debug.java", "source-debug"); FieldVisitor fv = cw.visitField(ACC_FINAL + ACC_STATIC, "serialVersionUID", "J", null, new Long(1L)); fv.visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(3, l0); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(ICONST_0); mv.visitJumpInsn(IFEQ, l1); mv.visitJumpInsn(GOTO, l1); mv.visitLabel(l1); mv.visitLineNumber(3, l1); mv.visitInsn(RETURN); mv.visitLabel(l2); mv.visitLocalVariable("this", "Lpkg/Debug;", "Lpkg/Debug;", l0, l2, 0); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Attribute.java0000644000175000017500000000726610452754520025074 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.attrs.CodeComment; import org.objectweb.asm.attrs.Comment; /** * Generates a class with non standard attributes. Covers class, field, method * and code attributes. Also covers the V1_3 class version and the SYNTHETIC * access flag for classes. * * @author Eric Bruneton */ public class Attribute extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Attribute.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_3, ACC_PUBLIC + ACC_SYNTHETIC, "pkg/Attribute", null, "java/lang/Object", null); cw.visitAttribute(new Comment()); fv = cw.visitField(ACC_PUBLIC, "f", "I", null, null); fv.visitAttribute(new Comment()); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitAttribute(new Comment()); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); /* * the following instructions are designed so that this method will be * resized by the method resizing test, in order to cover the code that * recomputes the code attribute labels in the resizeInstructions method * (see MethodWriter). */ Label l0 = new Label(); mv.visitInsn(ICONST_0); mv.visitJumpInsn(IFEQ, l0); // many NOPs will be introduced here by the method resizing test mv.visitJumpInsn(GOTO, l0); mv.visitLabel(l0); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitAttribute(new CodeComment()); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Insns.java0000644000175000017500000006324210452754520024217 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; /** * Generates a class that contain all bytecode instruction types (except JSR and * RET). Also covers access flags, signatures, and unicode characters. * * @author Eric Bruneton */ public class Insns extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Insns.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "pkg/Insns", "Ljava/util/ArrayList;LInterface;", "java/util/ArrayList", new String[] { "Interface" }); fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, "z", "Z", null, new Integer(1)); fv.visitEnd(); fv = cw.visitField(ACC_PROTECTED, "b", "B", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PUBLIC, "c", "C", null, null); fv.visitEnd(); fv = cw.visitField(ACC_STATIC, "s", "S", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PRIVATE + ACC_TRANSIENT, "i", "I", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PRIVATE + ACC_VOLATILE, "l", "J", null, null); fv.visitEnd(); fv = cw.visitField(0, "f", "F", null, null); fv.visitEnd(); fv = cw.visitField(0, "d", "D", null, null); fv.visitEnd(); fv = cw.visitField(0, "str", "Ljava/lang/String;", null, ""); fv.visitEnd(); fv = cw.visitField(0, "e", "Ljava/lang/Object;", "TE;", null); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNCHRONIZED, "m", "(ZBCSIFJDLjava/lang/Object;)Ljava/lang/Object;", "(ZBCSIFJDTE;)TE;", null); mv.visitCode(); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); // instruction types constInsns(cw); varInsns(cw); arrayInsns(cw); stackInsns(cw); mathInsns(cw); castInsns(cw); jumpInsns(cw); returnInsns(cw); fieldInsns(cw); methodInsns(cw); monitorInsns(cw); // various method types not covered by other test cases varargMethod(cw); bridgeMethod(cw); nativeMethod(cw); clinitMethod(cw); cw.visitEnd(); return cw.toByteArray(); } private void constInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "constInsns", "()V", null, null); mv.visitInsn(NOP); mv.visitInsn(ACONST_NULL); mv.visitInsn(ICONST_M1); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_2); mv.visitInsn(ICONST_3); mv.visitInsn(ICONST_4); mv.visitInsn(ICONST_5); mv.visitInsn(LCONST_0); mv.visitInsn(LCONST_1); mv.visitInsn(FCONST_0); mv.visitInsn(FCONST_1); mv.visitInsn(FCONST_2); mv.visitInsn(DCONST_0); mv.visitInsn(DCONST_1); mv.visitIntInsn(BIPUSH, 16); mv.visitIntInsn(SIPUSH, 256); mv.visitLdcInsn(new Integer(65536)); mv.visitLdcInsn(new Long(128L)); mv.visitLdcInsn(new Float("128.0")); mv.visitLdcInsn(new Double("128.0")); mv.visitLdcInsn("\n\r\u0009\"\\"); mv.visitLdcInsn("\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u1111\u0111\u0011\u0001"); mv.visitLdcInsn(Type.getType("Ljava/lang/Object;")); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void varInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "varInsns", "(IJFDD)V", null, null); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(IINC, 1); mv.visitVarInsn(ISTORE, 1); mv.visitVarInsn(LLOAD, 2); mv.visitVarInsn(LSTORE, 2); mv.visitVarInsn(FLOAD, 4); mv.visitVarInsn(FSTORE, 4); mv.visitVarInsn(DLOAD, 5); mv.visitVarInsn(DSTORE, 5); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ASTORE, 0); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 3); mv.visitInsn(LCONST_0); mv.visitVarInsn(LSTORE, 6); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void arrayInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "arrayInsns", "()V", null, null); // boolean arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_BOOLEAN); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(BASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(BALOAD); // byte arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_BYTE); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(BASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(BALOAD); // char arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_CHAR); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(CASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(CALOAD); // short arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_SHORT); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(SASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(SALOAD); // int arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_INT); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(IASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(IALOAD); // long arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_LONG); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(LCONST_0); mv.visitInsn(LASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(LALOAD); // float arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_FLOAT); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(FCONST_0); mv.visitInsn(FASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(FALOAD); // double arrays mv.visitInsn(ICONST_1); mv.visitIntInsn(NEWARRAY, T_DOUBLE); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(DCONST_0); mv.visitInsn(DASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(DALOAD); // object arrays mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitInsn(ACONST_NULL); mv.visitInsn(AASTORE); mv.visitInsn(ICONST_0); mv.visitInsn(AALOAD); // multi dimensional arrays mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, "[I"); mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_2); mv.visitInsn(ICONST_3); mv.visitMultiANewArrayInsn("[[[I", 3); // array length mv.visitInsn(ARRAYLENGTH); // end method mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void stackInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "stackInsns", "()V", null, null); // pop mv.visitInsn(ICONST_0); mv.visitInsn(POP); // pop2 (two variants) mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(POP2); mv.visitInsn(LCONST_0); mv.visitInsn(POP2); // dup mv.visitInsn(ICONST_0); mv.visitInsn(DUP); // dup_x1 mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP_X1); // dup_x2 (two variants) mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP_X2); mv.visitInsn(LCONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP_X2); // dup2 (two variants) mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP2); mv.visitInsn(LCONST_0); mv.visitInsn(DUP2); // dup2_x1 (two variants) mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP2_X1); mv.visitInsn(ICONST_0); mv.visitInsn(LCONST_0); mv.visitInsn(DUP2_X1); // dup2_x2 (four variants) mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP2_X2); mv.visitInsn(LCONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(DUP2_X2); mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0); mv.visitInsn(LCONST_0); mv.visitInsn(DUP2_X2); mv.visitInsn(LCONST_0); mv.visitInsn(LCONST_0); mv.visitInsn(DUP2_X2); // swap mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_1); mv.visitInsn(SWAP); // end method mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void mathInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "mathInsns", "(IJFD)V", null, null); // int math insns for (int i = 0; i < 12; ++i) { mv.visitVarInsn(ILOAD, 1); } mv.visitInsn(IADD); mv.visitInsn(ISUB); mv.visitInsn(IMUL); mv.visitInsn(IDIV); mv.visitInsn(IREM); mv.visitInsn(INEG); mv.visitInsn(ISHL); mv.visitInsn(ISHR); mv.visitInsn(IUSHR); mv.visitInsn(IAND); mv.visitInsn(IOR); mv.visitInsn(IXOR); // long math insns for (int i = 0; i < 9; ++i) { mv.visitVarInsn(LLOAD, 2); } mv.visitInsn(LADD); mv.visitInsn(LSUB); mv.visitInsn(LMUL); mv.visitInsn(LDIV); mv.visitInsn(LREM); mv.visitInsn(LNEG); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(LSHL); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(LSHR); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(LUSHR); mv.visitInsn(LAND); mv.visitInsn(LOR); mv.visitInsn(LXOR); // float math insns for (int i = 0; i < 6; ++i) { mv.visitVarInsn(FLOAD, 4); } mv.visitInsn(FADD); mv.visitInsn(FSUB); mv.visitInsn(FMUL); mv.visitInsn(FDIV); mv.visitInsn(FREM); mv.visitInsn(FNEG); // double math insns for (int i = 0; i < 6; ++i) { mv.visitVarInsn(DLOAD, 5); } mv.visitInsn(DADD); mv.visitInsn(DSUB); mv.visitInsn(DMUL); mv.visitInsn(DDIV); mv.visitInsn(DREM); mv.visitInsn(DNEG); // end method mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void castInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "castInsns", "(IJFD)V", null, null); // I2x mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2L); mv.visitVarInsn(LSTORE, 2); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2F); mv.visitVarInsn(FSTORE, 4); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2D); mv.visitVarInsn(DSTORE, 5); // L2x mv.visitVarInsn(LLOAD, 2); mv.visitInsn(L2I); mv.visitVarInsn(ISTORE, 1); mv.visitVarInsn(LLOAD, 2); mv.visitInsn(L2F); mv.visitVarInsn(FSTORE, 4); mv.visitVarInsn(LLOAD, 2); mv.visitInsn(L2D); mv.visitVarInsn(DSTORE, 5); // F2x mv.visitVarInsn(FLOAD, 4); mv.visitInsn(F2I); mv.visitVarInsn(ISTORE, 1); mv.visitVarInsn(FLOAD, 4); mv.visitInsn(F2L); mv.visitVarInsn(LSTORE, 2); mv.visitVarInsn(FLOAD, 4); mv.visitInsn(F2D); mv.visitVarInsn(DSTORE, 5); // D2x mv.visitVarInsn(DLOAD, 5); mv.visitInsn(D2I); mv.visitVarInsn(ISTORE, 1); mv.visitVarInsn(DLOAD, 5); mv.visitInsn(D2L); mv.visitVarInsn(LSTORE, 2); mv.visitVarInsn(DLOAD, 5); mv.visitInsn(D2F); mv.visitVarInsn(FSTORE, 4); // I2B mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2B); mv.visitFieldInsn(PUTFIELD, "pkg/Insns", "b", "B"); // I2C mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2C); mv.visitFieldInsn(PUTFIELD, "pkg/Insns", "c", "C"); // I2S mv.visitVarInsn(ILOAD, 1); mv.visitInsn(I2S); mv.visitFieldInsn(PUTSTATIC, "pkg/Insns", "s", "S"); // checkcast mv.visitInsn(ACONST_NULL); mv.visitTypeInsn(CHECKCAST, "java/lang/String"); mv.visitInsn(ACONST_NULL); mv.visitTypeInsn(CHECKCAST, "[[I"); // instanceof mv.visitInsn(ACONST_NULL); mv.visitTypeInsn(INSTANCEOF, "java/lang/String"); // end method mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void jumpInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "jumpInsns", "(IJFD)V", null, null); Label l0 = new Label(); // ifxx mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFNE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFEQ, l0); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFLE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFGE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFLT, l0); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFGT, l0); // ificmpxx mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPNE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPEQ, l0); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPLE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPGE, l0); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPLT, l0); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IF_ICMPGT, l0); // lcmp mv.visitVarInsn(LLOAD, 2); mv.visitVarInsn(LLOAD, 2); mv.visitInsn(LCMP); mv.visitJumpInsn(IFNE, l0); // fcmpx mv.visitVarInsn(FLOAD, 4); mv.visitVarInsn(FLOAD, 4); mv.visitInsn(FCMPL); mv.visitJumpInsn(IFNE, l0); mv.visitVarInsn(FLOAD, 4); mv.visitVarInsn(FLOAD, 4); mv.visitInsn(FCMPG); mv.visitJumpInsn(IFNE, l0); // dcmpx mv.visitVarInsn(DLOAD, 5); mv.visitVarInsn(DLOAD, 5); mv.visitInsn(DCMPL); mv.visitJumpInsn(IFNE, l0); mv.visitVarInsn(DLOAD, 5); mv.visitVarInsn(DLOAD, 5); mv.visitInsn(DCMPG); mv.visitJumpInsn(IFNE, l0); // ifacmp mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitJumpInsn(IF_ACMPNE, l0); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitJumpInsn(IF_ACMPEQ, l0); // ifnull mv.visitVarInsn(ALOAD, 0); mv.visitJumpInsn(IFNULL, l0); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 7); mv.visitVarInsn(ALOAD, 0); mv.visitJumpInsn(IFNONNULL, l0); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 7); mv.visitVarInsn(ALOAD, 0); // tableswitch Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); mv.visitVarInsn(ILOAD, 1); mv.visitTableSwitchInsn(0, 2, l3, new Label[] { l1, l2, l3 }); mv.visitLabel(l1); mv.visitInsn(ICONST_1); mv.visitVarInsn(ISTORE, 7); mv.visitJumpInsn(GOTO, l3); mv.visitLabel(l2); mv.visitInsn(ICONST_2); mv.visitVarInsn(ISTORE, 7); mv.visitJumpInsn(GOTO, l3); mv.visitLabel(l3); mv.visitVarInsn(ILOAD, 7); // lookupswitch Label l4 = new Label(); Label l5 = new Label(); Label l6 = new Label(); mv.visitVarInsn(ILOAD, 1); mv.visitLookupSwitchInsn(l6, new int[] { 0, 1, 2 }, new Label[] { l4, l5, l6 }); mv.visitLabel(l4); mv.visitInsn(ICONST_1); mv.visitVarInsn(ISTORE, 7); mv.visitJumpInsn(GOTO, l6); mv.visitLabel(l5); mv.visitInsn(ICONST_2); mv.visitVarInsn(ISTORE, 7); mv.visitJumpInsn(GOTO, l6); mv.visitLabel(l6); mv.visitVarInsn(ILOAD, 7); // throw mv.visitInsn(ACONST_NULL); mv.visitInsn(ATHROW); // misc instructions to cover code in MethodWriter.resizeInsns mv.visitLabel(l0); mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_2); mv.visitMultiANewArrayInsn("[[I", 2); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "size", "()V"); // end method mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void returnInsns(final ClassWriter cw) { MethodVisitor mv; mv = cw.visitMethod(ACC_STATIC, "ireturnInsn", "()I", null, null); mv.visitCode(); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PRIVATE, "lreturnInsn", "()J", null, null); mv.visitCode(); mv.visitInsn(LCONST_0); mv.visitInsn(LRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(0, "freturnInsn", "()F", null, null); mv.visitCode(); mv.visitInsn(FCONST_0); mv.visitInsn(FRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(0, "dreturnInsn", "()D", null, null); mv.visitCode(); mv.visitInsn(DCONST_0); mv.visitInsn(DRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void fieldInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "fieldInsns", "()V", null, null); mv.visitFieldInsn(GETSTATIC, "pkg/Insns", "s", "S"); mv.visitFieldInsn(PUTSTATIC, "pkg/Insns", "s", "S"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "pkg/Insns", "i", "I"); mv.visitFieldInsn(PUTFIELD, "pkg/Insns", "i", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "pkg/Insns", "l", "J"); mv.visitFieldInsn(PUTFIELD, "pkg/Insns", "l", "J"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void methodInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "methodInsns", "()V", null, null); // invokstatic mv.visitMethodInsn(INVOKESTATIC, "pkg/Insns", "ireturn", "()I"); // invokespecial mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Insns", "lreturn", "()J"); // invokevirtual mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "pkg/Insns", "freturn", "()F"); // invokeinterface mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "size", "()I"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void monitorInsns(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "monitorInsns", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(MONITORENTER); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(MONITOREXIT); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void varargMethod(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS + ACC_STRICT, "varargMethod", "([Ljava/lang/Object;)V", "([Ljava/lang/Object;)V^TF;", new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void bridgeMethod(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(I)Ljava/lang/String;", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "get", "(I)Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "java/lang/String"); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(I)Ljava/lang/Object;", "(I)TE;", null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "pkg/Insns", "get", "(I)Ljava/lang/String;"); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private void nativeMethod(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_NATIVE, "nativeMethod", "()V", null, null); mv.visitEnd(); } private void clinitMethod(final ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); mv.visitCode(); mv.visitInsn(ICONST_1); mv.visitFieldInsn(PUTSTATIC, "pkg/Insns", "s", "S"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Generator.java0000644000175000017500000000543210452754520025050 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import org.objectweb.asm.Opcodes; /** * Generates classes designed so that the "conform" test suite, applied to these * classes, covers all the ASM code base. * * @author Eric Bruneton */ public class Generator implements Opcodes { public static void main(final String[] args) throws IOException { Generator generators[] = { new Annotation(), new Attribute(), new Debug(), new Enum(), new Frames(), new Insns(), new Interface(), new JSR(), new Outer(), new Wide() }; for (int i = 0; i < generators.length; ++i) { generators[i].generate(args[0]); } } protected void generate(final String dir) throws IOException { } protected void generate( final String dir, final String path, final byte[] clazz) throws IOException { File f = new File(new File(dir), path); f.getParentFile().mkdirs(); FileOutputStream o = new FileOutputStream(f); o.write(clazz); o.close(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Enum.java0000644000175000017500000001514610452754520024031 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; /** * Generates an enum class. * * @author Eric Bruneton */ public class Enum extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Enum.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_5, ACC_PUBLIC + ACC_FINAL + ACC_SUPER + ACC_ENUM, "pkg/Enum", "Ljava/lang/Enum;", "java/lang/Enum", null); fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM, "V0", "Lpkg/Enum;", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM, "V1", "Lpkg/Enum;", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM, "V2", "Lpkg/Enum;", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC, "$VALUES", "[Lpkg/Enum;", null, null); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "values", "()[Lpkg/Enum;", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "pkg/Enum", "$VALUES", "[Lpkg/Enum;"); mv.visitMethodInsn(INVOKEVIRTUAL, "[Lpkg/Enum;", "clone", "()Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "[Lpkg/Enum;"); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "valueOf", "(Ljava/lang/String;)Lpkg/Enum;", null, null); mv.visitCode(); mv.visitLdcInsn(Type.getType("Lpkg/Enum;")); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;"); mv.visitTypeInsn(CHECKCAST, "pkg/Enum"); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PRIVATE, "", "(Ljava/lang/String;I)V", "()V", null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "", "(Ljava/lang/String;I)V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); mv.visitCode(); mv.visitTypeInsn(NEW, "pkg/Enum"); mv.visitInsn(DUP); mv.visitLdcInsn("V0"); mv.visitInsn(ICONST_0); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Enum", "", "(Ljava/lang/String;I)V"); mv.visitFieldInsn(PUTSTATIC, "pkg/Enum", "V0", "Lpkg/Enum;"); mv.visitTypeInsn(NEW, "pkg/Enum"); mv.visitInsn(DUP); mv.visitLdcInsn("V1"); mv.visitInsn(ICONST_1); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Enum", "", "(Ljava/lang/String;I)V"); mv.visitFieldInsn(PUTSTATIC, "pkg/Enum", "V1", "Lpkg/Enum;"); mv.visitTypeInsn(NEW, "pkg/Enum"); mv.visitInsn(DUP); mv.visitLdcInsn("V2"); mv.visitInsn(ICONST_2); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Enum", "", "(Ljava/lang/String;I)V"); mv.visitFieldInsn(PUTSTATIC, "pkg/Enum", "V2", "Lpkg/Enum;"); mv.visitInsn(ICONST_3); mv.visitTypeInsn(ANEWARRAY, "pkg/Enum"); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitFieldInsn(GETSTATIC, "pkg/Enum", "V0", "Lpkg/Enum;"); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_1); mv.visitFieldInsn(GETSTATIC, "pkg/Enum", "V1", "Lpkg/Enum;"); mv.visitInsn(AASTORE); mv.visitInsn(DUP); mv.visitInsn(ICONST_2); mv.visitFieldInsn(GETSTATIC, "pkg/Enum", "V2", "Lpkg/Enum;"); mv.visitInsn(AASTORE); mv.visitFieldInsn(PUTSTATIC, "pkg/Enum", "$VALUES", "[Lpkg/Enum;"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Interface.java0000644000175000017500000000522210452754520025017 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; /** * Generates an interface class. Also covers signatures, default package and non * null minor class version number. * * @author Eric Bruneton */ public class Interface extends Generator { public void generate(final String dir) throws IOException { generate(dir, "Interface.class", dump()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(1 << 16 | V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "Interface", "Ljava/lang/Object;", "java/lang/Object", null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "(ZBCSIFJDLjava/lang/Object;)Ljava/lang/Object;", "(ZBCSIFJDTE;)TE;", null); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Annotation.java0000644000175000017500000002743610710602357025241 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; /** * Generates an annotation class with values of all types and a class using it. * * @author Eric Bruneton */ public class Annotation extends Generator { final static int M = ACC_PUBLIC + ACC_ABSTRACT; final static String STRING = "Ljava/lang/String;"; final static String CLASS = "Ljava/lang/Class;"; final static String DOC = "Ljava/lang/annotation/Documented;"; final static String DEPRECATED = "Ljava/lang/Deprecated;"; public void generate(final String dir) throws IOException { generate(dir, "pkg/Annotation.class", dumpAnnotation()); generate(dir, "pkg/Annotated.class", dumpAnnotated()); } public byte[] dumpAnnotation() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; AnnotationVisitor av0, av1; cw.visit(V1_5, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Annotation", null, "java/lang/Object", new String[] { "java/lang/annotation/Annotation" }); mv = cw.visitMethod(M, "byteValue", "()B", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Byte((byte) 1)); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "charValue", "()C", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Character((char) 1)); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "booleanValue", "()Z", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, Boolean.TRUE); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "intValue", "()I", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Integer(1)); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "shortValue", "()S", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Short((short) 1)); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "longValue", "()J", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Long(1L)); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "floatValue", "()F", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Float("1.0")); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "doubleValue", "()D", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new Double("1.0")); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "stringValue", "()" + STRING, null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, "1"); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "classValue", "()" + CLASS, null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, Type.getType("Lpkg/Annotation;")); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "enumValue", "()Lpkg/Enum;", null, null); av0 = mv.visitAnnotationDefault(); av0.visitEnum(null, "Lpkg/Enum;", "V1"); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "annotationValue", "()" + DOC, null, null); av0 = mv.visitAnnotationDefault(); av1 = av0.visitAnnotation(null, DOC); av1.visitEnd(); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "byteArrayValue", "()[B", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new byte[] { 0, 1 }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "charArrayValue", "()[C", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new char[] { '0', '1' }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "booleanArrayValue", "()[Z", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new boolean[] { false, true }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "intArrayValue", "()[I", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new int[] { 0, 1 }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "shortArrayValue", "()[S", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new short[] { (short) 0, (short) 1 }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "longArrayValue", "()[J", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new long[] { 0L, 1L }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "floatArrayValue", "()[F", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new float[] { 0.0f, 1.0f }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "doubleArrayValue", "()[D", null, null); av0 = mv.visitAnnotationDefault(); av0.visit(null, new double[] { 0.0d, 1.0d }); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "stringArrayValue", "()" + STRING, null, null); av0 = mv.visitAnnotationDefault(); av1 = av0.visitArray(null); av1.visit(null, "0"); av1.visit(null, "1"); av1.visitEnd(); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "classArrayValue", "()[" + CLASS, null, null); av0 = mv.visitAnnotationDefault(); av1 = av0.visitArray(null); av1.visit(null, Type.getType("Lpkg/Annotation;")); av1.visit(null, Type.getType("Lpkg/Annotation;")); av1.visitEnd(); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "enumArrayValue", "()[Lpkg/Enum;", null, null); av0 = mv.visitAnnotationDefault(); av1 = av0.visitArray(null); av1.visitEnum(null, "Lpkg/Enum;", "V0"); av1.visitEnum(null, "Lpkg/Enum;", "V1"); av1.visitEnd(); av0.visitEnd(); mv.visitEnd(); mv = cw.visitMethod(M, "annotationArrayValue", "()[" + DOC, null, null); av0 = mv.visitAnnotationDefault(); av1 = av0.visitArray(null); av1.visitAnnotation(null, DOC).visitEnd(); av1.visitAnnotation(null, DOC).visitEnd(); av1.visitEnd(); av0.visitEnd(); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } public byte[] dumpAnnotated() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; AnnotationVisitor av0, av1; cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "pkg/Annotated", null, "java/lang/Object", null); // visible class annotation cw.visitAnnotation(DEPRECATED, true).visitEnd(); // invisible class annotation, with values of all types av0 = cw.visitAnnotation("Lpkg/Annotation;", false); av0.visit("byteValue", new Byte((byte) 0)); av0.visit("charValue", new Character((char) 48)); av0.visit("booleanValue", Boolean.FALSE); av0.visit("intValue", new Integer(0)); av0.visit("shortValue", new Short((short) 0)); av0.visit("longValue", new Long(0L)); av0.visit("floatValue", new Float("0.0")); av0.visit("doubleValue", new Double("0.0")); av0.visit("stringValue", "0"); av0.visitEnum("enumValue", "Lpkg/Enum;", "V0"); av0.visitAnnotation("annotationValue", DOC).visitEnd(); av0.visit("classValue", Type.getType("Lpkg/Annotation;")); av0.visit("byteArrayValue", new byte[] { 1, 0 }); av0.visit("charArrayValue", new char[] { '1', '0' }); av0.visit("booleanArrayValue", new boolean[] { true, false }); av0.visit("intArrayValue", new int[] { 1, 0 }); av0.visit("shortArrayValue", new short[] { (short) 1, (short) 0 }); av0.visit("longArrayValue", new long[] { 1L, 0L }); av0.visit("floatArrayValue", new float[] { 1.0f, 0.0f }); av0.visit("doubleArrayValue", new double[] { 1.0d, 0.0d }); av1 = av0.visitArray("stringArrayValue"); av1.visit(null, "1"); av1.visit(null, "0"); av1.visitEnd(); av0.visitArray("classArrayValue").visitEnd(); av1 = av0.visitArray("enumArrayValue"); av1.visitEnum(null, "Lpkg/Enum;", "V1"); av1.visitEnum(null, "Lpkg/Enum;", "V2"); av1.visitEnd(); av0.visitArray("annotationArrayValue").visitEnd(); av0.visitEnd(); fv = cw.visitField(ACC_PUBLIC, "f", "I", null, null); // visible field annotation fv.visitAnnotation(DEPRECATED, true).visitEnd(); // invisible field annotation av0 = fv.visitAnnotation("Lpkg/Annotation;", false); av0.visitEnum("enumValue", "Lpkg/Enum;", "V0"); av0.visitEnd(); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "", "(IIIIIIIIII)V", null, null); // visible method annotation mv.visitAnnotation(DEPRECATED, true).visitEnd(); // invisible method annotation av0 = mv.visitAnnotation("Lpkg/Annotation;", false); av0.visitAnnotation("annotationValue", DOC).visitEnd(); av0.visitEnd(); // synthetic parameter annotation mv.visitParameterAnnotation(0, "Ljava/lang/Synthetic;", false); // visible parameter annotation mv.visitParameterAnnotation(8, DEPRECATED, true).visitEnd(); // invisible parameter annotation av0 = mv.visitParameterAnnotation(8, "Lpkg/Annotation;", false); av0.visitArray("stringArrayValue").visitEnd(); av0.visitEnd(); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/JSR.java0000644000175000017500000001403510452754520023557 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; /** * Generates classes with JSR/RET instructions. Covers forward and backward JSR * and JSR_W instructions. Also covers the wide form of IFNULL instruction, and * the V1_1 class version (these jump instructions are not directly generated in * their 'wide' form, but are transformed to this form by the method resizing * test). * * @author Eric Bruneton * */ public class JSR extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/JSR1.class", dumpForwardJSR()); generate(dir, "pkg/JSR2.class", dumpBackwardJSR()); } public byte[] dumpForwardJSR() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; cw.visit(V1_1, ACC_PUBLIC, "pkg/JSR1", null, "java/lang/Object", null); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "forwardJSR", "([I)V", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); Label l4 = new Label(); Label l5 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, null); mv.visitTryCatchBlock(l2, l3, l2, null); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "pkg/JSR1", "forwardJSR", "([I)V"); mv.visitJumpInsn(JSR, l4); // forward JSR, will give forward JSR_W // many NOPs will be introduced here by the method resizing test mv.visitLabel(l1); mv.visitJumpInsn(GOTO, l5); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); mv.visitJumpInsn(JSR, l4); mv.visitLabel(l3); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ATHROW); mv.visitLabel(l4); mv.visitVarInsn(ASTORE, 3); mv.visitInsn(DCONST_0); mv.visitVarInsn(DSTORE, 4); mv.visitVarInsn(RET, 3); mv.visitLabel(l5); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } public byte[] dumpBackwardJSR() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; cw.visit(V1_1, ACC_PUBLIC, "pkg/JSR2", null, "java/lang/Object", null); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "backwardJSR", "([I)V", null, null); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); Label l4 = new Label(); Label l5 = new Label(); Label l6 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, null); mv.visitTryCatchBlock(l2, l3, l2, null); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 4); mv.visitJumpInsn(GOTO, l0); mv.visitLabel(l4); mv.visitVarInsn(ASTORE, 3); mv.visitIincInsn(4, 1); mv.visitVarInsn(RET, 3); /* extra instructions only used to trigger method resizing */ mv.visitLabel(l0); mv.visitInsn(ACONST_NULL); mv.visitJumpInsn(IFNULL, l6); // will give wide IFNULL // many NOPs will be introduced here by the method resizing test mv.visitJumpInsn(GOTO, l6); mv.visitLabel(l6); mv.visitJumpInsn(JSR, l4); // backward JSR, will give JSR_W mv.visitLabel(l1); mv.visitJumpInsn(GOTO, l5); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 2); mv.visitJumpInsn(JSR, l4); mv.visitLabel(l3); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ATHROW); mv.visitLabel(l5); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/test/cases/Outer.java0000644000175000017500000001700310452754520024215 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.test.cases; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; /** * Generates a class with two inner classes. Covers all features used by inner * classes (visitInner, visitOuter, synthetic members, etc). Also covers the * V1_4 class version and the DEPRECATED access flag. * * @author Eric Bruneton */ public class Outer extends Generator { public void generate(final String dir) throws IOException { generate(dir, "pkg/Outer.class", dump()); generate(dir, "pkg/Outer$1.class", dump1()); generate(dir, "pkg/Outer$Inner.class", dumpInner()); } public byte[] dump() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_4, ACC_PUBLIC + ACC_SUPER + ACC_DEPRECATED, "pkg/Outer", null, "java/lang/Object", null); cw.visitInnerClass("pkg/Outer$Inner", "pkg/Outer", "C", 0); cw.visitInnerClass("pkg/Outer$1", null, null, 0); fv = cw.visitField(ACC_PRIVATE + ACC_DEPRECATED, "i", "I", null, null); fv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_DEPRECATED, "m", "()V", null, null); mv.visitCode(); mv.visitTypeInsn(NEW, "pkg/Outer$1"); mv.visitInsn(DUP); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Outer$1", "", "(Lpkg/Outer;)V"); mv.visitInsn(POP); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "access$000", "(Lpkg/Outer;)I", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "pkg/Outer", "i", "I"); mv.visitInsn(IRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } public static byte[] dump1() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_4, ACC_SUPER, "pkg/Outer$1", null, "pkg/Outer", null); cw.visitOuterClass("pkg/Outer", "m", "()V"); cw.visitInnerClass("pkg/Outer$1", null, null, 0); fv = cw.visitField(ACC_FINAL + ACC_SYNTHETIC, "this$0", "Lpkg/Outer;", null, null); fv.visitEnd(); mv = cw.visitMethod(0, "", "(Lpkg/Outer;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(PUTFIELD, "pkg/Outer$1", "this$0", "Lpkg/Outer;"); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "pkg/Outer", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); mv.visitCode(); mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "pkg/Outer$1", "this$0", "Lpkg/Outer;"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuilder;"); mv.visitLdcInsn(" "); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "pkg/Outer$1", "this$0", "Lpkg/Outer;"); mv.visitMethodInsn(INVOKESTATIC, "pkg/Outer", "access$000", "(Lpkg/Outer;)I"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } public static byte[] dumpInner() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); FieldVisitor fv; MethodVisitor mv; cw.visit(V1_4, ACC_SUPER, "pkg/Outer$Inner", null, "java/lang/Object", null); cw.visitInnerClass("pkg/Outer$Inner", "pkg/Outer", "C", 0); fv = cw.visitField(ACC_FINAL + ACC_SYNTHETIC, "this$0", "Lpkg/Outer;", null, null); fv.visitEnd(); mv = cw.visitMethod(0, "", "(Lpkg/Outer;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(PUTFIELD, "pkg/Outer$Inner", "this$0", "Lpkg/Outer;"); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassReaderUnitTest.java0000644000175000017500000000675410510372227024740 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.IOException; import java.io.InputStream; import junit.framework.TestCase; /** * ClassReader unit tests. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class ClassReaderUnitTest extends TestCase implements Opcodes { public void testIllegalConstructorArgument() { try { new ClassReader((InputStream) null); fail(); } catch (IOException e) { } } public void testGetItem() throws IOException { ClassReader cr = new ClassReader(getClass().getName()); int item = cr.getItem(1); assertTrue(item >= 10); assertTrue(item < cr.header); } public void testReadByte() throws IOException { ClassReader cr = new ClassReader(getClass().getName()); assertEquals(cr.b[0] & 0xFF, cr.readByte(0)); } public void testGetAccess() throws Exception { String name = getClass().getName(); assertEquals(Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, new ClassReader(name).getAccess()); } public void testGetClassName() throws Exception { String name = getClass().getName(); assertEquals(name.replace('.', '/'), new ClassReader(name).getClassName()); } public void testGetSuperName() throws Exception { assertEquals(TestCase.class.getName().replace('.', '/'), new ClassReader(getClass().getName()).getSuperName()); assertEquals(null, new ClassReader(Object.class.getName()).getSuperName()); } public void testGetInterfaces() throws Exception { String[] interfaces = new ClassReader(getClass().getName()).getInterfaces(); assertNotNull(interfaces); assertEquals(1, interfaces.length); assertEquals(Opcodes.class.getName().replace('.', '/'), interfaces[0]); interfaces = new ClassReader(Opcodes.class.getName()).getInterfaces(); assertNotNull(interfaces); } } asm-3.3.2/test/conform/org/objectweb/asm/attrs/0000755000175000017500000000000011633370174021334 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/attrs/CodeComment.java0000644000175000017500000000620310452754520024374 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.attrs; import java.util.Map; import org.objectweb.asm.Attribute; import org.objectweb.asm.ByteVector; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.util.ASMifiable; import org.objectweb.asm.util.Traceable; /** * A non standard code attribute used for testing purposes. * * @author Eric Bruneton */ public class CodeComment extends Attribute implements ASMifiable, Traceable { public CodeComment() { super("CodeComment"); } public boolean isUnknown() { return false; } public boolean isCodeAttribute() { return true; } protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return new CodeComment(); } protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { return new ByteVector(); } protected Label[] getLabels() { super.getLabels(); return new Label[] { new Label() }; } public void asmify( final StringBuffer buf, final String varName, final Map labelNames) { buf.append("Attribute ") .append(varName) .append(" = new org.objectweb.asm.attrs.CodeComment();"); } public void trace(final StringBuffer buf, final Map labelNames) { } } asm-3.3.2/test/conform/org/objectweb/asm/attrs/Comment.java0000644000175000017500000000566510452754520023614 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.attrs; import java.util.Map; import org.objectweb.asm.Attribute; import org.objectweb.asm.ByteVector; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.util.ASMifiable; import org.objectweb.asm.util.Traceable; /** * A non standard attribute used for testing purposes. * * @author Eric Bruneton */ public class Comment extends Attribute implements ASMifiable, Traceable { public Comment() { super("Comment"); } public boolean isUnknown() { return false; } protected Attribute read( final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) { return new Comment(); } protected ByteVector write( final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { return new ByteVector(); } public void asmify( final StringBuffer buf, final String varName, final Map labelNames) { buf.append("Attribute ") .append(varName) .append(" = new org.objectweb.asm.attrs.Comment();"); } public void trace(final StringBuffer buf, final Map labelNames) { } } asm-3.3.2/test/conform/org/objectweb/asm/signature/0000755000175000017500000000000011633370174022200 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/signature/SignatureUnitTest.java0000644000175000017500000000607610621275626026517 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.signature; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.util.TraceSignatureVisitorUnitTest; import org.objectweb.asm.util.TraceSignatureVisitorUnitTest.TestData; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Signature tests. * * @author Eugene Kuleshov * @author Eric Bruneton */ public class SignatureUnitTest extends TestCase { public static TestSuite suite() { TestSuite suite = new TestSuite(SignatureUnitTest.class.getName()); for (int i = 0; i < TraceSignatureVisitorUnitTest.DATA.length; i++) { suite.addTest(new SignatureUnitTest(new TestData(TraceSignatureVisitorUnitTest.DATA[i]))); } return suite; } private TestData data; private SignatureUnitTest(final TestData data) { super("testSignature"); this.data = data; } public void testSignature() { SignatureWriter wrt = new SignatureWriter(); SignatureReader rdr = new SignatureReader(data.signature); switch (data.type) { case 'C': case 'M': rdr.accept(wrt); break; case 'F': rdr.acceptType(wrt); break; default: return; } assertEquals(data.signature, wrt.toString()); } public String getName() { return super.getName() + " " + data.signature; } } asm-3.3.2/test/conform/org/objectweb/asm/signature/SignatureWriterTest.java0000644000175000017500000000747010621275626027053 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.signature; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; /** * Signature tests. * * @author Eric Bruneton */ public class SignatureWriterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new SignatureWriterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); cr.accept(new EmptyVisitor() { public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.accept(sw); assertEquals(signature, sw.toString()); } } public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.acceptType(sw); assertEquals(signature, sw.toString()); } return null; } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if (signature != null) { SignatureReader sr = new SignatureReader(signature); SignatureWriter sw = new SignatureWriter(); sr.accept(sw); assertEquals(signature, sw.toString()); } return null; } }, 0); } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterUnitTest.java0000644000175000017500000000501210507622260024775 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import junit.framework.TestCase; /** * ClassWriter unit tests. * * @author Eric Bruneton */ public class ClassWriterUnitTest extends TestCase { public void testNewConst() { ClassWriter cw = new ClassWriter(0); cw.newConst(new Byte((byte) 0)); cw.newConst(new Character('0')); cw.newConst(new Short((short) 0)); cw.newConst(Boolean.FALSE); cw.newField("A", "f", "I"); cw.newMethod("A", "m", "()V", false); } public void testIllegalNewConstArgument() { ClassWriter cw = new ClassWriter(0); try { cw.newConst(new Object()); fail(); } catch (RuntimeException e) { } } public void testIllegalGetCommonSuperClassArguments() { ClassWriter cw = new ClassWriter(0); try { cw.getCommonSuperClass("-", "-"); fail(); } catch (RuntimeException e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/ClassWriterComputeFramesTest.java0000644000175000017500000002261511224532001026626 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; import org.objectweb.asm.util.TraceClassVisitor; import junit.framework.TestSuite; /** * ClassWriter tests. * * @author Eric Bruneton */ public class ClassWriterComputeFramesTest extends AbstractTest { public static void premain( final String agentArgs, final Instrumentation inst) { inst.addTransformer(new ClassFileTransformer() { public byte[] transform( final ClassLoader loader, final String className, final Class classBeingRedefined, final ProtectionDomain domain, final byte[] classFileBuffer) throws IllegalClassFormatException { String n = className.replace('/', '.'); if (n.indexOf("junit") != -1) { return null; } if (agentArgs.length() == 0 || n.indexOf(agentArgs) != -1) { return transformClass(n, classFileBuffer); } else { return null; } } }); } static byte[] transformClass(final String n, final byte[] clazz) { ClassReader cr = new ClassReader(clazz); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) { protected String getCommonSuperClass( final String type1, final String type2) { if (n.equals("pkg.Frames")) { return super.getCommonSuperClass(type1, type2); } ClassInfo c, d; try { c = new ClassInfo(type1, getClass().getClassLoader()); d = new ClassInfo(type2, getClass().getClassLoader()); } catch (Throwable e) { throw new RuntimeException(e); } if (c.isAssignableFrom(d)) { return type1; } if (d.isAssignableFrom(c)) { return type2; } if (c.isInterface() || d.isInterface()) { return "java/lang/Object"; } else { do { c = c.getSuperclass(); } while (!c.isAssignableFrom(d)); return c.getType().getInternalName(); } } }; cr.accept(new ClassAdapter(cw) { public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { super.visit(Opcodes.V1_6, access, name, signature, superName, interfaces); } }, ClassReader.SKIP_FRAMES); return cw.toByteArray(); } public static TestSuite suite() throws Exception { return new ClassWriterComputeFramesTest().getSuite(); } public void test() throws Exception { try { Class.forName(n, true, getClass().getClassLoader()); } catch (NoClassDefFoundError ncdfe) { // ignored } catch (UnsatisfiedLinkError ule) { // ignored } catch (ClassFormatError cfe) { fail(cfe.getMessage()); } catch (VerifyError ve) { String s = n.replace('.', '/') + ".class"; InputStream is = getClass().getClassLoader().getResourceAsStream(s); ClassReader cr = new ClassReader(is); byte[] b = transformClass("", cr.b); StringWriter sw1 = new StringWriter(); StringWriter sw2 = new StringWriter(); sw2.write(ve.toString() + "\n"); ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1)); ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2)); cr.accept(cv1, 0); new ClassReader(b).accept(cv2, 0); String s1 = sw1.toString(); String s2 = sw2.toString(); assertEquals("different data", s1, s2); } } } /** * @author Eugene Kuleshov */ class ClassInfo { private Type type; private ClassLoader loader; int access; String superClass; String[] interfaces; public ClassInfo(final String type, final ClassLoader loader) { this.loader = loader; this.type = Type.getObjectType(type); String s = type.replace('.', '/') + ".class"; InputStream is = null; ClassReader cr; try { is = loader.getResourceAsStream(s); cr = new ClassReader(is); } catch (IOException e) { throw new RuntimeException(e); } finally { if (is != null) { try { is.close(); } catch (Exception e) { } } } // optimized version int h = cr.header; ClassInfo.this.access = cr.readUnsignedShort(h); char[] buf = new char[2048]; // String name = cr.readClass( cr.header + 2, buf); int v = cr.getItem(cr.readUnsignedShort(h + 4)); ClassInfo.this.superClass = v == 0 ? null : cr.readUTF8(v, buf); ClassInfo.this.interfaces = new String[cr.readUnsignedShort(h + 6)]; h += 8; for (int i = 0; i < interfaces.length; ++i) { interfaces[i] = cr.readClass(h, buf); h += 2; } } String getName() { return type.getInternalName(); } Type getType() { return type; } int getModifiers() { return access; } ClassInfo getSuperclass() { if (superClass == null) { return null; } return new ClassInfo(superClass, loader); } ClassInfo[] getInterfaces() { if (interfaces == null) { return new ClassInfo[0]; } ClassInfo[] result = new ClassInfo[interfaces.length]; for (int i = 0; i < result.length; ++i) { result[i] = new ClassInfo(interfaces[i], loader); } return result; } boolean isInterface() { return (getModifiers() & Opcodes.ACC_INTERFACE) > 0; } private boolean implementsInterface(final ClassInfo that) { for (ClassInfo c = this; c != null; c = c.getSuperclass()) { ClassInfo[] tis = c.getInterfaces(); for (int i = 0; i < tis.length; ++i) { ClassInfo ti = tis[i]; if (ti.type.equals(that.type) || ti.implementsInterface(that)) { return true; } } } return false; } private boolean isSubclassOf(final ClassInfo that) { for (ClassInfo c = this; c != null; c = c.getSuperclass()) { if (c.getSuperclass() != null && c.getSuperclass().type.equals(that.type)) { return true; } } return false; } public boolean isAssignableFrom(final ClassInfo that) { if (this == that) { return true; } if (that.isSubclassOf(this)) { return true; } if (that.implementsInterface(this)) { return true; } if (that.isInterface() && getType().getDescriptor().equals("Ljava/lang/Object;")) { return true; } return false; } } asm-3.3.2/test/conform/org/objectweb/asm/tree/0000755000175000017500000000000011633370174021136 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/0000755000175000017500000000000011633370174022761 5ustar twernertwernerasm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/BasicVerifierTest.java0000644000175000017500000000471010462406024027174 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; /** * Analysis tests. * * @author Eric Bruneton */ public class BasicVerifierTest extends AbstractTest { public static TestSuite suite() throws Exception { return new BasicVerifierTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassNode cn = new ClassNode(); cr.accept(cn, 0); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); Analyzer a = new Analyzer(new BasicVerifier()); a.analyze(cn.name, method); } } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/SimpleVerifierTest.java0000644000175000017500000000471310462406024027407 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; /** * Verifier tests. * * @author Eric Bruneton */ public class SimpleVerifierTest extends AbstractTest { public static TestSuite suite() throws Exception { return new SimpleVerifierTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassNode cn = new ClassNode(); cr.accept(cn, 0); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); Analyzer a = new Analyzer(new SimpleVerifier()); a.analyze(cn.name, method); } } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/BasicInterpreterTest.java0000644000175000017500000000472110462406024027726 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; /** * Analysis tests. * * @author Eric Bruneton */ public class BasicInterpreterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new BasicInterpreterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassNode cn = new ClassNode(); cr.accept(cn, 0); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); Analyzer a = new Analyzer(new BasicInterpreter()); a.analyze(cn.name, method); } } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/ValueUnitTest.java0000644000175000017500000000427210701747173026407 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import junit.framework.TestCase; /** * BasicValue and SourceValue unit tests. * * @author Eric Bruneton */ public class ValueUnitTest extends TestCase { public void testBasicValue() { assertFalse(BasicValue.INT_VALUE.equals(new Object())); BasicValue.INT_VALUE.hashCode(); BasicValue.UNINITIALIZED_VALUE.toString(); BasicValue.RETURNADDRESS_VALUE.toString(); BasicValue.REFERENCE_VALUE.toString(); } public void testSourceValue() { new SourceValue(1).hashCode(); assertFalse(new SourceValue(1).equals(null)); } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/SimpleVerifierUnitTest.java0000644000175000017500000003074611442701300030246 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; import junit.framework.TestCase; /** * SimpleVerifier unit tests. * * @author Eric Bruneton */ public class SimpleVerifierUnitTest extends TestCase implements Opcodes { private Analyzer a; private MethodNode mn; protected void setUp() { Type c = Type.getType("LC;"); Type d = Type.getType("Ljava/lang/Number;"); a = new Analyzer(new SimpleVerifier(c, d, false)); mn = new MethodNode(ACC_PUBLIC, "m", "()V", null, null); } private void assertValid() throws AnalyzerException { mn.visitInsn(RETURN); mn.visitMaxs(10, 10); a.analyze("C", mn); Frame[] frames = a.getFrames(); for (int i = 0; i < frames.length; ++i) { if (frames[i] != null) { frames[i].toString(); } } a.getHandlers(0); } private void assertInvalid() { mn.visitInsn(RETURN); mn.visitMaxs(10, 10); try { a.analyze("C", mn); fail(); } catch (AnalyzerException e) { } catch (RuntimeException e) { } } public void testInvalidOpcode() { mn.visitInsn(-1); assertInvalid(); } public void testInvalidPop() { mn.visitInsn(LCONST_0); mn.visitInsn(POP); assertInvalid(); } public void testInvalidPop2() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(POP2); assertInvalid(); } public void testInvalidDup() { mn.visitInsn(LCONST_0); mn.visitInsn(DUP); assertInvalid(); } public void testInvalidDupx1() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(DUP_X1); assertInvalid(); } public void testInvalidDupx2() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(DUP_X2); assertInvalid(); } public void testInvalidDup2() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(DUP2); assertInvalid(); } public void testInvalidDup2x1() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(DUP2_X1); assertInvalid(); } public void testInvalidDup2x2() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(DUP2_X2); assertInvalid(); } public void testInvalidSwap() { mn.visitInsn(LCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(SWAP); assertInvalid(); } public void testInvalidGetLocal() { mn.visitVarInsn(ALOAD, 10); assertInvalid(); } public void testInvalidSetLocal() { mn.visitInsn(ACONST_NULL); mn.visitVarInsn(ASTORE, 10); assertInvalid(); } public void testInvalidEmptyStack() { mn.visitInsn(POP); assertInvalid(); } public void testInvalidFullStack() { mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); assertInvalid(); } public void testInconsistentStackHeights() { Label l0 = new Label(); mn.visitInsn(ICONST_0); mn.visitJumpInsn(IFEQ, l0); mn.visitInsn(ICONST_0); mn.visitLabel(l0); assertInvalid(); } public void testInvalidNewArray() { mn.visitInsn(ICONST_1); mn.visitIntInsn(NEWARRAY, -1); assertInvalid(); } public void testInvalidAload() { mn.visitInsn(ICONST_0); mn.visitVarInsn(ISTORE, 1); mn.visitVarInsn(ALOAD, 1); assertInvalid(); } public void testInvalidAstore() { mn.visitInsn(ICONST_0); mn.visitVarInsn(ASTORE, 1); assertInvalid(); } public void testInvalidIstore() { mn.visitInsn(ACONST_NULL); mn.visitVarInsn(ISTORE, 1); assertInvalid(); } public void testInvalidCheckcast() { mn.visitInsn(ICONST_0); mn.visitTypeInsn(CHECKCAST, "java/lang/String"); assertInvalid(); } public void testInvalidArraylength() { mn.visitInsn(ICONST_0); mn.visitInsn(ARRAYLENGTH); assertInvalid(); } public void testInvalidAthrow() { mn.visitInsn(ICONST_0); mn.visitInsn(ATHROW); assertInvalid(); } public void testInvalidIneg() { mn.visitInsn(FCONST_0); mn.visitInsn(INEG); assertInvalid(); } public void testInvalidIadd() { mn.visitInsn(FCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(IADD); assertInvalid(); } public void testInvalidIsub() { mn.visitInsn(ICONST_0); mn.visitInsn(FCONST_0); mn.visitInsn(ISUB); assertInvalid(); } public void testInvalidIastore() { mn.visitInsn(ICONST_1); mn.visitIntInsn(NEWARRAY, T_INT); mn.visitInsn(FCONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(IASTORE); assertInvalid(); } public void testInvalidFastore() { mn.visitInsn(ICONST_1); mn.visitIntInsn(NEWARRAY, T_FLOAT); mn.visitInsn(ICONST_0); mn.visitInsn(ICONST_0); mn.visitInsn(FASTORE); assertInvalid(); } public void testInvalidLastore() { mn.visitInsn(ICONST_1); mn.visitInsn(ICONST_0); mn.visitInsn(LCONST_0); mn.visitInsn(LASTORE); assertInvalid(); } public void testInvalidMultianewarray() { mn.visitInsn(FCONST_1); mn.visitInsn(ICONST_2); mn.visitMultiANewArrayInsn("[[I", 2); assertInvalid(); } public void testInvalidInvokevirtual() { mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "java/lang/Object"); mn.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "size", "()I"); assertInvalid(); } public void testInvalidInvokeinterface() { mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "java/util/List"); mn.visitInsn(FCONST_0); mn.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;"); assertInvalid(); } public void testInvalidRet() { mn.visitVarInsn(RET, 1); assertInvalid(); } public void testInvalidFalloff() { mn.visitMaxs(10, 10); try { a.analyze("C", mn); fail(); } catch (AnalyzerException e) { } catch (RuntimeException e) { } } public void testInvalidSubroutineFalloff() { Label l0 = new Label(); Label l1 = new Label(); mn.visitJumpInsn(GOTO, l0); mn.visitLabel(l1); mn.visitVarInsn(ASTORE, 1); mn.visitVarInsn(RET, 1); mn.visitLabel(l0); mn.visitJumpInsn(JSR, l1); mn.visitMaxs(10, 10); try { a.analyze("C", mn); fail(); } catch (AnalyzerException e) { } catch (RuntimeException e) { } } public void testNestedSubroutines() throws AnalyzerException { Label l0 = new Label(); Label l1 = new Label(); mn.visitJumpInsn(JSR, l0); mn.visitInsn(RETURN); mn.visitLabel(l0); mn.visitVarInsn(ASTORE, 1); mn.visitJumpInsn(JSR, l1); mn.visitJumpInsn(JSR, l1); mn.visitVarInsn(RET, 1); mn.visitLabel(l1); mn.visitVarInsn(ASTORE, 2); mn.visitVarInsn(RET, 2); assertValid(); } public void testSubroutineLocalsAccess() throws AnalyzerException { MethodVisitor mv = mn; mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l0, l1, null); mv.visitTryCatchBlock(l0, l2, l2, "java/lang/RuntimeException"); mv.visitLabel(l0); mv.visitJumpInsn(JSR, l3); mv.visitInsn(RETURN); mv.visitLabel(l1); mv.visitVarInsn(ASTORE, 1); mv.visitJumpInsn(JSR, l3); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitVarInsn(ASTORE, 2); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(RET, 2); mv.visitLabel(l2); mv.visitVarInsn(ASTORE, 4); mv.visitVarInsn(ALOAD, 4); mv.visitInsn(ATHROW); assertValid(); } public void _testOverlappingSubroutines() { // TODO currently Analyzer can not detect this situation. The problem // is that other overlapping subroutine situations are valid, such as // when a nested subroutine implicitely returns to its parent // subroutine, without a RET. Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mn.visitJumpInsn(JSR, l0); mn.visitJumpInsn(JSR, l1); mn.visitInsn(RETURN); mn.visitLabel(l0); mn.visitVarInsn(ASTORE, 1); mn.visitJumpInsn(GOTO, l2); mn.visitLabel(l1); mn.visitVarInsn(ASTORE, 1); mn.visitLabel(l2); mn.visitVarInsn(RET, 1); assertInvalid(); } public void testMerge() throws AnalyzerException { Label l0 = new Label(); mn.visitVarInsn(ALOAD, 0); mn.visitVarInsn(ASTORE, 1); mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "java/lang/Number"); mn.visitVarInsn(ASTORE, 2); mn.visitVarInsn(ALOAD, 0); mn.visitVarInsn(ASTORE, 3); mn.visitLabel(l0); mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "java/lang/Number"); mn.visitVarInsn(ASTORE, 1); mn.visitVarInsn(ALOAD, 0); mn.visitVarInsn(ASTORE, 2); mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "java/lang/Integer"); mn.visitVarInsn(ASTORE, 3); mn.visitJumpInsn(GOTO, l0); assertValid(); } public void testClassNotFound() { Label l0 = new Label(); mn.visitVarInsn(ALOAD, 0); mn.visitVarInsn(ASTORE, 1); mn.visitLabel(l0); mn.visitInsn(ACONST_NULL); mn.visitTypeInsn(CHECKCAST, "D"); mn.visitVarInsn(ASTORE, 1); mn.visitJumpInsn(GOTO, l0); mn.visitMaxs(10, 10); try { a.analyze("C", mn); fail(); } catch (Exception e) { } } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/SourceInterpreterTest.java0000644000175000017500000000473510462406024030152 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.List; import junit.framework.TestSuite; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; /** * SourceInterpreter tests. * * @author Eric Bruneton */ public class SourceInterpreterTest extends AbstractTest { public static TestSuite suite() throws Exception { return new SourceInterpreterTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassNode cn = new ClassNode(); cr.accept(cn, 0); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); Analyzer a = new Analyzer(new SourceInterpreter()); a.analyze(cn.name, method); } } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/SmallSetUnitTest.java0000644000175000017500000000460710452754520027056 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import java.util.Set; import junit.framework.TestCase; /** * SmallSet unit tests. * * @author Eric Bruneton */ public class SmallSetUnitTest extends TestCase { private final Object A = new Object(); private final Object B = new Object(); private final Object C = new Object(); private final Object D = new Object(); public void testSubsetUnion() { SmallSet s1 = new SmallSet(A, B); SmallSet s2 = new SmallSet(A, null); Set u = s1.union(s2); Set v = s2.union(s1); assertEquals(u, v); s1.remove(); } public void testDisjointUnion() { SmallSet s1 = new SmallSet(A, B); SmallSet s2 = new SmallSet(C, D); Set u = s1.union(s2); Set v = s2.union(s1); assertEquals(u, v); } } asm-3.3.2/test/conform/org/objectweb/asm/tree/analysis/AnalyzerUnitTest.java0000644000175000017500000001056210504156672027116 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree.analysis; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriterComputeMaxsUnitTest; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; import org.objectweb.asm.tree.MethodNode; /** * Analyzer unit tests for methods with JSR instructions. * * @author Eric Bruneton */ public class AnalyzerUnitTest extends ClassWriterComputeMaxsUnitTest { protected boolean isComputeMaxs() { return false; } protected void assertMaxs(final int maxStack, final int maxLocals) { mv.visitMaxs(maxStack, maxLocals); mv.visitEnd(); cw.visitEnd(); byte[] b = cw.toByteArray(); ClassReader cr = new ClassReader(b); cr.accept(new EmptyVisitor() { public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { if (name.equals("m")) { return new MethodNode(access, name, desc, signature, exceptions) { public void visitEnd() { Analyzer a = new Analyzer(new BasicInterpreter()); try { Frame[] frames = a.analyze("C", this); int mStack = 0; int mLocals = 0; for (int i = 0; i < frames.length; ++i) { if (frames[i] != null) { mStack = Math.max(mStack, frames[i].getStackSize()); mLocals = Math.max(mLocals, frames[i].getLocals()); } } assertEquals("maxStack", maxStack, mStack); assertEquals("maxLocals", maxLocals, mLocals); } catch (Exception e) { fail(e.getMessage()); } } }; } else { return new EmptyVisitor(); } } }, 0); try { TestClassLoader loader = new TestClassLoader(); Class c = loader.defineClass("C", b); c.newInstance(); } catch (Throwable t) { fail(t.getMessage()); } } protected void assertGraph(final String graph) { } } asm-3.3.2/test/conform/org/objectweb/asm/tree/InsnListUnitTest.java0000644000175000017500000005145310701747173025256 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.ListIterator; import java.util.NoSuchElementException; import junit.framework.TestCase; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; /** * InsnList unit tests. * * @author Eric Bruneton * @author Eugene Kuleshov */ public class InsnListUnitTest extends TestCase { InsnList l1; InsnList l2; InsnNode in1; InsnNode in2; protected void setUp() throws Exception { super.setUp(); InsnList.check = true; l1 = new InsnList(); l2 = new InsnList(); in1 = new InsnNode(0); in2 = new InsnNode(0); l2.add(in1); l2.add(in2); } protected void assertEquals( final AbstractInsnNode[] expected, final AbstractInsnNode[] value) { assertEquals(expected.length, value.length); for (int i = 0; i < value.length; ++i) { assertEquals(expected[i], value[i]); } } public void testSize() { assertEquals(0, l1.size()); } public void testGetFirst() { assertEquals(null, l1.getFirst()); } public void testGetLast() { assertEquals(null, l1.getLast()); } public void testInvalidGet() { try { l1.get(0); fail(); } catch (IndexOutOfBoundsException e) { } } public void testContains() { assertEquals(false, l1.contains(new InsnNode(0))); } public void testIterator() { InsnNode insn = new InsnNode(0); // iteration ListIterator it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); assertTrue(it.hasNext()); assertEquals(in2, it.next()); assertFalse(it.hasNext()); assertTrue(it.hasPrevious()); assertEquals(in2, it.previous()); assertTrue(it.hasPrevious()); assertEquals(in1, it.previous()); assertFalse(it.hasPrevious()); l2.add(insn); // remove() it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); assertTrue(it.hasNext()); assertEquals(in2, it.next()); assertTrue(it.hasNext()); it.remove(); // remove in2 assertTrue(it.hasNext()); assertEquals(insn, it.next()); assertFalse(it.hasNext()); assertTrue(it.hasPrevious()); it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); assertTrue(it.hasNext()); assertEquals(insn, it.next()); assertFalse(it.hasNext()); l2.remove(insn); l2.insert(in1, in2); // add() then next() it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); it.add(insn); assertEquals(in2, it.next()); l2.remove(insn); // add() then previous() it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); it.add(insn); assertEquals(insn, it.previous()); assertEquals(insn, it.next()); assertTrue(it.hasNext()); assertEquals(in2, it.next()); assertFalse(it.hasNext()); l2.remove(insn); // set() then previous() it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); it.set(insn); assertEquals(insn, it.previous()); assertEquals(insn, it.next()); assertTrue(it.hasNext()); l2.remove(insn); l2.insertBefore(in2, in1); // add() then next() it = l2.iterator(); assertTrue(it.hasNext()); assertEquals(in1, it.next()); it.set(insn); assertEquals(in2, it.next()); } public void testIterator2() { ListIterator it = l2.iterator(l2.size()); assertFalse(it.hasNext()); assertTrue(it.hasPrevious()); assertEquals(1, it.previousIndex()); assertEquals(in2, it.previous()); assertTrue(it.hasPrevious()); assertEquals(0, it.previousIndex()); assertEquals(in1, it.previous()); assertFalse(it.hasPrevious()); assertEquals(-1, it.previousIndex()); assertTrue(it.hasNext()); assertEquals(0, it.nextIndex()); assertEquals(in1, it.next()); assertTrue(it.hasNext()); assertEquals(1, it.nextIndex()); InsnNode insn = new InsnNode(0); it.add(insn); assertEquals(2, it.nextIndex()); assertEquals(in2, it.next()); assertFalse(it.hasNext()); assertEquals(3, it.nextIndex()); } public void testIterator3() { try { new InsnList().iterator().next(); fail(); } catch (NoSuchElementException e) { } } public void testInvalidIndexOf() { try { l1.indexOf(new InsnNode(0)); fail(); } catch (IllegalArgumentException e) { } } public void testToArray() { assertEquals(0, l1.toArray().length); } public void testInvalidSet() { try { l1.set(new InsnNode(0), new InsnNode(0)); fail(); } catch (IllegalArgumentException e) { } } public void testSet() { l1.add(new InsnNode(0)); AbstractInsnNode insn = new InsnNode(0); l1.set(l1.getFirst(), insn); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); l1.remove(insn); l1.add(new InsnNode(0)); l1.set(l1.get(0), insn); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); l1.remove(insn); l1.add(new InsnNode(0)); l1.add(new InsnNode(0)); l1.set(l1.get(1), insn); assertEquals(2, l1.size()); assertEquals(insn, l1.get(1)); } public void testInvalidAdd() { try { l1.add(in1); fail(); } catch (IllegalArgumentException e) { } } public void testAddEmpty() { InsnNode insn = new InsnNode(0); l1.add(insn); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(0, l1.indexOf(insn)); assertEquals(new AbstractInsnNode[] { insn }, l1.toArray()); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testAddNonEmpty() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.add(insn); assertEquals(2, l1.size()); assertEquals(insn, l1.getLast()); assertEquals(1, l1.indexOf(insn)); assertEquals(insn, l1.get(1)); assertEquals(true, l1.contains(insn)); } public void testAddEmptyList() { l1.add(new InsnList()); assertEquals(0, l1.size()); assertEquals(null, l1.getFirst()); assertEquals(null, l1.getLast()); assertEquals(new AbstractInsnNode[0], l1.toArray()); } public void testInvalidAddAll() { try { l1.add(l1); fail(); } catch (IllegalArgumentException e) { } } public void testAddAllEmpty() { l1.add(l2); assertEquals(2, l1.size()); assertEquals(in1, l1.getFirst()); assertEquals(in2, l1.getLast()); assertEquals(in1, l1.get(0)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(in1)); assertEquals(1, l1.indexOf(in2)); assertEquals(new AbstractInsnNode[] { in1, in2 }, l1.toArray()); } public void testAddAllNonEmpty() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.add(l2); assertEquals(3, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(in2, l1.getLast()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(insn)); assertEquals(1, l1.indexOf(in1)); assertEquals(2, l1.indexOf(in2)); assertEquals(new AbstractInsnNode[] { insn, in1, in2 }, l1.toArray()); } public void testInvalidInsert() { try { l1.insert(in1); fail(); } catch (IllegalArgumentException e) { } } public void testInsertEmpty() { InsnNode insn = new InsnNode(0); l1.insert(insn); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(0, l1.indexOf(insn)); assertEquals(new AbstractInsnNode[] { insn }, l1.toArray()); } public void testInsertNonEmpty() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.insert(insn); assertEquals(2, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(0, l1.indexOf(insn)); } public void testInvalidInsertAll() { try { l1.insert(l1); fail(); } catch (IllegalArgumentException e) { } } public void testInsertAllEmptyList() { l1.insert(new InsnList()); assertEquals(0, l1.size()); assertEquals(null, l1.getFirst()); assertEquals(null, l1.getLast()); assertEquals(new AbstractInsnNode[0], l1.toArray()); } public void testInsertAllEmpty() { l1.insert(l2); assertEquals(2, l1.size(), 2); assertEquals(in1, l1.getFirst()); assertEquals(in2, l1.getLast()); assertEquals(in1, l1.get(0)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(in1)); assertEquals(1, l1.indexOf(in2)); assertEquals(new AbstractInsnNode[] { in1, in2 }, l1.toArray()); } public void testInsertAllNonEmpty() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.insert(l2); assertEquals(3, l1.size()); assertEquals(in1, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(in1, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(in1)); assertEquals(1, l1.indexOf(in2)); assertEquals(2, l1.indexOf(insn)); assertEquals(new AbstractInsnNode[] { in1, in2, insn }, l1.toArray()); } public void testInvalidInsert2() { try { l1.insert(new InsnNode(0), new InsnNode(0)); fail(); } catch (IllegalArgumentException e) { } } public void testInsert2NotLast() { InsnNode insn = new InsnNode(0); l2.insert(in1, insn); assertEquals(3, l2.size()); assertEquals(in1, l2.getFirst()); assertEquals(in2, l2.getLast()); assertEquals(in1, l2.get(0)); assertEquals(true, l2.contains(insn)); assertEquals(1, l2.indexOf(insn)); assertEquals(new AbstractInsnNode[] { in1, insn, in2 }, l2.toArray()); } public void testInsert2Last() { InsnNode insn = new InsnNode(0); l2.insert(in2, insn); assertEquals(3, l2.size()); assertEquals(in1, l2.getFirst()); assertEquals(insn, l2.getLast()); assertEquals(in1, l2.get(0)); assertEquals(true, l2.contains(insn)); assertEquals(2, l2.indexOf(insn)); assertEquals(new AbstractInsnNode[] { in1, in2, insn }, l2.toArray()); } public void testInsertBefore() { InsnNode insn = new InsnNode(0); l2.insertBefore(in2, insn); assertEquals(3, l2.size()); assertEquals(in1, l2.getFirst()); assertEquals(in2, l2.getLast()); assertEquals(insn, l2.get(1)); assertEquals(true, l2.contains(insn)); assertEquals(1, l2.indexOf(insn)); assertEquals(new AbstractInsnNode[] { in1, insn, in2 }, l2.toArray()); } public void testInsertBeforeFirst() { InsnNode insn = new InsnNode(0); l2.insertBefore(in1, insn); assertEquals(3, l2.size()); assertEquals(insn, l2.getFirst()); assertEquals(in2, l2.getLast()); assertEquals(insn, l2.get(0)); assertEquals(true, l2.contains(insn)); assertEquals(0, l2.indexOf(insn)); assertEquals(new AbstractInsnNode[] { insn, in1, in2 }, l2.toArray()); } public void testInvalidInsertBefore() { try { l1.insertBefore(new InsnNode(0), new InsnNode(0)); fail(); } catch (IllegalArgumentException e) { } } public void testInvalidInsertAll2() { try { l1.insert(new InsnNode(0), new InsnList()); fail(); } catch (IllegalArgumentException e) { } } public void testInsertAll2EmptyList() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.insert(insn, new InsnList()); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(new AbstractInsnNode[] { insn }, l1.toArray()); } public void testInsertAll2NotLast() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.add(new InsnNode(0)); l1.insert(insn, l2); assertEquals(4, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(insn)); assertEquals(1, l1.indexOf(in1)); assertEquals(2, l1.indexOf(in2)); } public void testInsertAll2Last() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.insert(insn, l2); assertEquals(3, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(in2, l1.getLast()); assertEquals(insn, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(0, l1.indexOf(insn)); assertEquals(1, l1.indexOf(in1)); assertEquals(2, l1.indexOf(in2)); assertEquals(new AbstractInsnNode[] { insn, in1, in2 }, l1.toArray()); } public void testInvalidInsertBeforeAll() { try { l1.insertBefore(new InsnNode(0), new InsnList()); fail(); } catch (IllegalArgumentException e) { } } public void testInsertBeforeAll2EmptyList() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.insertBefore(insn, new InsnList()); assertEquals(1, l1.size()); assertEquals(insn, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(new AbstractInsnNode[] { insn }, l1.toArray()); } public void testInsertBeforeAll2NotLast() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.add(insn); l1.insertBefore(insn, l2); assertEquals(4, l1.size()); assertEquals(in1, l1.get(1)); assertEquals(in2, l1.get(2)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(3, l1.indexOf(insn)); assertEquals(1, l1.indexOf(in1)); assertEquals(2, l1.indexOf(in2)); } public void testInsertBeforeAll2First() { InsnNode insn = new InsnNode(0); l1.insert(insn); l1.insertBefore(insn, l2); assertEquals(3, l1.size()); assertEquals(in1, l1.getFirst()); assertEquals(insn, l1.getLast()); assertEquals(in1, l1.get(0)); assertEquals(true, l1.contains(insn)); assertEquals(true, l1.contains(in1)); assertEquals(true, l1.contains(in2)); assertEquals(2, l1.indexOf(insn)); assertEquals(0, l1.indexOf(in1)); assertEquals(1, l1.indexOf(in2)); assertEquals(new AbstractInsnNode[] { in1, in2, insn }, l1.toArray()); } public void testInvalidRemove() { try { l1.remove(new InsnNode(0)); } catch (IllegalArgumentException e) { } } public void testRemoveSingle() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.remove(insn); assertEquals(0, l1.size()); assertEquals(null, l1.getFirst()); assertEquals(null, l1.getLast()); assertEquals(false, l1.contains(insn)); assertEquals(new AbstractInsnNode[0], l1.toArray()); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testRemoveFirst() { InsnNode insn = new InsnNode(0); l1.add(insn); l1.add(new InsnNode(0)); l1.remove(insn); assertEquals(false, l1.contains(insn)); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testRemoveMiddle() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.add(insn); l1.add(new InsnNode(0)); l1.remove(insn); assertEquals(false, l1.contains(insn)); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testRemoveLast() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.add(insn); l1.remove(insn); assertEquals(false, l1.contains(insn)); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testClear() { InsnNode insn = new InsnNode(0); l1.add(new InsnNode(0)); l1.add(insn); l1.add(new InsnNode(0)); l1.clear(); assertEquals(0, l1.size()); assertEquals(null, l1.getFirst()); assertEquals(null, l1.getLast()); assertEquals(false, l1.contains(insn)); assertEquals(new AbstractInsnNode[0], l1.toArray()); assertEquals(null, insn.getPrevious()); assertEquals(null, insn.getNext()); } public void testAcceptor1() { l1.add(new InsnNode(55)); l1.add(new InsnNode(77)); final InsnList lst = new InsnList(); l1.accept(new MethodAdapter(null) { public void visitInsn(int opcode) { lst.add(new InsnNode(opcode)); } }); assertEquals(55, lst.get(0).opcode); assertEquals(77, lst.get(1).opcode); } public void testResetLabels() throws Exception { LabelNode labelNode = new LabelNode(); l1.add(new InsnNode(55)); l1.add(labelNode); l1.add(new InsnNode(55)); Label label = labelNode.getLabel(); assertNotNull(label); l1.resetLabels(); assertNotSame(label, labelNode.getLabel()); } } asm-3.3.2/test/conform/org/objectweb/asm/tree/ClassNodeTest.java0000644000175000017500000000714110474575114024522 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.objectweb.asm.AbstractTest; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; import junit.framework.TestSuite; /** * ClassNode tests. * * @author Eric Bruneton */ public class ClassNodeTest extends AbstractTest { public static TestSuite suite() throws Exception { return new ClassNodeTest().getSuite(); } public void test() throws Exception { ClassReader cr = new ClassReader(is); ClassNode cn = new ClassNode(); cr.accept(cn, 0); // clone instructions for testing clone methods for (int i = 0; i < cn.methods.size(); ++i) { MethodNode mn = (MethodNode) cn.methods.get(i); Iterator it = mn.instructions.iterator(); Map m = new HashMap() { public Object get(final Object o) { return o; } }; while (it.hasNext()) { AbstractInsnNode insn = (AbstractInsnNode) it.next(); mn.instructions.set(insn, insn.clone(m)); } } // test accept with visitors that remove class members cn.accept(new EmptyVisitor() { public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { return null; } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { return null; } }); ClassWriter cw = new ClassWriter(0); cn.accept(cw); assertEquals(cr, new ClassReader(cw.toByteArray())); } } asm-3.3.2/test/conform/org/objectweb/asm/tree/ClassNodeUnitTest.java0000644000175000017500000001142710474575114025364 0ustar twernertwerner/*** * ASM tests * Copyright (c) 2002-2005 France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.tree; import org.objectweb.asm.Opcodes; import junit.framework.TestCase; /** * ClassNode unit tests. * * @author Eric Bruneton */ public class ClassNodeUnitTest extends TestCase implements Opcodes { public void testFrameNode() { FrameNode fn = new FrameNode(F_SAME, 0, null, 0, null); assertEquals(AbstractInsnNode.FRAME, fn.getType()); } public void testInsnNode() { InsnNode in = new InsnNode(NOP); assertEquals(in.getOpcode(), NOP); assertEquals(AbstractInsnNode.INSN, in.getType()); } public void testIntInsnNode() { IntInsnNode iin = new IntInsnNode(BIPUSH, 0); iin.setOpcode(SIPUSH); assertEquals(SIPUSH, iin.getOpcode()); assertEquals(AbstractInsnNode.INT_INSN, iin.getType()); } public void testVarInsnNode() { VarInsnNode vn = new VarInsnNode(ALOAD, 0); vn.setOpcode(ASTORE); assertEquals(ASTORE, vn.getOpcode()); assertEquals(AbstractInsnNode.VAR_INSN, vn.getType()); } public void testTypeInsnNode() { TypeInsnNode tin = new TypeInsnNode(NEW, "java/lang/Object"); tin.setOpcode(CHECKCAST); assertEquals(CHECKCAST, tin.getOpcode()); assertEquals(AbstractInsnNode.TYPE_INSN, tin.getType()); } public void testFieldInsnNode() { FieldInsnNode fn = new FieldInsnNode(GETSTATIC, "owner", "name", "I"); fn.setOpcode(PUTSTATIC); assertEquals(PUTSTATIC, fn.getOpcode()); assertEquals(AbstractInsnNode.FIELD_INSN, fn.getType()); } public void testMethodInsnNode() { MethodInsnNode mn = new MethodInsnNode(INVOKESTATIC, "owner", "name", "I"); mn.setOpcode(INVOKESPECIAL); assertEquals(INVOKESPECIAL, mn.getOpcode()); assertEquals(AbstractInsnNode.METHOD_INSN, mn.getType()); } public void testJumpInsnNode() { JumpInsnNode jn = new JumpInsnNode(GOTO, new LabelNode()); jn.setOpcode(IFEQ); assertEquals(IFEQ, jn.getOpcode()); assertEquals(AbstractInsnNode.JUMP_INSN, jn.getType()); } public void testLabelNode() { LabelNode ln = new LabelNode(); assertEquals(AbstractInsnNode.LABEL, ln.getType()); assertTrue(ln.getLabel() != null); } public void testIincInsnNode() { IincInsnNode iincn = new IincInsnNode(1, 1); assertEquals(AbstractInsnNode.IINC_INSN, iincn.getType()); } public void testLdcInsnNode() { LdcInsnNode ldcn = new LdcInsnNode("s"); assertEquals(AbstractInsnNode.LDC_INSN, ldcn.getType()); } public void testLookupSwitchInsnNode() { LookupSwitchInsnNode lsn = new LookupSwitchInsnNode(null, null, null); assertEquals(AbstractInsnNode.LOOKUPSWITCH_INSN, lsn.getType()); } public void testTableSwitchInsnNode() { TableSwitchInsnNode tsn = new TableSwitchInsnNode(0, 1, null, null); assertEquals(AbstractInsnNode.TABLESWITCH_INSN, tsn.getType()); } public void testMultiANewArrayInsnNode() { MultiANewArrayInsnNode manan = new MultiANewArrayInsnNode("[[I", 2); assertEquals(AbstractInsnNode.MULTIANEWARRAY_INSN, manan.getType()); } } asm-3.3.2/test/conform/basicinterpreter.xml0000644000175000017500000000113710452754520020754 0ustar twernertwerner asm-3.3.2/test/conform/classwritercomputemaxs.xml0000644000175000017500000000114310452754520022234 0ustar twernertwerner asm-3.3.2/test/conform/asmifier.xml0000644000175000017500000000153510452754520017210 0ustar twernertwerner asm-3.3.2/test/conform/classwritercomputeframes.xml0000644000175000017500000000663510452754520022554 0ustar twernertwerner asm-3.3.2/test/conform/classwriter.xml0000644000175000017500000000113010140406020017721 0ustar twernertwerner asm-3.3.2/test/conform/classnode.xml0000644000175000017500000000113010140406020017332 0ustar twernertwerner asm-3.3.2/test/conform/signaturewriter.xml0000644000175000017500000000113410474515547020652 0ustar twernertwerner asm-3.3.2/test/build.xml0000644000175000017500000002135511101031415015026 0ustar twernertwerner asm-3.3.2/.cvsignore0000644000175000017500000000004010352050112014214 0ustar twernertwerneroutput plugin.xml cobertura.ser asm-3.3.2/build.xml0000644000175000017500000006763511225010263014067 0ustar twernertwerner