jaroslav@810: /* jaroslav@810: * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. jaroslav@810: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@810: * jaroslav@810: * This code is free software; you can redistribute it and/or modify it jaroslav@810: * under the terms of the GNU General Public License version 2 only, as jaroslav@810: * published by the Free Software Foundation. Oracle designates this jaroslav@810: * particular file as subject to the "Classpath" exception as provided jaroslav@810: * by Oracle in the LICENSE file that accompanied this code. jaroslav@810: * jaroslav@810: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@810: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@810: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@810: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@810: * accompanied this code). jaroslav@810: * jaroslav@810: * You should have received a copy of the GNU General Public License version jaroslav@810: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@810: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@810: * jaroslav@810: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@810: * or visit www.oracle.com if you need additional information or have any jaroslav@810: * questions. jaroslav@810: */ jaroslav@810: package org.apidesign.vm4brwsr; jaroslav@810: jaroslav@810: import java.io.ByteArrayInputStream; jaroslav@810: import java.io.DataInputStream; jaroslav@810: import java.io.IOException; jaroslav@810: import java.io.InputStream; jaroslav@810: import org.apidesign.bck2brwsr.core.JavaScriptBody; jaroslav@810: import org.apidesign.bck2brwsr.core.JavaScriptPrototype; jaroslav@810: jaroslav@810: /** This is a byte code parser heavily based on original code of JavaP utility. jaroslav@810: * As such I decided to keep the original Oracle's GPLv2 header. jaroslav@810: * jaroslav@810: * @author Jaroslav Tulach jaroslav@810: */ jaroslav@810: final class ByteCodeParser { jaroslav@810: private ByteCodeParser() { jaroslav@810: } jaroslav@810: jaroslav@810: /* Class File Constants */ jaroslav@810: public static final int JAVA_MAGIC = 0xcafebabe; jaroslav@810: public static final int JAVA_VERSION = 45; jaroslav@810: public static final int JAVA_MINOR_VERSION = 3; jaroslav@810: jaroslav@810: /* Constant table */ jaroslav@810: public static final int CONSTANT_UTF8 = 1; jaroslav@810: public static final int CONSTANT_UNICODE = 2; jaroslav@810: public static final int CONSTANT_INTEGER = 3; jaroslav@810: public static final int CONSTANT_FLOAT = 4; jaroslav@810: public static final int CONSTANT_LONG = 5; jaroslav@810: public static final int CONSTANT_DOUBLE = 6; jaroslav@810: public static final int CONSTANT_CLASS = 7; jaroslav@810: public static final int CONSTANT_STRING = 8; jaroslav@810: public static final int CONSTANT_FIELD = 9; jaroslav@810: public static final int CONSTANT_METHOD = 10; jaroslav@810: public static final int CONSTANT_INTERFACEMETHOD = 11; jaroslav@810: public static final int CONSTANT_NAMEANDTYPE = 12; jaroslav@1639: public static final int CONSTANT_METHODHANDLE = 15; jaroslav@1639: public static final int CONSTANT_METHODTYPE = 16; jaroslav@1639: public static final int CONSTANT_INVOKEDYNAMIC = 18; jaroslav@810: jaroslav@810: /* Access Flags */ jaroslav@810: public static final int ACC_PUBLIC = 0x00000001; jaroslav@810: public static final int ACC_PRIVATE = 0x00000002; jaroslav@810: public static final int ACC_PROTECTED = 0x00000004; jaroslav@810: public static final int ACC_STATIC = 0x00000008; jaroslav@810: public static final int ACC_FINAL = 0x00000010; jaroslav@810: public static final int ACC_SYNCHRONIZED = 0x00000020; jaroslav@810: public static final int ACC_SUPER = 0x00000020; jaroslav@810: public static final int ACC_VOLATILE = 0x00000040; jaroslav@810: public static final int ACC_TRANSIENT = 0x00000080; jaroslav@810: public static final int ACC_NATIVE = 0x00000100; jaroslav@810: public static final int ACC_INTERFACE = 0x00000200; jaroslav@810: public static final int ACC_ABSTRACT = 0x00000400; jaroslav@810: public static final int ACC_STRICT = 0x00000800; jaroslav@810: public static final int ACC_EXPLICIT = 0x00001000; jaroslav@810: public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute jaroslav@810: jaroslav@810: /* Type codes for StackMap attribute */ jaroslav@810: public static final int ITEM_Bogus =0; // an unknown or uninitialized value jaroslav@810: public static final int ITEM_Integer =1; // a 32-bit integer jaroslav@810: public static final int ITEM_Float =2; // not used jaroslav@810: public static final int ITEM_Double =3; // not used jaroslav@810: public static final int ITEM_Long =4; // a 64-bit integer jaroslav@810: public static final int ITEM_Null =5; // the type of null jaroslav@810: public static final int ITEM_InitObject =6; // "this" in constructor jaroslav@810: public static final int ITEM_Object =7; // followed by 2-byte index of class name jaroslav@810: public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new" jaroslav@810: jaroslav@810: /* Constants used in StackMapTable attribute */ jaroslav@810: public static final int SAME_FRAME_BOUND = 64; jaroslav@810: public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; jaroslav@810: public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; jaroslav@810: public static final int SAME_FRAME_EXTENDED = 251; jaroslav@810: public static final int FULL_FRAME = 255; jaroslav@810: jaroslav@810: /* Opcodes */ jaroslav@810: public static final int opc_dead = -2; jaroslav@810: public static final int opc_label = -1; jaroslav@810: public static final int opc_nop = 0; jaroslav@810: public static final int opc_aconst_null = 1; jaroslav@810: public static final int opc_iconst_m1 = 2; jaroslav@810: public static final int opc_iconst_0 = 3; jaroslav@810: public static final int opc_iconst_1 = 4; jaroslav@810: public static final int opc_iconst_2 = 5; jaroslav@810: public static final int opc_iconst_3 = 6; jaroslav@810: public static final int opc_iconst_4 = 7; jaroslav@810: public static final int opc_iconst_5 = 8; jaroslav@810: public static final int opc_lconst_0 = 9; jaroslav@810: public static final int opc_lconst_1 = 10; jaroslav@810: public static final int opc_fconst_0 = 11; jaroslav@810: public static final int opc_fconst_1 = 12; jaroslav@810: public static final int opc_fconst_2 = 13; jaroslav@810: public static final int opc_dconst_0 = 14; jaroslav@810: public static final int opc_dconst_1 = 15; jaroslav@810: public static final int opc_bipush = 16; jaroslav@810: public static final int opc_sipush = 17; jaroslav@810: public static final int opc_ldc = 18; jaroslav@810: public static final int opc_ldc_w = 19; jaroslav@810: public static final int opc_ldc2_w = 20; jaroslav@810: public static final int opc_iload = 21; jaroslav@810: public static final int opc_lload = 22; jaroslav@810: public static final int opc_fload = 23; jaroslav@810: public static final int opc_dload = 24; jaroslav@810: public static final int opc_aload = 25; jaroslav@810: public static final int opc_iload_0 = 26; jaroslav@810: public static final int opc_iload_1 = 27; jaroslav@810: public static final int opc_iload_2 = 28; jaroslav@810: public static final int opc_iload_3 = 29; jaroslav@810: public static final int opc_lload_0 = 30; jaroslav@810: public static final int opc_lload_1 = 31; jaroslav@810: public static final int opc_lload_2 = 32; jaroslav@810: public static final int opc_lload_3 = 33; jaroslav@810: public static final int opc_fload_0 = 34; jaroslav@810: public static final int opc_fload_1 = 35; jaroslav@810: public static final int opc_fload_2 = 36; jaroslav@810: public static final int opc_fload_3 = 37; jaroslav@810: public static final int opc_dload_0 = 38; jaroslav@810: public static final int opc_dload_1 = 39; jaroslav@810: public static final int opc_dload_2 = 40; jaroslav@810: public static final int opc_dload_3 = 41; jaroslav@810: public static final int opc_aload_0 = 42; jaroslav@810: public static final int opc_aload_1 = 43; jaroslav@810: public static final int opc_aload_2 = 44; jaroslav@810: public static final int opc_aload_3 = 45; jaroslav@810: public static final int opc_iaload = 46; jaroslav@810: public static final int opc_laload = 47; jaroslav@810: public static final int opc_faload = 48; jaroslav@810: public static final int opc_daload = 49; jaroslav@810: public static final int opc_aaload = 50; jaroslav@810: public static final int opc_baload = 51; jaroslav@810: public static final int opc_caload = 52; jaroslav@810: public static final int opc_saload = 53; jaroslav@810: public static final int opc_istore = 54; jaroslav@810: public static final int opc_lstore = 55; jaroslav@810: public static final int opc_fstore = 56; jaroslav@810: public static final int opc_dstore = 57; jaroslav@810: public static final int opc_astore = 58; jaroslav@810: public static final int opc_istore_0 = 59; jaroslav@810: public static final int opc_istore_1 = 60; jaroslav@810: public static final int opc_istore_2 = 61; jaroslav@810: public static final int opc_istore_3 = 62; jaroslav@810: public static final int opc_lstore_0 = 63; jaroslav@810: public static final int opc_lstore_1 = 64; jaroslav@810: public static final int opc_lstore_2 = 65; jaroslav@810: public static final int opc_lstore_3 = 66; jaroslav@810: public static final int opc_fstore_0 = 67; jaroslav@810: public static final int opc_fstore_1 = 68; jaroslav@810: public static final int opc_fstore_2 = 69; jaroslav@810: public static final int opc_fstore_3 = 70; jaroslav@810: public static final int opc_dstore_0 = 71; jaroslav@810: public static final int opc_dstore_1 = 72; jaroslav@810: public static final int opc_dstore_2 = 73; jaroslav@810: public static final int opc_dstore_3 = 74; jaroslav@810: public static final int opc_astore_0 = 75; jaroslav@810: public static final int opc_astore_1 = 76; jaroslav@810: public static final int opc_astore_2 = 77; jaroslav@810: public static final int opc_astore_3 = 78; jaroslav@810: public static final int opc_iastore = 79; jaroslav@810: public static final int opc_lastore = 80; jaroslav@810: public static final int opc_fastore = 81; jaroslav@810: public static final int opc_dastore = 82; jaroslav@810: public static final int opc_aastore = 83; jaroslav@810: public static final int opc_bastore = 84; jaroslav@810: public static final int opc_castore = 85; jaroslav@810: public static final int opc_sastore = 86; jaroslav@810: public static final int opc_pop = 87; jaroslav@810: public static final int opc_pop2 = 88; jaroslav@810: public static final int opc_dup = 89; jaroslav@810: public static final int opc_dup_x1 = 90; jaroslav@810: public static final int opc_dup_x2 = 91; jaroslav@810: public static final int opc_dup2 = 92; jaroslav@810: public static final int opc_dup2_x1 = 93; jaroslav@810: public static final int opc_dup2_x2 = 94; jaroslav@810: public static final int opc_swap = 95; jaroslav@810: public static final int opc_iadd = 96; jaroslav@810: public static final int opc_ladd = 97; jaroslav@810: public static final int opc_fadd = 98; jaroslav@810: public static final int opc_dadd = 99; jaroslav@810: public static final int opc_isub = 100; jaroslav@810: public static final int opc_lsub = 101; jaroslav@810: public static final int opc_fsub = 102; jaroslav@810: public static final int opc_dsub = 103; jaroslav@810: public static final int opc_imul = 104; jaroslav@810: public static final int opc_lmul = 105; jaroslav@810: public static final int opc_fmul = 106; jaroslav@810: public static final int opc_dmul = 107; jaroslav@810: public static final int opc_idiv = 108; jaroslav@810: public static final int opc_ldiv = 109; jaroslav@810: public static final int opc_fdiv = 110; jaroslav@810: public static final int opc_ddiv = 111; jaroslav@810: public static final int opc_irem = 112; jaroslav@810: public static final int opc_lrem = 113; jaroslav@810: public static final int opc_frem = 114; jaroslav@810: public static final int opc_drem = 115; jaroslav@810: public static final int opc_ineg = 116; jaroslav@810: public static final int opc_lneg = 117; jaroslav@810: public static final int opc_fneg = 118; jaroslav@810: public static final int opc_dneg = 119; jaroslav@810: public static final int opc_ishl = 120; jaroslav@810: public static final int opc_lshl = 121; jaroslav@810: public static final int opc_ishr = 122; jaroslav@810: public static final int opc_lshr = 123; jaroslav@810: public static final int opc_iushr = 124; jaroslav@810: public static final int opc_lushr = 125; jaroslav@810: public static final int opc_iand = 126; jaroslav@810: public static final int opc_land = 127; jaroslav@810: public static final int opc_ior = 128; jaroslav@810: public static final int opc_lor = 129; jaroslav@810: public static final int opc_ixor = 130; jaroslav@810: public static final int opc_lxor = 131; jaroslav@810: public static final int opc_iinc = 132; jaroslav@810: public static final int opc_i2l = 133; jaroslav@810: public static final int opc_i2f = 134; jaroslav@810: public static final int opc_i2d = 135; jaroslav@810: public static final int opc_l2i = 136; jaroslav@810: public static final int opc_l2f = 137; jaroslav@810: public static final int opc_l2d = 138; jaroslav@810: public static final int opc_f2i = 139; jaroslav@810: public static final int opc_f2l = 140; jaroslav@810: public static final int opc_f2d = 141; jaroslav@810: public static final int opc_d2i = 142; jaroslav@810: public static final int opc_d2l = 143; jaroslav@810: public static final int opc_d2f = 144; jaroslav@810: public static final int opc_i2b = 145; jaroslav@810: public static final int opc_int2byte = 145; jaroslav@810: public static final int opc_i2c = 146; jaroslav@810: public static final int opc_int2char = 146; jaroslav@810: public static final int opc_i2s = 147; jaroslav@810: public static final int opc_int2short = 147; jaroslav@810: public static final int opc_lcmp = 148; jaroslav@810: public static final int opc_fcmpl = 149; jaroslav@810: public static final int opc_fcmpg = 150; jaroslav@810: public static final int opc_dcmpl = 151; jaroslav@810: public static final int opc_dcmpg = 152; jaroslav@810: public static final int opc_ifeq = 153; jaroslav@810: public static final int opc_ifne = 154; jaroslav@810: public static final int opc_iflt = 155; jaroslav@810: public static final int opc_ifge = 156; jaroslav@810: public static final int opc_ifgt = 157; jaroslav@810: public static final int opc_ifle = 158; jaroslav@810: public static final int opc_if_icmpeq = 159; jaroslav@810: public static final int opc_if_icmpne = 160; jaroslav@810: public static final int opc_if_icmplt = 161; jaroslav@810: public static final int opc_if_icmpge = 162; jaroslav@810: public static final int opc_if_icmpgt = 163; jaroslav@810: public static final int opc_if_icmple = 164; jaroslav@810: public static final int opc_if_acmpeq = 165; jaroslav@810: public static final int opc_if_acmpne = 166; jaroslav@810: public static final int opc_goto = 167; jaroslav@810: public static final int opc_jsr = 168; jaroslav@810: public static final int opc_ret = 169; jaroslav@810: public static final int opc_tableswitch = 170; jaroslav@810: public static final int opc_lookupswitch = 171; jaroslav@810: public static final int opc_ireturn = 172; jaroslav@810: public static final int opc_lreturn = 173; jaroslav@810: public static final int opc_freturn = 174; jaroslav@810: public static final int opc_dreturn = 175; jaroslav@810: public static final int opc_areturn = 176; jaroslav@810: public static final int opc_return = 177; jaroslav@810: public static final int opc_getstatic = 178; jaroslav@810: public static final int opc_putstatic = 179; jaroslav@810: public static final int opc_getfield = 180; jaroslav@810: public static final int opc_putfield = 181; jaroslav@810: public static final int opc_invokevirtual = 182; jaroslav@810: public static final int opc_invokenonvirtual = 183; jaroslav@810: public static final int opc_invokespecial = 183; jaroslav@810: public static final int opc_invokestatic = 184; jaroslav@810: public static final int opc_invokeinterface = 185; jaroslav@810: // public static final int opc_xxxunusedxxx = 186; jaroslav@810: public static final int opc_new = 187; jaroslav@810: public static final int opc_newarray = 188; jaroslav@810: public static final int opc_anewarray = 189; jaroslav@810: public static final int opc_arraylength = 190; jaroslav@810: public static final int opc_athrow = 191; jaroslav@810: public static final int opc_checkcast = 192; jaroslav@810: public static final int opc_instanceof = 193; jaroslav@810: public static final int opc_monitorenter = 194; jaroslav@810: public static final int opc_monitorexit = 195; jaroslav@810: public static final int opc_wide = 196; jaroslav@810: public static final int opc_multianewarray = 197; jaroslav@810: public static final int opc_ifnull = 198; jaroslav@810: public static final int opc_ifnonnull = 199; jaroslav@810: public static final int opc_goto_w = 200; jaroslav@810: public static final int opc_jsr_w = 201; jaroslav@810: /* Pseudo-instructions */ jaroslav@810: public static final int opc_bytecode = 203; jaroslav@810: public static final int opc_try = 204; jaroslav@810: public static final int opc_endtry = 205; jaroslav@810: public static final int opc_catch = 206; jaroslav@810: public static final int opc_var = 207; jaroslav@810: public static final int opc_endvar = 208; jaroslav@810: public static final int opc_localsmap = 209; jaroslav@810: public static final int opc_stackmap = 210; jaroslav@810: /* PicoJava prefixes */ jaroslav@810: public static final int opc_nonpriv = 254; jaroslav@810: public static final int opc_priv = 255; jaroslav@810: jaroslav@1471: /* Wide instructions * jaroslav@810: public static final int opc_iload_w = (opc_wide<<8)|opc_iload; jaroslav@810: public static final int opc_lload_w = (opc_wide<<8)|opc_lload; jaroslav@810: public static final int opc_fload_w = (opc_wide<<8)|opc_fload; jaroslav@810: public static final int opc_dload_w = (opc_wide<<8)|opc_dload; jaroslav@810: public static final int opc_aload_w = (opc_wide<<8)|opc_aload; jaroslav@810: public static final int opc_istore_w = (opc_wide<<8)|opc_istore; jaroslav@810: public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore; jaroslav@810: public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore; jaroslav@810: public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore; jaroslav@810: public static final int opc_astore_w = (opc_wide<<8)|opc_astore; jaroslav@810: public static final int opc_ret_w = (opc_wide<<8)|opc_ret; jaroslav@810: public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc; jaroslav@1471: */ jaroslav@810: static class AnnotationParser { jaroslav@810: jaroslav@810: private final boolean textual; jaroslav@810: private final boolean iterateArray; jaroslav@810: jaroslav@810: protected AnnotationParser(boolean textual, boolean iterateArray) { jaroslav@810: this.textual = textual; jaroslav@810: this.iterateArray = iterateArray; jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitAnnotationStart(String type, boolean top) throws IOException { jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitAnnotationEnd(String type, boolean top) throws IOException { jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitValueStart(String attrName, char type) throws IOException { jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitValueEnd(String attrName, char type) throws IOException { jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitAttr( jaroslav@810: String annoType, String attr, String attrType, String value) throws IOException { jaroslav@810: } jaroslav@810: jaroslav@810: protected void visitEnumAttr( jaroslav@810: String annoType, String attr, String attrType, String value) throws IOException { jaroslav@810: visitAttr(annoType, attr, attrType, value); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Initialize the parsing with constant pool from jaroslav@810: * cd. jaroslav@810: * jaroslav@810: * @param attr the attribute defining annotations jaroslav@810: * @param cd constant pool jaroslav@810: * @throws IOException in case I/O fails jaroslav@810: */ jaroslav@810: public final void parse(byte[] attr, ClassData cd) throws IOException { jaroslav@810: ByteArrayInputStream is = new ByteArrayInputStream(attr); jaroslav@810: DataInputStream dis = new DataInputStream(is); jaroslav@810: try { jaroslav@810: read(dis, cd); jaroslav@810: } finally { jaroslav@810: is.close(); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private void read(DataInputStream dis, ClassData cd) throws IOException { jaroslav@810: int cnt = dis.readUnsignedShort(); jaroslav@810: for (int i = 0; i < cnt; i++) { jaroslav@810: readAnno(dis, cd, true); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException { jaroslav@810: int type = dis.readUnsignedShort(); jaroslav@810: String typeName = cd.StringValue(type); jaroslav@810: visitAnnotationStart(typeName, top); jaroslav@810: int cnt = dis.readUnsignedShort(); jaroslav@810: for (int i = 0; i < cnt; i++) { jaroslav@810: String attrName = cd.StringValue(dis.readUnsignedShort()); jaroslav@810: readValue(dis, cd, typeName, attrName); jaroslav@810: } jaroslav@810: visitAnnotationEnd(typeName, top); jaroslav@810: if (cnt == 0) { jaroslav@810: visitAttr(typeName, null, null, null); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private void readValue( jaroslav@810: DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException { jaroslav@810: char type = (char) dis.readByte(); jaroslav@810: visitValueStart(attrName, type); jaroslav@810: if (type == '@') { jaroslav@810: readAnno(dis, cd, false); jaroslav@810: } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N jaroslav@810: int primitive = dis.readUnsignedShort(); jaroslav@810: String val = cd.stringValue(primitive, textual); jaroslav@810: String attrType; jaroslav@810: if (type == 's') { jaroslav@810: attrType = "Ljava_lang_String_2"; jaroslav@810: if (textual) { jaroslav@810: val = '"' + val + '"'; jaroslav@810: } jaroslav@810: } else { jaroslav@810: attrType = "" + type; jaroslav@810: } jaroslav@810: visitAttr(typeName, attrName, attrType, val); jaroslav@810: } else if (type == 'c') { jaroslav@810: int cls = dis.readUnsignedShort(); jaroslav@810: } else if (type == '[') { jaroslav@810: int cnt = dis.readUnsignedShort(); jaroslav@810: for (int i = 0; i < cnt; i++) { jaroslav@810: readValue(dis, cd, typeName, iterateArray ? attrName : null); jaroslav@810: } jaroslav@810: } else if (type == 'e') { jaroslav@810: int enumT = dis.readUnsignedShort(); jaroslav@810: String attrType = cd.stringValue(enumT, textual); jaroslav@810: int enumN = dis.readUnsignedShort(); jaroslav@810: String val = cd.stringValue(enumN, textual); jaroslav@810: visitEnumAttr(typeName, attrName, attrType, val); jaroslav@810: } else { jaroslav@810: throw new IOException("Unknown type " + type); jaroslav@810: } jaroslav@810: visitValueEnd(attrName, type); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads and stores attribute information. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class AttrData { jaroslav@810: jaroslav@810: ClassData cls; jaroslav@810: int name_cpx; jaroslav@810: int datalen; jaroslav@810: byte data[]; jaroslav@810: jaroslav@810: public AttrData(ClassData cls) { jaroslav@810: this.cls = cls; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads unknown attribute. jaroslav@810: */ jaroslav@810: public void read(int name_cpx, DataInputStream in) throws IOException { jaroslav@810: this.name_cpx = name_cpx; jaroslav@810: datalen = in.readInt(); jaroslav@810: data = new byte[datalen]; jaroslav@810: in.readFully(data); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads just the name of known attribute. jaroslav@810: */ jaroslav@810: public void read(int name_cpx) { jaroslav@810: this.name_cpx = name_cpx; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns attribute name. jaroslav@810: */ jaroslav@810: public String getAttrName() { jaroslav@810: return cls.getString(name_cpx); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns attribute data. jaroslav@810: */ jaroslav@810: public byte[] getData() { jaroslav@810: return data; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Stores constant pool entry information with one field. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class CPX { jaroslav@810: jaroslav@810: int cpx; jaroslav@810: jaroslav@810: CPX(int cpx) { jaroslav@810: this.cpx = cpx; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Stores constant pool entry information with two fields. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class CPX2 { jaroslav@810: jaroslav@810: int cpx1, cpx2; jaroslav@810: jaroslav@810: CPX2(int cpx1, int cpx2) { jaroslav@810: this.cpx1 = cpx1; jaroslav@810: this.cpx2 = cpx2; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Central data repository of the Java Disassembler. Stores all the jaroslav@810: * information in java class file. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: static final class ClassData { jaroslav@810: jaroslav@810: private int magic; jaroslav@810: private int minor_version; jaroslav@810: private int major_version; jaroslav@810: private int cpool_count; jaroslav@810: private Object cpool[]; jaroslav@810: private int access; jaroslav@810: private int this_class = 0; jaroslav@810: private int super_class; jaroslav@810: private int interfaces_count; jaroslav@810: private int[] interfaces = new int[0]; jaroslav@810: private FieldData[] fields; jaroslav@810: private MethodData[] methods; jaroslav@810: private InnerClassData[] innerClasses; jaroslav@810: private int attributes_count; jaroslav@810: private AttrData[] attrs; jaroslav@810: private int source_cpx = 0; jaroslav@810: private byte tags[]; jaroslav@810: private Hashtable indexHashAscii = new Hashtable(); jaroslav@810: private String pkgPrefix = ""; jaroslav@810: private int pkgPrefixLen = 0; jaroslav@810: jaroslav@810: /** jaroslav@810: * Read classfile to disassemble. jaroslav@810: */ jaroslav@810: public ClassData(InputStream infile) throws IOException { jaroslav@810: this.read(new DataInputStream(infile)); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads and stores class file information. jaroslav@810: */ jaroslav@810: public void read(DataInputStream in) throws IOException { jaroslav@810: // Read the header jaroslav@810: magic = in.readInt(); jaroslav@810: if (magic != JAVA_MAGIC) { jaroslav@810: throw new ClassFormatError("wrong magic: " jaroslav@810: + toHex(magic) + ", expected " jaroslav@810: + toHex(JAVA_MAGIC)); jaroslav@810: } jaroslav@810: minor_version = in.readShort(); jaroslav@810: major_version = in.readShort(); jaroslav@810: if (major_version != JAVA_VERSION) { jaroslav@810: } jaroslav@810: jaroslav@810: // Read the constant pool jaroslav@810: readCP(in); jaroslav@810: access = in.readUnsignedShort(); jaroslav@810: this_class = in.readUnsignedShort(); jaroslav@810: super_class = in.readUnsignedShort(); jaroslav@810: jaroslav@810: //Read interfaces. jaroslav@810: interfaces_count = in.readUnsignedShort(); jaroslav@810: if (interfaces_count > 0) { jaroslav@810: interfaces = new int[interfaces_count]; jaroslav@810: } jaroslav@810: for (int i = 0; i < interfaces_count; i++) { jaroslav@810: interfaces[i] = in.readShort(); jaroslav@810: } jaroslav@810: jaroslav@810: // Read the fields jaroslav@810: readFields(in); jaroslav@810: jaroslav@810: // Read the methods jaroslav@810: readMethods(in); jaroslav@810: jaroslav@810: // Read the attributes jaroslav@810: attributes_count = in.readUnsignedShort(); jaroslav@810: attrs = new AttrData[attributes_count]; jaroslav@810: for (int k = 0; k < attributes_count; k++) { jaroslav@810: int name_cpx = in.readUnsignedShort(); jaroslav@810: if (getTag(name_cpx) == CONSTANT_UTF8 jaroslav@810: && getString(name_cpx).equals("SourceFile")) { jaroslav@810: if (in.readInt() != 2) { jaroslav@810: throw new ClassFormatError("invalid attr length"); jaroslav@810: } jaroslav@810: source_cpx = in.readUnsignedShort(); jaroslav@810: AttrData attr = new AttrData(this); jaroslav@810: attr.read(name_cpx); jaroslav@810: attrs[k] = attr; jaroslav@810: jaroslav@810: } else if (getTag(name_cpx) == CONSTANT_UTF8 jaroslav@810: && getString(name_cpx).equals("InnerClasses")) { jaroslav@810: int length = in.readInt(); jaroslav@810: int num = in.readUnsignedShort(); jaroslav@810: if (2 + num * 8 != length) { jaroslav@810: throw new ClassFormatError("invalid attr length"); jaroslav@810: } jaroslav@810: innerClasses = new InnerClassData[num]; jaroslav@810: for (int j = 0; j < num; j++) { jaroslav@810: InnerClassData innerClass = new InnerClassData(this); jaroslav@810: innerClass.read(in); jaroslav@810: innerClasses[j] = innerClass; jaroslav@810: } jaroslav@810: AttrData attr = new AttrData(this); jaroslav@810: attr.read(name_cpx); jaroslav@810: attrs[k] = attr; jaroslav@810: } else { jaroslav@810: AttrData attr = new AttrData(this); jaroslav@810: attr.read(name_cpx, in); jaroslav@810: attrs[k] = attr; jaroslav@810: } jaroslav@810: } jaroslav@810: in.close(); jaroslav@810: } // end ClassData.read() jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads and stores constant pool info. jaroslav@810: */ jaroslav@810: void readCP(DataInputStream in) throws IOException { jaroslav@810: cpool_count = in.readUnsignedShort(); jaroslav@810: tags = new byte[cpool_count]; jaroslav@810: cpool = new Object[cpool_count]; jaroslav@810: for (int i = 1; i < cpool_count; i++) { jaroslav@810: byte tag = in.readByte(); jaroslav@810: jaroslav@810: switch (tags[i] = tag) { jaroslav@810: case CONSTANT_UTF8: jaroslav@810: String str = in.readUTF(); jaroslav@810: indexHashAscii.put(cpool[i] = str, new Integer(i)); jaroslav@810: break; jaroslav@810: case CONSTANT_INTEGER: jaroslav@810: cpool[i] = new Integer(in.readInt()); jaroslav@810: break; jaroslav@810: case CONSTANT_FLOAT: jaroslav@810: cpool[i] = new Float(in.readFloat()); jaroslav@810: break; jaroslav@810: case CONSTANT_LONG: jaroslav@810: cpool[i++] = new Long(in.readLong()); jaroslav@810: break; jaroslav@810: case CONSTANT_DOUBLE: jaroslav@810: cpool[i++] = new Double(in.readDouble()); jaroslav@810: break; jaroslav@810: case CONSTANT_CLASS: jaroslav@810: case CONSTANT_STRING: jaroslav@810: cpool[i] = new CPX(in.readUnsignedShort()); jaroslav@810: break; jaroslav@810: jaroslav@810: case CONSTANT_FIELD: jaroslav@810: case CONSTANT_METHOD: jaroslav@810: case CONSTANT_INTERFACEMETHOD: jaroslav@810: case CONSTANT_NAMEANDTYPE: jaroslav@810: cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); jaroslav@810: break; jaroslav@1639: case CONSTANT_METHODHANDLE: jaroslav@1639: in.readByte(); jaroslav@1639: in.readUnsignedShort(); jaroslav@1639: break; jaroslav@1639: case CONSTANT_METHODTYPE: jaroslav@1639: in.readUnsignedShort(); jaroslav@1639: break; jaroslav@1639: case CONSTANT_INVOKEDYNAMIC: jaroslav@1639: in.readUnsignedShort(); jaroslav@1639: in.readUnsignedShort(); jaroslav@1639: break; jaroslav@810: case 0: jaroslav@810: default: jaroslav@810: throw new ClassFormatError("invalid constant type: " + (int) tags[i]); jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads and strores field info. jaroslav@810: */ jaroslav@810: protected void readFields(DataInputStream in) throws IOException { jaroslav@810: int fields_count = in.readUnsignedShort(); jaroslav@810: fields = new FieldData[fields_count]; jaroslav@810: for (int k = 0; k < fields_count; k++) { jaroslav@810: FieldData field = new FieldData(this); jaroslav@810: field.read(in); jaroslav@810: fields[k] = field; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Reads and strores Method info. jaroslav@810: */ jaroslav@810: protected void readMethods(DataInputStream in) throws IOException { jaroslav@810: int methods_count = in.readUnsignedShort(); jaroslav@810: methods = new MethodData[methods_count]; jaroslav@810: for (int k = 0; k < methods_count; k++) { jaroslav@810: MethodData method = new MethodData(this); jaroslav@810: method.read(in); jaroslav@810: methods[k] = method; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * get a string jaroslav@810: */ jaroslav@810: public String getString(int n) { jaroslav@810: if (n == 0) { jaroslav@810: return null; jaroslav@810: } else { jaroslav@810: return (String) cpool[n]; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * get the type of constant given an index jaroslav@810: */ jaroslav@810: public byte getTag(int n) { jaroslav@810: try { jaroslav@810: return tags[n]; jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return (byte) 100; jaroslav@810: } jaroslav@810: } jaroslav@810: static final String hexString = "0123456789ABCDEF"; jaroslav@810: public static char hexTable[] = hexString.toCharArray(); jaroslav@810: jaroslav@810: static String toHex(long val, int width) { jaroslav@810: StringBuffer s = new StringBuffer(); jaroslav@810: for (int i = width - 1; i >= 0; i--) { jaroslav@810: s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); jaroslav@810: } jaroslav@810: return "0x" + s.toString(); jaroslav@810: } jaroslav@810: jaroslav@810: static String toHex(long val) { jaroslav@810: int width; jaroslav@810: for (width = 16; width > 0; width--) { jaroslav@810: if ((val >> (width - 1) * 4) != 0) { jaroslav@810: break; jaroslav@810: } jaroslav@810: } jaroslav@810: return toHex(val, width); jaroslav@810: } jaroslav@810: jaroslav@810: static String toHex(int val) { jaroslav@810: int width; jaroslav@810: for (width = 8; width > 0; width--) { jaroslav@810: if ((val >> (width - 1) * 4) != 0) { jaroslav@810: break; jaroslav@810: } jaroslav@810: } jaroslav@810: return toHex(val, width); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns the name of this class. jaroslav@810: */ jaroslav@810: public String getClassName() { jaroslav@810: String res = null; jaroslav@810: if (this_class == 0) { jaroslav@810: return res; jaroslav@810: } jaroslav@810: int tcpx; jaroslav@810: try { jaroslav@810: if (tags[this_class] != CONSTANT_CLASS) { jaroslav@810: return res; //" "; jaroslav@810: } jaroslav@810: tcpx = ((CPX) cpool[this_class]).cpx; jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "#"+cpx+"// invalid constant pool index"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: jaroslav@810: try { jaroslav@810: return (String) (cpool[tcpx]); jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool index"; jaroslav@810: } catch (ClassCastException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool reference"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns the name of class at perticular index. jaroslav@810: */ jaroslav@810: public String getClassName(int cpx) { jaroslav@810: String res = "#" + cpx; jaroslav@810: if (cpx == 0) { jaroslav@810: return res; jaroslav@810: } jaroslav@810: int scpx; jaroslav@810: try { jaroslav@810: if (tags[cpx] != CONSTANT_CLASS) { jaroslav@810: return res; //" "; jaroslav@810: } jaroslav@810: scpx = ((CPX) cpool[cpx]).cpx; jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "#"+cpx+"// invalid constant pool index"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: res = "#" + scpx; jaroslav@810: try { jaroslav@810: return (String) (cpool[scpx]); jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool index"; jaroslav@810: } catch (ClassCastException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool reference"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: public int getAccessFlags() { jaroslav@810: return access; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if it is a class jaroslav@810: */ jaroslav@810: public boolean isClass() { jaroslav@810: if ((access & ACC_INTERFACE) == 0) { jaroslav@810: return true; jaroslav@810: } jaroslav@810: return false; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if it is a interface. jaroslav@810: */ jaroslav@810: public boolean isInterface() { jaroslav@810: if ((access & ACC_INTERFACE) != 0) { jaroslav@810: return true; jaroslav@810: } jaroslav@810: return false; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if this member is public, false otherwise. jaroslav@810: */ jaroslav@810: public boolean isPublic() { jaroslav@810: return (access & ACC_PUBLIC) != 0; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns the access of this class or interface. jaroslav@810: */ jaroslav@810: public String[] getAccess() { jaroslav@810: Vector v = new Vector(); jaroslav@810: if ((access & ACC_PUBLIC) != 0) { jaroslav@810: v.addElement("public"); jaroslav@810: } jaroslav@810: if ((access & ACC_FINAL) != 0) { jaroslav@810: v.addElement("final"); jaroslav@810: } jaroslav@810: if ((access & ACC_ABSTRACT) != 0) { jaroslav@810: v.addElement("abstract"); jaroslav@810: } jaroslav@810: String[] accflags = new String[v.size()]; jaroslav@810: v.copyInto(accflags); jaroslav@810: return accflags; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of innerclasses. jaroslav@810: */ jaroslav@810: public InnerClassData[] getInnerClasses() { jaroslav@810: return innerClasses; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of attributes. jaroslav@810: */ jaroslav@810: final AttrData[] getAttributes() { jaroslav@810: return attrs; jaroslav@810: } jaroslav@810: jaroslav@810: public byte[] findAnnotationData(boolean classRetention) { jaroslav@810: String n = classRetention jaroslav@810: ? "RuntimeInvisibleAnnotations" : // NOI18N jaroslav@810: "RuntimeVisibleAnnotations"; // NOI18N jaroslav@810: return findAttr(n, attrs); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if superbit is set. jaroslav@810: */ jaroslav@810: public boolean isSuperSet() { jaroslav@810: if ((access & ACC_SUPER) != 0) { jaroslav@810: return true; jaroslav@810: } jaroslav@810: return false; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns super class name. jaroslav@810: */ jaroslav@810: public String getSuperClassName() { jaroslav@810: String res = null; jaroslav@810: if (super_class == 0) { jaroslav@810: return res; jaroslav@810: } jaroslav@810: int scpx; jaroslav@810: try { jaroslav@810: if (tags[super_class] != CONSTANT_CLASS) { jaroslav@810: return res; //" "; jaroslav@810: } jaroslav@810: scpx = ((CPX) cpool[super_class]).cpx; jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "#"+cpx+"// invalid constant pool index"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: jaroslav@810: try { jaroslav@810: return (String) (cpool[scpx]); jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool index"; jaroslav@810: } catch (ClassCastException e) { jaroslav@810: return res; // "class #"+scpx+"// invalid constant pool reference"; jaroslav@810: } catch (Throwable e) { jaroslav@810: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of super interfaces. jaroslav@810: */ jaroslav@810: public String[] getSuperInterfaces() { jaroslav@810: String interfacenames[] = new String[interfaces.length]; jaroslav@810: int interfacecpx = -1; jaroslav@810: for (int i = 0; i < interfaces.length; i++) { jaroslav@810: interfacecpx = ((CPX) cpool[interfaces[i]]).cpx; jaroslav@810: interfacenames[i] = (String) (cpool[interfacecpx]); jaroslav@810: } jaroslav@810: return interfacenames; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns string at prticular constant pool index. jaroslav@810: */ jaroslav@810: public String getStringValue(int cpoolx) { jaroslav@810: try { jaroslav@810: return ((String) cpool[cpoolx]); jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return "//invalid constant pool index:" + cpoolx; jaroslav@810: } catch (ClassCastException e) { jaroslav@810: return "//invalid constant pool ref:" + cpoolx; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of field info. jaroslav@810: */ jaroslav@810: public FieldData[] getFields() { jaroslav@810: return fields; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of method info. jaroslav@810: */ jaroslav@810: public MethodData[] getMethods() { jaroslav@810: return methods; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns constant pool entry at that index. jaroslav@810: */ jaroslav@810: public CPX2 getCpoolEntry(int cpx) { jaroslav@810: return ((CPX2) (cpool[cpx])); jaroslav@810: } jaroslav@810: jaroslav@810: public Object getCpoolEntryobj(int cpx) { jaroslav@810: return (cpool[cpx]); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns index of this class. jaroslav@810: */ jaroslav@810: public int getthis_cpx() { jaroslav@810: return this_class; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns string at that index. jaroslav@810: */ jaroslav@810: public String StringValue(int cpx) { jaroslav@810: return stringValue(cpx, false); jaroslav@810: } jaroslav@810: jaroslav@810: public String stringValue(int cpx, boolean textual) { jaroslav@810: return stringValue(cpx, textual, null); jaroslav@810: } jaroslav@810: jaroslav@810: public String stringValue(int cpx, String[] classRefs) { jaroslav@810: return stringValue(cpx, true, classRefs); jaroslav@810: } jaroslav@810: jaroslav@810: private String stringValue(int cpx, boolean textual, String[] refs) { jaroslav@810: if (cpx == 0) { jaroslav@810: return "#0"; jaroslav@810: } jaroslav@810: int tag; jaroslav@810: Object x; jaroslav@810: String suffix = ""; jaroslav@810: try { jaroslav@810: tag = tags[cpx]; jaroslav@810: x = cpool[cpx]; jaroslav@810: } catch (IndexOutOfBoundsException e) { jaroslav@810: return ""; jaroslav@810: } jaroslav@810: jaroslav@810: if (x == null) { jaroslav@810: return ""; jaroslav@810: } jaroslav@810: switch (tag) { jaroslav@810: case CONSTANT_UTF8: { jaroslav@810: if (!textual) { jaroslav@810: return (String) x; jaroslav@810: } jaroslav@810: StringBuilder sb = new StringBuilder(); jaroslav@810: String s = (String) x; jaroslav@810: for (int k = 0; k < s.length(); k++) { jaroslav@810: char c = s.charAt(k); jaroslav@810: switch (c) { jaroslav@810: case '\\': jaroslav@810: sb.append('\\').append('\\'); jaroslav@810: break; jaroslav@810: case '\t': jaroslav@810: sb.append('\\').append('t'); jaroslav@810: break; jaroslav@810: case '\n': jaroslav@810: sb.append('\\').append('n'); jaroslav@810: break; jaroslav@810: case '\r': jaroslav@810: sb.append('\\').append('r'); jaroslav@810: break; jaroslav@810: case '\"': jaroslav@810: sb.append('\\').append('\"'); jaroslav@810: break; jaroslav@1354: case '\u2028': jaroslav@1354: sb.append("\\u2028"); jaroslav@1354: break; jaroslav@1354: case '\u2029': jaroslav@1354: sb.append("\\u2029"); jaroslav@1354: break; jaroslav@810: default: jaroslav@810: sb.append(c); jaroslav@810: } jaroslav@810: } jaroslav@810: return sb.toString(); jaroslav@810: } jaroslav@810: case CONSTANT_DOUBLE: { jaroslav@810: Double d = (Double) x; jaroslav@810: String sd = d.toString(); jaroslav@810: if (textual) { jaroslav@810: return sd; jaroslav@810: } jaroslav@810: return sd + "d"; jaroslav@810: } jaroslav@810: case CONSTANT_FLOAT: { jaroslav@810: Float f = (Float) x; jaroslav@810: String sf = (f).toString(); jaroslav@810: if (textual) { jaroslav@810: return sf; jaroslav@810: } jaroslav@810: return sf + "f"; jaroslav@810: } jaroslav@810: case CONSTANT_LONG: { jaroslav@810: Long ln = (Long) x; jaroslav@810: if (textual) { jaroslav@810: return ln.toString(); jaroslav@810: } jaroslav@810: return ln.toString() + 'l'; jaroslav@810: } jaroslav@810: case CONSTANT_INTEGER: { jaroslav@810: Integer in = (Integer) x; jaroslav@810: return in.toString(); jaroslav@810: } jaroslav@810: case CONSTANT_CLASS: jaroslav@810: String jn = getClassName(cpx); jaroslav@810: if (textual) { jaroslav@810: if (refs != null) { jaroslav@810: refs[0] = jn; jaroslav@810: } jaroslav@810: return jn; jaroslav@810: } jaroslav@810: return javaName(jn); jaroslav@810: case CONSTANT_STRING: jaroslav@810: String sv = stringValue(((CPX) x).cpx, textual); jaroslav@810: if (textual) { jaroslav@810: return '"' + sv + '"'; jaroslav@810: } else { jaroslav@810: return sv; jaroslav@810: } jaroslav@810: case CONSTANT_FIELD: jaroslav@810: case CONSTANT_METHOD: jaroslav@810: case CONSTANT_INTERFACEMETHOD: jaroslav@810: //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2); jaroslav@810: return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2); jaroslav@810: jaroslav@810: case CONSTANT_NAMEANDTYPE: jaroslav@810: return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2); jaroslav@810: default: jaroslav@810: return "UnknownTag"; //TBD jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns resolved java type name. jaroslav@810: */ jaroslav@810: public String javaName(String name) { jaroslav@810: if (name == null) { jaroslav@810: return "null"; jaroslav@810: } jaroslav@810: int len = name.length(); jaroslav@810: if (len == 0) { jaroslav@810: return "\"\""; jaroslav@810: } jaroslav@810: int cc = '/'; jaroslav@810: fullname: jaroslav@810: { // xxx/yyy/zzz jaroslav@810: int cp; jaroslav@810: for (int k = 0; k < len; k += Character.charCount(cp)) { jaroslav@810: cp = name.codePointAt(k); jaroslav@810: if (cc == '/') { jaroslav@810: if (!isJavaIdentifierStart(cp)) { jaroslav@810: break fullname; jaroslav@810: } jaroslav@810: } else if (cp != '/') { jaroslav@810: if (!isJavaIdentifierPart(cp)) { jaroslav@810: break fullname; jaroslav@810: } jaroslav@810: } jaroslav@810: cc = cp; jaroslav@810: } jaroslav@810: return name; jaroslav@810: } jaroslav@810: return "\"" + name + "\""; jaroslav@810: } jaroslav@810: jaroslav@810: public String getName(int cpx) { jaroslav@810: String res; jaroslav@810: try { jaroslav@810: return javaName((String) cpool[cpx]); //.replace('/','.'); jaroslav@810: } catch (ArrayIndexOutOfBoundsException e) { jaroslav@810: return ""; jaroslav@810: } catch (ClassCastException e) { jaroslav@810: return ""; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns unqualified class name. jaroslav@810: */ jaroslav@810: public String getShortClassName(int cpx) { jaroslav@810: String classname = javaName(getClassName(cpx)); jaroslav@810: pkgPrefixLen = classname.lastIndexOf("/") + 1; jaroslav@810: if (pkgPrefixLen != 0) { jaroslav@810: pkgPrefix = classname.substring(0, pkgPrefixLen); jaroslav@810: if (classname.startsWith(pkgPrefix)) { jaroslav@810: return classname.substring(pkgPrefixLen); jaroslav@810: } jaroslav@810: } jaroslav@810: return classname; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns source file name. jaroslav@810: */ jaroslav@810: public String getSourceName() { jaroslav@810: return getName(source_cpx); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns package name. jaroslav@810: */ jaroslav@810: public String getPkgName() { jaroslav@810: String classname = getClassName(this_class); jaroslav@810: pkgPrefixLen = classname.lastIndexOf("/") + 1; jaroslav@810: if (pkgPrefixLen != 0) { jaroslav@810: pkgPrefix = classname.substring(0, pkgPrefixLen); lubomir@967: return /* ("package " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */; jaroslav@810: } else { jaroslav@810: return null; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns total constant pool entry count. jaroslav@810: */ jaroslav@810: public int getCpoolCount() { jaroslav@810: return cpool_count; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns minor version of class file. jaroslav@810: */ jaroslav@810: public int getMinor_version() { jaroslav@810: return minor_version; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns major version of class file. jaroslav@810: */ jaroslav@810: public int getMajor_version() { jaroslav@810: return major_version; jaroslav@810: } jaroslav@810: jaroslav@810: private boolean isJavaIdentifierStart(int cp) { jaroslav@810: return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); jaroslav@810: } jaroslav@810: jaroslav@810: private boolean isJavaIdentifierPart(int cp) { jaroslav@810: return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); jaroslav@810: } jaroslav@810: jaroslav@810: public String[] getNameAndType(int indx) { jaroslav@810: return getNameAndType(indx, 0, new String[2]); jaroslav@810: } jaroslav@810: jaroslav@810: private String[] getNameAndType(int indx, int at, String[] arr) { jaroslav@810: CPX2 c2 = getCpoolEntry(indx); jaroslav@810: arr[at] = StringValue(c2.cpx1); jaroslav@810: arr[at + 1] = StringValue(c2.cpx2); jaroslav@810: return arr; jaroslav@810: } jaroslav@810: jaroslav@810: public String[] getFieldInfoName(int indx) { jaroslav@810: CPX2 c2 = getCpoolEntry(indx); jaroslav@810: String[] arr = new String[3]; jaroslav@810: arr[0] = getClassName(c2.cpx1); jaroslav@810: return getNameAndType(c2.cpx2, 1, arr); jaroslav@810: } jaroslav@810: lubomir@1085: public MethodData findMethod(String name, String signature) { lubomir@1085: for (MethodData md: methods) { lubomir@1085: if (md.getName().equals(name) lubomir@1085: && md.getInternalSig().equals(signature)) { lubomir@1085: return md; lubomir@1085: } lubomir@1085: } lubomir@1085: lubomir@1085: // not found lubomir@1085: return null; lubomir@1085: } lubomir@1085: lubomir@1085: public FieldData findField(String name, String signature) { lubomir@1085: for (FieldData fd: fields) { lubomir@1085: if (fd.getName().equals(name) lubomir@1085: && fd.getInternalSig().equals(signature)) { lubomir@1085: return fd; lubomir@1085: } lubomir@1085: } lubomir@1085: lubomir@1085: // not found lubomir@1085: return null; lubomir@1085: } lubomir@1085: jaroslav@810: static byte[] findAttr(String n, AttrData[] attrs) { jaroslav@810: for (AttrData ad : attrs) { jaroslav@810: if (n.equals(ad.getAttrName())) { jaroslav@810: return ad.getData(); jaroslav@810: } jaroslav@810: } jaroslav@810: return null; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Strores field data informastion. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: static class FieldData { jaroslav@810: jaroslav@810: ClassData cls; jaroslav@810: int access; jaroslav@810: int name_index; jaroslav@810: int descriptor_index; jaroslav@810: int attributes_count; jaroslav@1474: int value_cpx = -1; jaroslav@810: boolean isSynthetic = false; jaroslav@810: boolean isDeprecated = false; jaroslav@810: Vector attrs; jaroslav@810: jaroslav@810: public FieldData(ClassData cls) { jaroslav@810: this.cls = cls; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read and store field info. jaroslav@810: */ jaroslav@810: public void read(DataInputStream in) throws IOException { jaroslav@810: access = in.readUnsignedShort(); jaroslav@810: name_index = in.readUnsignedShort(); jaroslav@810: descriptor_index = in.readUnsignedShort(); jaroslav@810: // Read the attributes jaroslav@810: int attributes_count = in.readUnsignedShort(); jaroslav@810: attrs = new Vector(attributes_count); jaroslav@810: for (int i = 0; i < attributes_count; i++) { jaroslav@810: int attr_name_index = in.readUnsignedShort(); jaroslav@810: if (cls.getTag(attr_name_index) != CONSTANT_UTF8) { jaroslav@810: continue; jaroslav@810: } jaroslav@810: String attr_name = cls.getString(attr_name_index); jaroslav@810: if (attr_name.equals("ConstantValue")) { jaroslav@810: if (in.readInt() != 2) { jaroslav@810: throw new ClassFormatError("invalid ConstantValue attr length"); jaroslav@810: } jaroslav@810: value_cpx = in.readUnsignedShort(); jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: } else if (attr_name.equals("Synthetic")) { jaroslav@810: if (in.readInt() != 0) { jaroslav@810: throw new ClassFormatError("invalid Synthetic attr length"); jaroslav@810: } jaroslav@810: isSynthetic = true; jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: } else if (attr_name.equals("Deprecated")) { jaroslav@810: if (in.readInt() != 0) { jaroslav@810: throw new ClassFormatError("invalid Synthetic attr length"); jaroslav@810: } jaroslav@810: isDeprecated = true; jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: } else { jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index, in); jaroslav@810: attrs.addElement(attr); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: } // end read jaroslav@810: jaroslav@810: public boolean isStatic() { jaroslav@810: return (access & ACC_STATIC) != 0; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns access of a field. jaroslav@810: */ jaroslav@810: public String[] getAccess() { jaroslav@810: Vector v = new Vector(); jaroslav@810: if ((access & ACC_PUBLIC) != 0) { jaroslav@810: v.addElement("public"); jaroslav@810: } jaroslav@810: if ((access & ACC_PRIVATE) != 0) { jaroslav@810: v.addElement("private"); jaroslav@810: } jaroslav@810: if ((access & ACC_PROTECTED) != 0) { jaroslav@810: v.addElement("protected"); jaroslav@810: } jaroslav@810: if ((access & ACC_STATIC) != 0) { jaroslav@810: v.addElement("static"); jaroslav@810: } jaroslav@810: if ((access & ACC_FINAL) != 0) { jaroslav@810: v.addElement("final"); jaroslav@810: } jaroslav@810: if ((access & ACC_VOLATILE) != 0) { jaroslav@810: v.addElement("volatile"); jaroslav@810: } jaroslav@810: if ((access & ACC_TRANSIENT) != 0) { jaroslav@810: v.addElement("transient"); jaroslav@810: } jaroslav@810: String[] accflags = new String[v.size()]; jaroslav@810: v.copyInto(accflags); jaroslav@810: return accflags; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns name of a field. jaroslav@810: */ jaroslav@810: public String getName() { jaroslav@810: return cls.getStringValue(name_index); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns internal signature of a field jaroslav@810: */ jaroslav@810: public String getInternalSig() { jaroslav@810: return cls.getStringValue(descriptor_index); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if field is synthetic. jaroslav@810: */ jaroslav@810: public boolean isSynthetic() { jaroslav@810: return isSynthetic; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns true if field is deprecated. jaroslav@810: */ jaroslav@810: public boolean isDeprecated() { jaroslav@810: return isDeprecated; jaroslav@810: } jaroslav@810: jaroslav@1474: public boolean hasConstantValue() { jaroslav@1474: return value_cpx != -1; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns list of attributes of field. jaroslav@810: */ jaroslav@810: public Vector getAttributes() { jaroslav@810: return attrs; jaroslav@810: } jaroslav@810: jaroslav@810: public byte[] findAnnotationData(boolean classRetention) { jaroslav@810: String n = classRetention jaroslav@810: ? "RuntimeInvisibleAnnotations" : // NOI18N jaroslav@810: "RuntimeVisibleAnnotations"; // NOI18N jaroslav@810: AttrData[] arr = new AttrData[attrs.size()]; jaroslav@810: attrs.copyInto(arr); jaroslav@810: return ClassData.findAttr(n, arr); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * A JavaScript optimized replacement for Hashtable. jaroslav@810: * jaroslav@810: * @author Jaroslav Tulach jaroslav@810: */ jaroslav@810: private static final class Hashtable { jaroslav@810: jaroslav@810: private Object[] keys; jaroslav@810: private Object[] values; jaroslav@810: jaroslav@810: Hashtable(int i) { jaroslav@810: this(); jaroslav@810: } jaroslav@810: jaroslav@810: Hashtable(int i, double d) { jaroslav@810: this(); jaroslav@810: } jaroslav@810: jaroslav@810: Hashtable() { jaroslav@810: } jaroslav@810: jaroslav@810: synchronized void put(Object key, Object val) { jaroslav@810: int[] where = {-1, -1}; jaroslav@810: Object found = get(key, where); jaroslav@810: if (where[0] != -1) { jaroslav@810: // key exists jaroslav@810: values[where[0]] = val; jaroslav@810: } else { jaroslav@810: if (where[1] != -1) { jaroslav@810: // null found jaroslav@810: keys[where[1]] = key; jaroslav@810: values[where[1]] = val; jaroslav@810: } else { jaroslav@810: if (keys == null) { jaroslav@810: keys = new Object[11]; jaroslav@810: values = new Object[11]; jaroslav@810: keys[0] = key; jaroslav@810: values[0] = val; jaroslav@810: } else { jaroslav@810: Object[] newKeys = new Object[keys.length * 2]; jaroslav@810: Object[] newValues = new Object[values.length * 2]; jaroslav@810: for (int i = 0; i < keys.length; i++) { jaroslav@810: newKeys[i] = keys[i]; jaroslav@810: newValues[i] = values[i]; jaroslav@810: } jaroslav@810: newKeys[keys.length] = key; jaroslav@810: newValues[keys.length] = val; jaroslav@810: keys = newKeys; jaroslav@810: values = newValues; jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: Object get(Object key) { jaroslav@810: return get(key, null); jaroslav@810: } jaroslav@810: jaroslav@810: private synchronized Object get(Object key, int[] foundAndNull) { jaroslav@810: if (keys == null) { jaroslav@810: return null; jaroslav@810: } jaroslav@810: for (int i = 0; i < keys.length; i++) { jaroslav@810: if (keys[i] == null) { jaroslav@810: if (foundAndNull != null) { jaroslav@810: foundAndNull[1] = i; jaroslav@810: } jaroslav@810: } else if (keys[i].equals(key)) { jaroslav@810: if (foundAndNull != null) { jaroslav@810: foundAndNull[0] = i; jaroslav@810: } jaroslav@810: return values[i]; jaroslav@810: } jaroslav@810: } jaroslav@810: return null; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Strores InnerClass data informastion. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class InnerClassData { jaroslav@810: jaroslav@810: ClassData cls; jaroslav@810: int inner_class_info_index, outer_class_info_index, inner_name_index, access; jaroslav@810: jaroslav@810: public InnerClassData(ClassData cls) { jaroslav@810: this.cls = cls; jaroslav@810: jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read Innerclass attribute data. jaroslav@810: */ jaroslav@810: public void read(DataInputStream in) throws IOException { jaroslav@810: inner_class_info_index = in.readUnsignedShort(); jaroslav@810: outer_class_info_index = in.readUnsignedShort(); jaroslav@810: inner_name_index = in.readUnsignedShort(); jaroslav@810: access = in.readUnsignedShort(); jaroslav@810: } // end read jaroslav@810: jaroslav@810: /** jaroslav@810: * Returns the access of this class or interface. jaroslav@810: */ jaroslav@810: public String[] getAccess() { jaroslav@810: Vector v = new Vector(); jaroslav@810: if ((access & ACC_PUBLIC) != 0) { jaroslav@810: v.addElement("public"); jaroslav@810: } jaroslav@810: if ((access & ACC_FINAL) != 0) { jaroslav@810: v.addElement("final"); jaroslav@810: } jaroslav@810: if ((access & ACC_ABSTRACT) != 0) { jaroslav@810: v.addElement("abstract"); jaroslav@810: } jaroslav@810: String[] accflags = new String[v.size()]; jaroslav@810: v.copyInto(accflags); jaroslav@810: return accflags; jaroslav@810: } jaroslav@810: } // end InnerClassData jaroslav@810: jaroslav@810: /** jaroslav@810: * Strores LineNumberTable data information. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class LineNumData { jaroslav@810: jaroslav@810: short start_pc, line_number; jaroslav@810: jaroslav@810: public LineNumData() { jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read LineNumberTable attribute. jaroslav@810: */ jaroslav@810: public LineNumData(DataInputStream in) throws IOException { jaroslav@810: start_pc = in.readShort(); jaroslav@810: line_number = in.readShort(); jaroslav@810: jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Strores LocalVariableTable data information. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: private static class LocVarData { jaroslav@810: jaroslav@810: short start_pc, length, name_cpx, sig_cpx, slot; jaroslav@810: jaroslav@810: public LocVarData() { jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read LocalVariableTable attribute. jaroslav@810: */ jaroslav@810: public LocVarData(DataInputStream in) throws IOException { jaroslav@810: start_pc = in.readShort(); jaroslav@810: length = in.readShort(); jaroslav@810: name_cpx = in.readShort(); jaroslav@810: sig_cpx = in.readShort(); jaroslav@810: slot = in.readShort(); jaroslav@810: jaroslav@810: } jaroslav@810: } jaroslav@810: /** jaroslav@810: * Strores method data informastion. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: static class MethodData { jaroslav@810: jaroslav@810: ClassData cls; jaroslav@810: int access; jaroslav@810: int name_index; jaroslav@810: int descriptor_index; jaroslav@810: int attributes_count; jaroslav@810: byte[] code; jaroslav@810: Vector exception_table = new Vector(0); jaroslav@810: Vector lin_num_tb = new Vector(0); jaroslav@810: Vector loc_var_tb = new Vector(0); jaroslav@810: StackMapTableData[] stackMapTable; jaroslav@810: StackMapData[] stackMap; jaroslav@810: int[] exc_index_table = null; jaroslav@810: Vector attrs = new Vector(0); jaroslav@810: Vector code_attrs = new Vector(0); jaroslav@810: int max_stack, max_locals; jaroslav@810: boolean isSynthetic = false; jaroslav@810: boolean isDeprecated = false; jaroslav@810: jaroslav@810: public MethodData(ClassData cls) { jaroslav@810: this.cls = cls; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read method info. jaroslav@810: */ jaroslav@810: public void read(DataInputStream in) throws IOException { jaroslav@810: access = in.readUnsignedShort(); jaroslav@810: name_index = in.readUnsignedShort(); jaroslav@810: descriptor_index = in.readUnsignedShort(); jaroslav@810: int attributes_count = in.readUnsignedShort(); jaroslav@810: for (int i = 0; i < attributes_count; i++) { jaroslav@810: int attr_name_index = in.readUnsignedShort(); jaroslav@810: jaroslav@810: readAttr: jaroslav@810: { jaroslav@810: if (cls.getTag(attr_name_index) == CONSTANT_UTF8) { jaroslav@810: String attr_name = cls.getString(attr_name_index); jaroslav@810: if (attr_name.equals("Code")) { jaroslav@810: readCode(in); jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: break readAttr; jaroslav@810: } else if (attr_name.equals("Exceptions")) { jaroslav@810: readExceptions(in); jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: break readAttr; jaroslav@810: } else if (attr_name.equals("Synthetic")) { jaroslav@810: if (in.readInt() != 0) { jaroslav@810: throw new ClassFormatError("invalid Synthetic attr length"); jaroslav@810: } jaroslav@810: isSynthetic = true; jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: break readAttr; jaroslav@810: } else if (attr_name.equals("Deprecated")) { jaroslav@810: if (in.readInt() != 0) { jaroslav@810: throw new ClassFormatError("invalid Synthetic attr length"); jaroslav@810: } jaroslav@810: isDeprecated = true; jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index); jaroslav@810: attrs.addElement(attr); jaroslav@810: break readAttr; jaroslav@810: } jaroslav@810: } jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: attr.read(attr_name_index, in); jaroslav@810: attrs.addElement(attr); jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read code attribute info. jaroslav@810: */ jaroslav@810: public void readCode(DataInputStream in) throws IOException { jaroslav@810: jaroslav@810: int attr_length = in.readInt(); jaroslav@810: max_stack = in.readUnsignedShort(); jaroslav@810: max_locals = in.readUnsignedShort(); jaroslav@810: int codelen = in.readInt(); jaroslav@810: jaroslav@810: code = new byte[codelen]; jaroslav@810: int totalread = 0; jaroslav@810: while (totalread < codelen) { jaroslav@810: totalread += in.read(code, totalread, codelen - totalread); jaroslav@810: } jaroslav@810: // in.read(code, 0, codelen); jaroslav@810: int clen = 0; jaroslav@810: readExceptionTable(in); jaroslav@810: int code_attributes_count = in.readUnsignedShort(); jaroslav@810: jaroslav@810: for (int k = 0; k < code_attributes_count; k++) { jaroslav@810: int table_name_index = in.readUnsignedShort(); jaroslav@810: int table_name_tag = cls.getTag(table_name_index); jaroslav@810: AttrData attr = new AttrData(cls); jaroslav@810: if (table_name_tag == CONSTANT_UTF8) { jaroslav@810: String table_name_tstr = cls.getString(table_name_index); jaroslav@810: if (table_name_tstr.equals("LineNumberTable")) { jaroslav@810: readLineNumTable(in); jaroslav@810: attr.read(table_name_index); jaroslav@810: } else if (table_name_tstr.equals("LocalVariableTable")) { jaroslav@810: readLocVarTable(in); jaroslav@810: attr.read(table_name_index); jaroslav@810: } else if (table_name_tstr.equals("StackMapTable")) { jaroslav@810: readStackMapTable(in); jaroslav@810: attr.read(table_name_index); jaroslav@810: } else if (table_name_tstr.equals("StackMap")) { jaroslav@810: readStackMap(in); jaroslav@810: attr.read(table_name_index); jaroslav@810: } else { jaroslav@810: attr.read(table_name_index, in); jaroslav@810: } jaroslav@810: code_attrs.addElement(attr); jaroslav@810: continue; jaroslav@810: } jaroslav@810: jaroslav@810: attr.read(table_name_index, in); jaroslav@810: code_attrs.addElement(attr); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read exception table info. jaroslav@810: */ jaroslav@810: void readExceptionTable(DataInputStream in) throws IOException { jaroslav@810: int exception_table_len = in.readUnsignedShort(); jaroslav@810: exception_table = new Vector(exception_table_len); jaroslav@810: for (int l = 0; l < exception_table_len; l++) { jaroslav@810: exception_table.addElement(new TrapData(in, l)); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read LineNumberTable attribute info. jaroslav@810: */ jaroslav@810: void readLineNumTable(DataInputStream in) throws IOException { jaroslav@810: int attr_len = in.readInt(); // attr_length jaroslav@810: int lin_num_tb_len = in.readUnsignedShort(); jaroslav@810: lin_num_tb = new Vector(lin_num_tb_len); jaroslav@810: for (int l = 0; l < lin_num_tb_len; l++) { jaroslav@810: lin_num_tb.addElement(new LineNumData(in)); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read LocalVariableTable attribute info. jaroslav@810: */ jaroslav@810: void readLocVarTable(DataInputStream in) throws IOException { jaroslav@810: int attr_len = in.readInt(); // attr_length jaroslav@810: int loc_var_tb_len = in.readUnsignedShort(); jaroslav@810: loc_var_tb = new Vector(loc_var_tb_len); jaroslav@810: for (int l = 0; l < loc_var_tb_len; l++) { jaroslav@810: loc_var_tb.addElement(new LocVarData(in)); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read Exception attribute info. jaroslav@810: */ jaroslav@810: public void readExceptions(DataInputStream in) throws IOException { jaroslav@810: int attr_len = in.readInt(); // attr_length in prog jaroslav@810: int num_exceptions = in.readUnsignedShort(); jaroslav@810: exc_index_table = new int[num_exceptions]; jaroslav@810: for (int l = 0; l < num_exceptions; l++) { jaroslav@810: int exc = in.readShort(); jaroslav@810: exc_index_table[l] = exc; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read StackMapTable attribute info. jaroslav@810: */ jaroslav@810: void readStackMapTable(DataInputStream in) throws IOException { jaroslav@810: int attr_len = in.readInt(); //attr_length jaroslav@810: int stack_map_tb_len = in.readUnsignedShort(); jaroslav@810: stackMapTable = new StackMapTableData[stack_map_tb_len]; jaroslav@810: for (int i = 0; i < stack_map_tb_len; i++) { jaroslav@810: stackMapTable[i] = StackMapTableData.getInstance(in, this); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Read StackMap attribute info. jaroslav@810: */ jaroslav@810: void readStackMap(DataInputStream in) throws IOException { jaroslav@810: int attr_len = in.readInt(); //attr_length jaroslav@810: int stack_map_len = in.readUnsignedShort(); jaroslav@810: stackMap = new StackMapData[stack_map_len]; jaroslav@810: for (int i = 0; i < stack_map_len; i++) { jaroslav@810: stackMap[i] = new StackMapData(in, this); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return access of the method. jaroslav@810: */ jaroslav@810: public int getAccess() { jaroslav@810: return access; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return name of the method. jaroslav@810: */ jaroslav@810: public String getName() { jaroslav@810: return cls.getStringValue(name_index); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return internal siganature of the method. jaroslav@810: */ jaroslav@810: public String getInternalSig() { jaroslav@810: return cls.getStringValue(descriptor_index); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return code attribute data of a method. jaroslav@810: */ jaroslav@810: public byte[] getCode() { jaroslav@810: return code; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return LineNumberTable size. jaroslav@810: */ jaroslav@810: public int getnumlines() { jaroslav@810: return lin_num_tb.size(); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return LineNumberTable jaroslav@810: */ jaroslav@810: public Vector getlin_num_tb() { jaroslav@810: return lin_num_tb; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return LocalVariableTable size. jaroslav@810: */ jaroslav@810: public int getloc_var_tbsize() { jaroslav@810: return loc_var_tb.size(); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return LocalVariableTable. jaroslav@810: */ jaroslav@810: public Vector getloc_var_tb() { jaroslav@810: return loc_var_tb; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return StackMap. jaroslav@810: */ jaroslav@810: public StackMapData[] getStackMap() { jaroslav@810: return stackMap; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return StackMapTable. jaroslav@810: */ jaroslav@810: public StackMapTableData[] getStackMapTable() { jaroslav@810: return stackMapTable; jaroslav@810: } jaroslav@810: jaroslav@810: public StackMapIterator createStackMapIterator() { jaroslav@810: return new StackMapIterator(this); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return true if method is static jaroslav@810: */ jaroslav@810: public boolean isStatic() { jaroslav@810: if ((access & ACC_STATIC) != 0) { jaroslav@810: return true; jaroslav@810: } jaroslav@810: return false; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return max depth of operand stack. jaroslav@810: */ jaroslav@810: public int getMaxStack() { jaroslav@810: return max_stack; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return number of local variables. jaroslav@810: */ jaroslav@810: public int getMaxLocals() { jaroslav@810: return max_locals; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return exception index table in Exception attribute. jaroslav@810: */ jaroslav@810: public int[] get_exc_index_table() { jaroslav@810: return exc_index_table; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return exception table in code attributre. jaroslav@810: */ jaroslav@810: public TrapDataIterator getTrapDataIterator() { jaroslav@810: return new TrapDataIterator(exception_table); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return method attributes. jaroslav@810: */ jaroslav@810: public Vector getAttributes() { jaroslav@810: return attrs; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return code attributes. jaroslav@810: */ jaroslav@810: public Vector getCodeAttributes() { jaroslav@810: return code_attrs; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return true if method id synthetic. jaroslav@810: */ jaroslav@810: public boolean isSynthetic() { jaroslav@810: return isSynthetic; jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Return true if method is deprecated. jaroslav@810: */ jaroslav@810: public boolean isDeprecated() { jaroslav@810: return isDeprecated; jaroslav@810: } jaroslav@810: jaroslav@810: public byte[] findAnnotationData(boolean classRetention) { jaroslav@810: String n = classRetention jaroslav@810: ? "RuntimeInvisibleAnnotations" : // NOI18N jaroslav@810: "RuntimeVisibleAnnotations"; // NOI18N jaroslav@810: AttrData[] arr = new AttrData[attrs.size()]; jaroslav@810: attrs.copyInto(arr); jaroslav@810: return ClassData.findAttr(n, arr); jaroslav@810: } jaroslav@810: jaroslav@810: public boolean isConstructor() { jaroslav@810: return "".equals(getName()); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /* represents one entry of StackMap attribute jaroslav@810: */ jaroslav@810: private static class StackMapData { jaroslav@810: jaroslav@810: final int offset; jaroslav@810: final int[] locals; jaroslav@810: final int[] stack; jaroslav@810: jaroslav@810: StackMapData(int offset, int[] locals, int[] stack) { jaroslav@810: this.offset = offset; jaroslav@810: this.locals = locals; jaroslav@810: this.stack = stack; jaroslav@810: } jaroslav@810: jaroslav@810: StackMapData(DataInputStream in, MethodData method) throws IOException { jaroslav@810: offset = in.readUnsignedShort(); jaroslav@810: int local_size = in.readUnsignedShort(); jaroslav@810: locals = readTypeArray(in, local_size, method); jaroslav@810: int stack_size = in.readUnsignedShort(); jaroslav@810: stack = readTypeArray(in, stack_size, method); jaroslav@810: } jaroslav@810: jaroslav@810: static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException { jaroslav@810: int[] types = new int[length]; jaroslav@810: for (int i = 0; i < length; i++) { jaroslav@810: types[i] = readType(in, method); jaroslav@810: } jaroslav@810: return types; jaroslav@810: } jaroslav@810: jaroslav@810: static final int readType(DataInputStream in, MethodData method) throws IOException { jaroslav@810: int type = in.readUnsignedByte(); jaroslav@810: if (type == ITEM_Object || type == ITEM_NewObject) { jaroslav@810: type = type | (in.readUnsignedShort() << 8); jaroslav@810: } jaroslav@810: return type; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: static final class StackMapIterator { jaroslav@810: jaroslav@810: private final StackMapTableData[] stackMapTable; jaroslav@810: private final TypeArray argTypes; jaroslav@810: private final TypeArray localTypes; jaroslav@810: private final TypeArray stackTypes; jaroslav@810: private int nextFrameIndex; jaroslav@810: private int lastFrameByteCodeOffset; jaroslav@810: private int byteCodeOffset; jaroslav@810: jaroslav@810: StackMapIterator(final MethodData methodData) { jaroslav@810: this(methodData.getStackMapTable(), jaroslav@810: methodData.getInternalSig(), jaroslav@810: methodData.isStatic()); jaroslav@810: } jaroslav@810: jaroslav@810: StackMapIterator(final StackMapTableData[] stackMapTable, jaroslav@810: final String methodSignature, jaroslav@810: final boolean isStaticMethod) { jaroslav@810: this.stackMapTable = (stackMapTable != null) jaroslav@810: ? stackMapTable jaroslav@810: : new StackMapTableData[0]; jaroslav@810: jaroslav@810: argTypes = getArgTypes(methodSignature, isStaticMethod); jaroslav@810: localTypes = new TypeArray(); jaroslav@810: stackTypes = new TypeArray(); jaroslav@810: jaroslav@810: localTypes.addAll(argTypes); jaroslav@810: jaroslav@810: lastFrameByteCodeOffset = -1; jaroslav@810: advanceBy(0); jaroslav@810: } jaroslav@1469: jaroslav@1469: public boolean isEmpty() { jaroslav@1469: return stackMapTable.length == 0; jaroslav@1469: } jaroslav@810: jaroslav@810: public String getFrameAsString() { jaroslav@810: return (nextFrameIndex == 0) jaroslav@810: ? StackMapTableData.toString("INITIAL", 0, null, null) jaroslav@810: : stackMapTable[nextFrameIndex - 1].toString(); jaroslav@810: } jaroslav@810: jaroslav@810: public int getFrameIndex() { jaroslav@810: return nextFrameIndex; jaroslav@810: } jaroslav@810: jaroslav@810: public TypeArray getFrameStack() { jaroslav@810: return stackTypes; jaroslav@810: } jaroslav@810: jaroslav@810: public TypeArray getFrameLocals() { jaroslav@810: return localTypes; jaroslav@810: } jaroslav@810: jaroslav@810: public TypeArray getArguments() { jaroslav@810: return argTypes; jaroslav@810: } jaroslav@810: jaroslav@810: public void advanceBy(final int numByteCodes) { jaroslav@810: if (numByteCodes < 0) { jaroslav@810: throw new IllegalStateException("Forward only iterator"); jaroslav@810: } jaroslav@810: jaroslav@810: byteCodeOffset += numByteCodes; jaroslav@810: while ((nextFrameIndex < stackMapTable.length) jaroslav@810: && ((byteCodeOffset - lastFrameByteCodeOffset) jaroslav@810: >= (stackMapTable[nextFrameIndex].offsetDelta jaroslav@810: + 1))) { jaroslav@810: final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; jaroslav@810: jaroslav@810: lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; jaroslav@810: nextFrame.applyTo(localTypes, stackTypes); jaroslav@810: jaroslav@810: ++nextFrameIndex; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: public void advanceTo(final int nextByteCodeOffset) { jaroslav@810: advanceBy(nextByteCodeOffset - byteCodeOffset); jaroslav@810: } jaroslav@810: jaroslav@810: private static TypeArray getArgTypes(final String methodSignature, jaroslav@810: final boolean isStaticMethod) { jaroslav@810: final TypeArray argTypes = new TypeArray(); jaroslav@810: jaroslav@810: if (!isStaticMethod) { jaroslav@810: argTypes.add(ITEM_Object); jaroslav@810: } jaroslav@810: jaroslav@810: if (methodSignature.charAt(0) != '(') { jaroslav@810: throw new IllegalArgumentException("Invalid method signature"); jaroslav@810: } jaroslav@810: jaroslav@810: final int length = methodSignature.length(); jaroslav@810: boolean skipType = false; jaroslav@810: int argType; jaroslav@810: for (int i = 1; i < length; ++i) { jaroslav@810: switch (methodSignature.charAt(i)) { jaroslav@810: case 'B': jaroslav@810: case 'C': jaroslav@810: case 'S': jaroslav@810: case 'Z': jaroslav@810: case 'I': jaroslav@810: argType = ITEM_Integer; jaroslav@810: break; jaroslav@810: case 'J': jaroslav@810: argType = ITEM_Long; jaroslav@810: break; jaroslav@810: case 'F': jaroslav@810: argType = ITEM_Float; jaroslav@810: break; jaroslav@810: case 'D': jaroslav@810: argType = ITEM_Double; jaroslav@810: break; jaroslav@810: case 'L': { jaroslav@810: i = methodSignature.indexOf(';', i + 1); jaroslav@810: if (i == -1) { jaroslav@810: throw new IllegalArgumentException( jaroslav@810: "Invalid method signature"); jaroslav@810: } jaroslav@810: argType = ITEM_Object; jaroslav@810: break; jaroslav@810: } jaroslav@810: case ')': jaroslav@810: // not interested in the return value type jaroslav@810: return argTypes; jaroslav@810: case '[': jaroslav@810: if (!skipType) { jaroslav@810: argTypes.add(ITEM_Object); jaroslav@810: skipType = true; jaroslav@810: } jaroslav@810: continue; jaroslav@810: jaroslav@810: default: jaroslav@810: throw new IllegalArgumentException( jaroslav@810: "Invalid method signature"); jaroslav@810: } jaroslav@810: jaroslav@810: if (!skipType) { jaroslav@810: argTypes.add(argType); jaroslav@810: } else { jaroslav@810: skipType = false; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: return argTypes; jaroslav@810: } jaroslav@810: } jaroslav@810: /* represents one entry of StackMapTable attribute jaroslav@810: */ jaroslav@810: jaroslav@810: private static abstract class StackMapTableData { jaroslav@810: jaroslav@810: final int frameType; jaroslav@810: int offsetDelta; jaroslav@810: jaroslav@810: StackMapTableData(int frameType) { jaroslav@810: this.frameType = frameType; jaroslav@810: } jaroslav@810: jaroslav@810: abstract void applyTo(TypeArray localTypes, TypeArray stackTypes); jaroslav@810: jaroslav@810: protected static String toString( jaroslav@810: final String frameType, jaroslav@810: final int offset, jaroslav@810: final int[] localTypes, jaroslav@810: final int[] stackTypes) { jaroslav@810: final StringBuilder sb = new StringBuilder(frameType); jaroslav@810: jaroslav@810: sb.append("(off: +").append(offset); jaroslav@810: if (localTypes != null) { jaroslav@810: sb.append(", locals: "); jaroslav@810: appendTypes(sb, localTypes); jaroslav@810: } jaroslav@810: if (stackTypes != null) { jaroslav@810: sb.append(", stack: "); jaroslav@810: appendTypes(sb, stackTypes); jaroslav@810: } jaroslav@810: sb.append(')'); jaroslav@810: jaroslav@810: return sb.toString(); jaroslav@810: } jaroslav@810: jaroslav@810: private static void appendTypes(final StringBuilder sb, final int[] types) { jaroslav@810: sb.append('['); jaroslav@810: if (types.length > 0) { jaroslav@810: sb.append(TypeArray.typeString(types[0])); jaroslav@810: for (int i = 1; i < types.length; ++i) { jaroslav@810: sb.append(", "); jaroslav@810: sb.append(TypeArray.typeString(types[i])); jaroslav@810: } jaroslav@810: } jaroslav@810: sb.append(']'); jaroslav@810: } jaroslav@810: jaroslav@810: private static class SameFrame extends StackMapTableData { jaroslav@810: jaroslav@810: SameFrame(int frameType, int offsetDelta) { jaroslav@810: super(frameType); jaroslav@810: this.offsetDelta = offsetDelta; jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: void applyTo(TypeArray localTypes, TypeArray stackTypes) { jaroslav@810: stackTypes.clear(); jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED) jaroslav@810: ? "_FRAME_EXTENDED" : ""), jaroslav@810: offsetDelta, jaroslav@810: null, null); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private static class SameLocals1StackItem extends StackMapTableData { jaroslav@810: jaroslav@810: final int[] stack; jaroslav@810: jaroslav@810: SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) { jaroslav@810: super(frameType); jaroslav@810: this.offsetDelta = offsetDelta; jaroslav@810: this.stack = stack; jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: void applyTo(TypeArray localTypes, TypeArray stackTypes) { jaroslav@810: stackTypes.setAll(stack); jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: return toString( jaroslav@810: "SAME_LOCALS_1_STACK_ITEM" jaroslav@810: + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) jaroslav@810: ? "_EXTENDED" : ""), jaroslav@810: offsetDelta, jaroslav@810: null, stack); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private static class ChopFrame extends StackMapTableData { jaroslav@810: jaroslav@810: ChopFrame(int frameType, int offsetDelta) { jaroslav@810: super(frameType); jaroslav@810: this.offsetDelta = offsetDelta; jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: void applyTo(TypeArray localTypes, TypeArray stackTypes) { jaroslav@810: localTypes.setSize(localTypes.getSize() jaroslav@810: - (SAME_FRAME_EXTENDED - frameType)); jaroslav@810: stackTypes.clear(); jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: return toString("CHOP", offsetDelta, null, null); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private static class AppendFrame extends StackMapTableData { jaroslav@810: jaroslav@810: final int[] locals; jaroslav@810: jaroslav@810: AppendFrame(int frameType, int offsetDelta, int[] locals) { jaroslav@810: super(frameType); jaroslav@810: this.offsetDelta = offsetDelta; jaroslav@810: this.locals = locals; jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: void applyTo(TypeArray localTypes, TypeArray stackTypes) { jaroslav@810: localTypes.addAll(locals); jaroslav@810: stackTypes.clear(); jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: return toString("APPEND", offsetDelta, locals, null); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private static class FullFrame extends StackMapTableData { jaroslav@810: jaroslav@810: final int[] locals; jaroslav@810: final int[] stack; jaroslav@810: jaroslav@810: FullFrame(int offsetDelta, int[] locals, int[] stack) { jaroslav@810: super(FULL_FRAME); jaroslav@810: this.offsetDelta = offsetDelta; jaroslav@810: this.locals = locals; jaroslav@810: this.stack = stack; jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: void applyTo(TypeArray localTypes, TypeArray stackTypes) { jaroslav@810: localTypes.setAll(locals); jaroslav@810: stackTypes.setAll(stack); jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: return toString("FULL", offsetDelta, locals, stack); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: static StackMapTableData getInstance(DataInputStream in, MethodData method) jaroslav@810: throws IOException { jaroslav@810: int frameType = in.readUnsignedByte(); jaroslav@810: jaroslav@810: if (frameType < SAME_FRAME_BOUND) { jaroslav@810: // same_frame jaroslav@810: return new SameFrame(frameType, frameType); jaroslav@810: } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) { jaroslav@810: // same_locals_1_stack_item_frame jaroslav@810: // read additional single stack element jaroslav@810: return new SameLocals1StackItem(frameType, jaroslav@810: (frameType - SAME_FRAME_BOUND), jaroslav@810: StackMapData.readTypeArray(in, 1, method)); jaroslav@810: } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { jaroslav@810: // same_locals_1_stack_item_extended jaroslav@810: return new SameLocals1StackItem(frameType, jaroslav@810: in.readUnsignedShort(), jaroslav@810: StackMapData.readTypeArray(in, 1, method)); jaroslav@810: } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) { jaroslav@810: // chop_frame or same_frame_extended jaroslav@810: return new ChopFrame(frameType, in.readUnsignedShort()); jaroslav@810: } else if (frameType == SAME_FRAME_EXTENDED) { jaroslav@810: // chop_frame or same_frame_extended jaroslav@810: return new SameFrame(frameType, in.readUnsignedShort()); jaroslav@810: } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) { jaroslav@810: // append_frame jaroslav@810: return new AppendFrame(frameType, in.readUnsignedShort(), jaroslav@810: StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method)); jaroslav@810: } else if (frameType == FULL_FRAME) { jaroslav@810: // full_frame jaroslav@810: int offsetDelta = in.readUnsignedShort(); jaroslav@810: int locals_size = in.readUnsignedShort(); jaroslav@810: int[] locals = StackMapData.readTypeArray(in, locals_size, method); jaroslav@810: int stack_size = in.readUnsignedShort(); jaroslav@810: int[] stack = StackMapData.readTypeArray(in, stack_size, method); jaroslav@810: return new FullFrame(offsetDelta, locals, stack); jaroslav@810: } else { jaroslav@810: throw new ClassFormatError("unrecognized frame_type in StackMapTable"); jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * Stores exception table data in code attribute. jaroslav@810: * jaroslav@810: * @author Sucheta Dambalkar (Adopted code from jdis) jaroslav@810: */ jaroslav@810: static final class TrapData { jaroslav@810: jaroslav@810: public final short start_pc; jaroslav@810: public final short end_pc; jaroslav@810: public final short handler_pc; jaroslav@810: public final short catch_cpx; jaroslav@810: final int num; jaroslav@810: jaroslav@810: /** jaroslav@810: * Read and store exception table data in code attribute. jaroslav@810: */ jaroslav@810: TrapData(DataInputStream in, int num) throws IOException { jaroslav@810: this.num = num; jaroslav@810: start_pc = in.readShort(); jaroslav@810: end_pc = in.readShort(); jaroslav@810: handler_pc = in.readShort(); jaroslav@810: catch_cpx = in.readShort(); jaroslav@810: } jaroslav@810: jaroslav@810: /** jaroslav@810: * returns recommended identifier jaroslav@810: */ jaroslav@810: public String ident() { jaroslav@810: return "t" + num; jaroslav@810: } jaroslav@810: } jaroslav@810: /** jaroslav@810: * jaroslav@810: * @author Jaroslav Tulach jaroslav@810: */ jaroslav@810: static final class TrapDataIterator { jaroslav@810: jaroslav@810: private final Hashtable exStart = new Hashtable(); jaroslav@810: private final Hashtable exStop = new Hashtable(); jaroslav@810: private TrapData[] current = new TrapData[10]; jaroslav@810: private int currentCount; jaroslav@810: jaroslav@810: TrapDataIterator(Vector exceptionTable) { jaroslav@810: for (int i = 0; i < exceptionTable.size(); i++) { jaroslav@810: final TrapData td = (TrapData) exceptionTable.elementAt(i); jaroslav@810: put(exStart, td.start_pc, td); jaroslav@810: put(exStop, td.end_pc, td); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: private static void put(Hashtable h, short key, TrapData td) { jaroslav@810: Short s = Short.valueOf((short) key); jaroslav@810: Vector v = (Vector) h.get(s); jaroslav@810: if (v == null) { jaroslav@810: v = new Vector(1); jaroslav@810: h.put(s, v); jaroslav@810: } jaroslav@810: v.add(td); jaroslav@810: } jaroslav@810: jaroslav@810: private boolean processAll(Hashtable h, Short key, boolean add) { jaroslav@810: boolean change = false; jaroslav@810: Vector v = (Vector) h.get(key); jaroslav@810: if (v != null) { jaroslav@810: int s = v.size(); jaroslav@810: for (int i = 0; i < s; i++) { jaroslav@810: TrapData td = (TrapData) v.elementAt(i); jaroslav@810: if (add) { jaroslav@810: add(td); jaroslav@810: change = true; jaroslav@810: } else { jaroslav@810: remove(td); jaroslav@810: change = true; jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: return change; jaroslav@810: } jaroslav@810: jaroslav@810: public boolean advanceTo(int i) { jaroslav@810: Short s = Short.valueOf((short) i); jaroslav@810: boolean ch1 = processAll(exStart, s, true); jaroslav@810: boolean ch2 = processAll(exStop, s, false); jaroslav@810: return ch1 || ch2; jaroslav@810: } jaroslav@810: jaroslav@810: public boolean useTry() { jaroslav@810: return currentCount > 0; jaroslav@810: } jaroslav@810: jaroslav@810: public TrapData[] current() { jaroslav@810: TrapData[] copy = new TrapData[currentCount]; jaroslav@810: for (int i = 0; i < currentCount; i++) { jaroslav@810: copy[i] = current[i]; jaroslav@810: } jaroslav@810: return copy; jaroslav@810: } jaroslav@810: jaroslav@810: private void add(TrapData e) { jaroslav@810: if (currentCount == current.length) { jaroslav@810: TrapData[] data = new TrapData[currentCount * 2]; jaroslav@810: for (int i = 0; i < currentCount; i++) { jaroslav@810: data[i] = current[i]; jaroslav@810: } jaroslav@810: current = data; jaroslav@810: } jaroslav@810: current[currentCount++] = e; jaroslav@810: } jaroslav@810: jaroslav@810: private void remove(TrapData e) { jaroslav@810: if (currentCount == 0) { jaroslav@810: return; jaroslav@810: } jaroslav@810: int from = 0; jaroslav@810: while (from < currentCount) { jaroslav@810: if (e == current[from++]) { jaroslav@810: break; jaroslav@810: } jaroslav@810: } jaroslav@810: while (from < currentCount) { jaroslav@810: current[from - 1] = current[from]; jaroslav@810: current[from] = null; jaroslav@810: from++; jaroslav@810: } jaroslav@810: currentCount--; jaroslav@810: } jaroslav@810: } jaroslav@810: static final class TypeArray { jaroslav@810: jaroslav@810: private static final int CAPACITY_INCREMENT = 16; jaroslav@810: private int[] types; jaroslav@810: private int size; jaroslav@810: jaroslav@810: public TypeArray() { jaroslav@810: } jaroslav@810: jaroslav@810: public TypeArray(final TypeArray initialTypes) { jaroslav@810: setAll(initialTypes); jaroslav@810: } jaroslav@810: jaroslav@810: public void add(final int newType) { jaroslav@810: ensureCapacity(size + 1); jaroslav@810: types[size++] = newType; jaroslav@810: } jaroslav@810: jaroslav@810: public void addAll(final TypeArray newTypes) { jaroslav@810: addAll(newTypes.types, 0, newTypes.size); jaroslav@810: } jaroslav@810: jaroslav@810: public void addAll(final int[] newTypes) { jaroslav@810: addAll(newTypes, 0, newTypes.length); jaroslav@810: } jaroslav@810: jaroslav@810: public void addAll(final int[] newTypes, jaroslav@810: final int offset, jaroslav@810: final int count) { jaroslav@810: if (count > 0) { jaroslav@810: ensureCapacity(size + count); jaroslav@810: arraycopy(newTypes, offset, types, size, count); jaroslav@810: size += count; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: public void set(final int index, final int newType) { jaroslav@810: types[index] = newType; jaroslav@810: } jaroslav@810: jaroslav@810: public void setAll(final TypeArray newTypes) { jaroslav@810: setAll(newTypes.types, 0, newTypes.size); jaroslav@810: } jaroslav@810: jaroslav@810: public void setAll(final int[] newTypes) { jaroslav@810: setAll(newTypes, 0, newTypes.length); jaroslav@810: } jaroslav@810: jaroslav@810: public void setAll(final int[] newTypes, jaroslav@810: final int offset, jaroslav@810: final int count) { jaroslav@810: if (count > 0) { jaroslav@810: ensureCapacity(count); jaroslav@810: arraycopy(newTypes, offset, types, 0, count); jaroslav@810: size = count; jaroslav@810: } else { jaroslav@810: clear(); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: public void setSize(final int newSize) { jaroslav@810: if (size != newSize) { jaroslav@810: ensureCapacity(newSize); jaroslav@810: jaroslav@810: for (int i = size; i < newSize; ++i) { jaroslav@810: types[i] = 0; jaroslav@810: } jaroslav@810: size = newSize; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: public void clear() { jaroslav@810: size = 0; jaroslav@810: } jaroslav@810: jaroslav@810: public int getSize() { jaroslav@810: return size; jaroslav@810: } jaroslav@810: jaroslav@810: public int get(final int index) { jaroslav@810: return types[index]; jaroslav@810: } jaroslav@810: jaroslav@810: public static String typeString(final int type) { jaroslav@810: switch (type & 0xff) { jaroslav@810: case ITEM_Bogus: jaroslav@810: return "_top_"; jaroslav@810: case ITEM_Integer: jaroslav@810: return "_int_"; jaroslav@810: case ITEM_Float: jaroslav@810: return "_float_"; jaroslav@810: case ITEM_Double: jaroslav@810: return "_double_"; jaroslav@810: case ITEM_Long: jaroslav@810: return "_long_"; jaroslav@810: case ITEM_Null: jaroslav@810: return "_null_"; jaroslav@810: case ITEM_InitObject: // UninitializedThis jaroslav@810: return "_init_"; jaroslav@810: case ITEM_Object: jaroslav@810: return "_object_"; jaroslav@810: case ITEM_NewObject: // Uninitialized jaroslav@810: return "_new_"; jaroslav@810: default: jaroslav@810: throw new IllegalArgumentException("Unknown type"); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: @Override jaroslav@810: public String toString() { jaroslav@810: final StringBuilder sb = new StringBuilder("["); jaroslav@810: if (size > 0) { jaroslav@810: sb.append(typeString(types[0])); jaroslav@810: for (int i = 1; i < size; ++i) { jaroslav@810: sb.append(", "); jaroslav@810: sb.append(typeString(types[i])); jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: return sb.append(']').toString(); jaroslav@810: } jaroslav@810: jaroslav@810: private void ensureCapacity(final int minCapacity) { jaroslav@810: if ((minCapacity == 0) jaroslav@810: || (types != null) && (minCapacity <= types.length)) { jaroslav@810: return; jaroslav@810: } jaroslav@810: jaroslav@810: final int newCapacity = jaroslav@810: ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT) jaroslav@810: * CAPACITY_INCREMENT; jaroslav@810: final int[] newTypes = new int[newCapacity]; jaroslav@810: jaroslav@810: if (size > 0) { jaroslav@810: arraycopy(types, 0, newTypes, 0, size); jaroslav@810: } jaroslav@810: jaroslav@810: types = newTypes; jaroslav@810: } jaroslav@810: jaroslav@810: // no System.arraycopy jaroslav@810: private void arraycopy(final int[] src, final int srcPos, jaroslav@810: final int[] dest, final int destPos, jaroslav@810: final int length) { jaroslav@810: for (int i = 0; i < length; ++i) { jaroslav@810: dest[destPos + i] = src[srcPos + i]; jaroslav@810: } jaroslav@810: } jaroslav@810: } jaroslav@810: /** jaroslav@810: * A JavaScript ready replacement for java.util.Vector jaroslav@810: * jaroslav@810: * @author Jaroslav Tulach jaroslav@810: */ jaroslav@810: @JavaScriptPrototype(prototype = "new Array") jaroslav@810: private static final class Vector { jaroslav@810: jaroslav@810: private Object[] arr; jaroslav@810: jaroslav@810: Vector() { jaroslav@810: } jaroslav@810: jaroslav@810: Vector(int i) { jaroslav@810: } jaroslav@810: jaroslav@810: void add(Object objectType) { jaroslav@810: addElement(objectType); jaroslav@810: } jaroslav@810: jaroslav@810: @JavaScriptBody(args = {"obj"}, body = jaroslav@810: "this.push(obj);") jaroslav@810: void addElement(Object obj) { jaroslav@810: final int s = size(); jaroslav@810: setSize(s + 1); jaroslav@810: setElementAt(obj, s); jaroslav@810: } jaroslav@810: jaroslav@810: @JavaScriptBody(args = {}, body = jaroslav@810: "return this.length;") jaroslav@810: int size() { jaroslav@810: return arr == null ? 0 : arr.length; jaroslav@810: } jaroslav@810: jaroslav@810: @JavaScriptBody(args = {"newArr"}, body = jaroslav@810: "for (var i = 0; i < this.length; i++) {\n" jaroslav@810: + " newArr[i] = this[i];\n" jaroslav@810: + "}\n") jaroslav@810: void copyInto(Object[] newArr) { jaroslav@810: if (arr == null) { jaroslav@810: return; jaroslav@810: } jaroslav@810: int min = Math.min(newArr.length, arr.length); jaroslav@810: for (int i = 0; i < min; i++) { jaroslav@810: newArr[i] = arr[i]; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: @JavaScriptBody(args = {"index"}, body = jaroslav@810: "return this[index];") jaroslav@810: Object elementAt(int index) { jaroslav@810: return arr[index]; jaroslav@810: } jaroslav@810: jaroslav@810: private void setSize(int len) { jaroslav@810: Object[] newArr = new Object[len]; jaroslav@810: copyInto(newArr); jaroslav@810: arr = newArr; jaroslav@810: } jaroslav@810: jaroslav@810: @JavaScriptBody(args = {"val", "index"}, body = jaroslav@810: "this[index] = val;") jaroslav@810: void setElementAt(Object val, int index) { jaroslav@810: arr[index] = val; jaroslav@810: } jaroslav@810: } jaroslav@810: jaroslav@810: }