diff -r 000000000000 -r 9eb750594b15 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Mon Mar 04 19:20:40 2013 +0100 @@ -0,0 +1,3461 @@ +/* + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.apidesign.vm4brwsr; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; + +/** This is a byte code parser heavily based on original code of JavaP utility. + * As such I decided to keep the original Oracle's GPLv2 header. + * + * @author Jaroslav Tulach + */ +final class ByteCodeParser { + private ByteCodeParser() { + } + /* Signature Characters */ + public static final char SIGC_VOID = 'V'; + public static final String SIG_VOID = "V"; + public static final char SIGC_BOOLEAN = 'Z'; + public static final String SIG_BOOLEAN = "Z"; + public static final char SIGC_BYTE = 'B'; + public static final String SIG_BYTE = "B"; + public static final char SIGC_CHAR = 'C'; + public static final String SIG_CHAR = "C"; + public static final char SIGC_SHORT = 'S'; + public static final String SIG_SHORT = "S"; + public static final char SIGC_INT = 'I'; + public static final String SIG_INT = "I"; + public static final char SIGC_LONG = 'J'; + public static final String SIG_LONG = "J"; + public static final char SIGC_FLOAT = 'F'; + public static final String SIG_FLOAT = "F"; + public static final char SIGC_DOUBLE = 'D'; + public static final String SIG_DOUBLE = "D"; + public static final char SIGC_ARRAY = '['; + public static final String SIG_ARRAY = "["; + public static final char SIGC_CLASS = 'L'; + public static final String SIG_CLASS = "L"; + public static final char SIGC_METHOD = '('; + public static final String SIG_METHOD = "("; + public static final char SIGC_ENDCLASS = ';'; + public static final String SIG_ENDCLASS = ";"; + public static final char SIGC_ENDMETHOD = ')'; + public static final String SIG_ENDMETHOD = ")"; + public static final char SIGC_PACKAGE = '/'; + public static final String SIG_PACKAGE = "/"; + + /* Class File Constants */ + public static final int JAVA_MAGIC = 0xcafebabe; + public static final int JAVA_VERSION = 45; + public static final int JAVA_MINOR_VERSION = 3; + + /* Constant table */ + public static final int CONSTANT_UTF8 = 1; + public static final int CONSTANT_UNICODE = 2; + public static final int CONSTANT_INTEGER = 3; + public static final int CONSTANT_FLOAT = 4; + public static final int CONSTANT_LONG = 5; + public static final int CONSTANT_DOUBLE = 6; + public static final int CONSTANT_CLASS = 7; + public static final int CONSTANT_STRING = 8; + public static final int CONSTANT_FIELD = 9; + public static final int CONSTANT_METHOD = 10; + public static final int CONSTANT_INTERFACEMETHOD = 11; + public static final int CONSTANT_NAMEANDTYPE = 12; + + /* Access Flags */ + public static final int ACC_PUBLIC = 0x00000001; + public static final int ACC_PRIVATE = 0x00000002; + public static final int ACC_PROTECTED = 0x00000004; + public static final int ACC_STATIC = 0x00000008; + public static final int ACC_FINAL = 0x00000010; + public static final int ACC_SYNCHRONIZED = 0x00000020; + public static final int ACC_SUPER = 0x00000020; + public static final int ACC_VOLATILE = 0x00000040; + public static final int ACC_TRANSIENT = 0x00000080; + public static final int ACC_NATIVE = 0x00000100; + public static final int ACC_INTERFACE = 0x00000200; + public static final int ACC_ABSTRACT = 0x00000400; + public static final int ACC_STRICT = 0x00000800; + public static final int ACC_EXPLICIT = 0x00001000; + public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute + + /* Type codes */ + public static final int T_CLASS = 0x00000002; + public static final int T_BOOLEAN = 0x00000004; + public static final int T_CHAR = 0x00000005; + public static final int T_FLOAT = 0x00000006; + public static final int T_DOUBLE = 0x00000007; + public static final int T_BYTE = 0x00000008; + public static final int T_SHORT = 0x00000009; + public static final int T_INT = 0x0000000a; + public static final int T_LONG = 0x0000000b; + + /* Type codes for StackMap attribute */ + public static final int ITEM_Bogus =0; // an unknown or uninitialized value + public static final int ITEM_Integer =1; // a 32-bit integer + public static final int ITEM_Float =2; // not used + public static final int ITEM_Double =3; // not used + public static final int ITEM_Long =4; // a 64-bit integer + public static final int ITEM_Null =5; // the type of null + public static final int ITEM_InitObject =6; // "this" in constructor + public static final int ITEM_Object =7; // followed by 2-byte index of class name + public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new" + + /* Constants used in StackMapTable attribute */ + public static final int SAME_FRAME_BOUND = 64; + public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; + public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; + public static final int SAME_FRAME_EXTENDED = 251; + public static final int FULL_FRAME = 255; + + /* Opcodes */ + public static final int opc_dead = -2; + public static final int opc_label = -1; + public static final int opc_nop = 0; + public static final int opc_aconst_null = 1; + public static final int opc_iconst_m1 = 2; + public static final int opc_iconst_0 = 3; + public static final int opc_iconst_1 = 4; + public static final int opc_iconst_2 = 5; + public static final int opc_iconst_3 = 6; + public static final int opc_iconst_4 = 7; + public static final int opc_iconst_5 = 8; + public static final int opc_lconst_0 = 9; + public static final int opc_lconst_1 = 10; + public static final int opc_fconst_0 = 11; + public static final int opc_fconst_1 = 12; + public static final int opc_fconst_2 = 13; + public static final int opc_dconst_0 = 14; + public static final int opc_dconst_1 = 15; + public static final int opc_bipush = 16; + public static final int opc_sipush = 17; + public static final int opc_ldc = 18; + public static final int opc_ldc_w = 19; + public static final int opc_ldc2_w = 20; + public static final int opc_iload = 21; + public static final int opc_lload = 22; + public static final int opc_fload = 23; + public static final int opc_dload = 24; + public static final int opc_aload = 25; + public static final int opc_iload_0 = 26; + public static final int opc_iload_1 = 27; + public static final int opc_iload_2 = 28; + public static final int opc_iload_3 = 29; + public static final int opc_lload_0 = 30; + public static final int opc_lload_1 = 31; + public static final int opc_lload_2 = 32; + public static final int opc_lload_3 = 33; + public static final int opc_fload_0 = 34; + public static final int opc_fload_1 = 35; + public static final int opc_fload_2 = 36; + public static final int opc_fload_3 = 37; + public static final int opc_dload_0 = 38; + public static final int opc_dload_1 = 39; + public static final int opc_dload_2 = 40; + public static final int opc_dload_3 = 41; + public static final int opc_aload_0 = 42; + public static final int opc_aload_1 = 43; + public static final int opc_aload_2 = 44; + public static final int opc_aload_3 = 45; + public static final int opc_iaload = 46; + public static final int opc_laload = 47; + public static final int opc_faload = 48; + public static final int opc_daload = 49; + public static final int opc_aaload = 50; + public static final int opc_baload = 51; + public static final int opc_caload = 52; + public static final int opc_saload = 53; + public static final int opc_istore = 54; + public static final int opc_lstore = 55; + public static final int opc_fstore = 56; + public static final int opc_dstore = 57; + public static final int opc_astore = 58; + public static final int opc_istore_0 = 59; + public static final int opc_istore_1 = 60; + public static final int opc_istore_2 = 61; + public static final int opc_istore_3 = 62; + public static final int opc_lstore_0 = 63; + public static final int opc_lstore_1 = 64; + public static final int opc_lstore_2 = 65; + public static final int opc_lstore_3 = 66; + public static final int opc_fstore_0 = 67; + public static final int opc_fstore_1 = 68; + public static final int opc_fstore_2 = 69; + public static final int opc_fstore_3 = 70; + public static final int opc_dstore_0 = 71; + public static final int opc_dstore_1 = 72; + public static final int opc_dstore_2 = 73; + public static final int opc_dstore_3 = 74; + public static final int opc_astore_0 = 75; + public static final int opc_astore_1 = 76; + public static final int opc_astore_2 = 77; + public static final int opc_astore_3 = 78; + public static final int opc_iastore = 79; + public static final int opc_lastore = 80; + public static final int opc_fastore = 81; + public static final int opc_dastore = 82; + public static final int opc_aastore = 83; + public static final int opc_bastore = 84; + public static final int opc_castore = 85; + public static final int opc_sastore = 86; + public static final int opc_pop = 87; + public static final int opc_pop2 = 88; + public static final int opc_dup = 89; + public static final int opc_dup_x1 = 90; + public static final int opc_dup_x2 = 91; + public static final int opc_dup2 = 92; + public static final int opc_dup2_x1 = 93; + public static final int opc_dup2_x2 = 94; + public static final int opc_swap = 95; + public static final int opc_iadd = 96; + public static final int opc_ladd = 97; + public static final int opc_fadd = 98; + public static final int opc_dadd = 99; + public static final int opc_isub = 100; + public static final int opc_lsub = 101; + public static final int opc_fsub = 102; + public static final int opc_dsub = 103; + public static final int opc_imul = 104; + public static final int opc_lmul = 105; + public static final int opc_fmul = 106; + public static final int opc_dmul = 107; + public static final int opc_idiv = 108; + public static final int opc_ldiv = 109; + public static final int opc_fdiv = 110; + public static final int opc_ddiv = 111; + public static final int opc_irem = 112; + public static final int opc_lrem = 113; + public static final int opc_frem = 114; + public static final int opc_drem = 115; + public static final int opc_ineg = 116; + public static final int opc_lneg = 117; + public static final int opc_fneg = 118; + public static final int opc_dneg = 119; + public static final int opc_ishl = 120; + public static final int opc_lshl = 121; + public static final int opc_ishr = 122; + public static final int opc_lshr = 123; + public static final int opc_iushr = 124; + public static final int opc_lushr = 125; + public static final int opc_iand = 126; + public static final int opc_land = 127; + public static final int opc_ior = 128; + public static final int opc_lor = 129; + public static final int opc_ixor = 130; + public static final int opc_lxor = 131; + public static final int opc_iinc = 132; + public static final int opc_i2l = 133; + public static final int opc_i2f = 134; + public static final int opc_i2d = 135; + public static final int opc_l2i = 136; + public static final int opc_l2f = 137; + public static final int opc_l2d = 138; + public static final int opc_f2i = 139; + public static final int opc_f2l = 140; + public static final int opc_f2d = 141; + public static final int opc_d2i = 142; + public static final int opc_d2l = 143; + public static final int opc_d2f = 144; + public static final int opc_i2b = 145; + public static final int opc_int2byte = 145; + public static final int opc_i2c = 146; + public static final int opc_int2char = 146; + public static final int opc_i2s = 147; + public static final int opc_int2short = 147; + public static final int opc_lcmp = 148; + public static final int opc_fcmpl = 149; + public static final int opc_fcmpg = 150; + public static final int opc_dcmpl = 151; + public static final int opc_dcmpg = 152; + public static final int opc_ifeq = 153; + public static final int opc_ifne = 154; + public static final int opc_iflt = 155; + public static final int opc_ifge = 156; + public static final int opc_ifgt = 157; + public static final int opc_ifle = 158; + public static final int opc_if_icmpeq = 159; + public static final int opc_if_icmpne = 160; + public static final int opc_if_icmplt = 161; + public static final int opc_if_icmpge = 162; + public static final int opc_if_icmpgt = 163; + public static final int opc_if_icmple = 164; + public static final int opc_if_acmpeq = 165; + public static final int opc_if_acmpne = 166; + public static final int opc_goto = 167; + public static final int opc_jsr = 168; + public static final int opc_ret = 169; + public static final int opc_tableswitch = 170; + public static final int opc_lookupswitch = 171; + public static final int opc_ireturn = 172; + public static final int opc_lreturn = 173; + public static final int opc_freturn = 174; + public static final int opc_dreturn = 175; + public static final int opc_areturn = 176; + public static final int opc_return = 177; + public static final int opc_getstatic = 178; + public static final int opc_putstatic = 179; + public static final int opc_getfield = 180; + public static final int opc_putfield = 181; + public static final int opc_invokevirtual = 182; + public static final int opc_invokenonvirtual = 183; + public static final int opc_invokespecial = 183; + public static final int opc_invokestatic = 184; + public static final int opc_invokeinterface = 185; +// public static final int opc_xxxunusedxxx = 186; + public static final int opc_new = 187; + public static final int opc_newarray = 188; + public static final int opc_anewarray = 189; + public static final int opc_arraylength = 190; + public static final int opc_athrow = 191; + public static final int opc_checkcast = 192; + public static final int opc_instanceof = 193; + public static final int opc_monitorenter = 194; + public static final int opc_monitorexit = 195; + public static final int opc_wide = 196; + public static final int opc_multianewarray = 197; + public static final int opc_ifnull = 198; + public static final int opc_ifnonnull = 199; + public static final int opc_goto_w = 200; + public static final int opc_jsr_w = 201; + /* Pseudo-instructions */ + public static final int opc_bytecode = 203; + public static final int opc_try = 204; + public static final int opc_endtry = 205; + public static final int opc_catch = 206; + public static final int opc_var = 207; + public static final int opc_endvar = 208; + public static final int opc_localsmap = 209; + public static final int opc_stackmap = 210; + /* PicoJava prefixes */ + public static final int opc_nonpriv = 254; + public static final int opc_priv = 255; + + /* Wide instructions */ + public static final int opc_iload_w = (opc_wide<<8)|opc_iload; + public static final int opc_lload_w = (opc_wide<<8)|opc_lload; + public static final int opc_fload_w = (opc_wide<<8)|opc_fload; + public static final int opc_dload_w = (opc_wide<<8)|opc_dload; + public static final int opc_aload_w = (opc_wide<<8)|opc_aload; + public static final int opc_istore_w = (opc_wide<<8)|opc_istore; + public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore; + public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore; + public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore; + public static final int opc_astore_w = (opc_wide<<8)|opc_astore; + public static final int opc_ret_w = (opc_wide<<8)|opc_ret; + public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc; + + /* Opcode Names */ + public static final String opcNamesTab[] = { + "nop", + "aconst_null", + "iconst_m1", + "iconst_0", + "iconst_1", + "iconst_2", + "iconst_3", + "iconst_4", + "iconst_5", + "lconst_0", + "lconst_1", + "fconst_0", + "fconst_1", + "fconst_2", + "dconst_0", + "dconst_1", + "bipush", + "sipush", + "ldc", + "ldc_w", + "ldc2_w", + "iload", + "lload", + "fload", + "dload", + "aload", + "iload_0", + "iload_1", + "iload_2", + "iload_3", + "lload_0", + "lload_1", + "lload_2", + "lload_3", + "fload_0", + "fload_1", + "fload_2", + "fload_3", + "dload_0", + "dload_1", + "dload_2", + "dload_3", + "aload_0", + "aload_1", + "aload_2", + "aload_3", + "iaload", + "laload", + "faload", + "daload", + "aaload", + "baload", + "caload", + "saload", + "istore", + "lstore", + "fstore", + "dstore", + "astore", + "istore_0", + "istore_1", + "istore_2", + "istore_3", + "lstore_0", + "lstore_1", + "lstore_2", + "lstore_3", + "fstore_0", + "fstore_1", + "fstore_2", + "fstore_3", + "dstore_0", + "dstore_1", + "dstore_2", + "dstore_3", + "astore_0", + "astore_1", + "astore_2", + "astore_3", + "iastore", + "lastore", + "fastore", + "dastore", + "aastore", + "bastore", + "castore", + "sastore", + "pop", + "pop2", + "dup", + "dup_x1", + "dup_x2", + "dup2", + "dup2_x1", + "dup2_x2", + "swap", + "iadd", + "ladd", + "fadd", + "dadd", + "isub", + "lsub", + "fsub", + "dsub", + "imul", + "lmul", + "fmul", + "dmul", + "idiv", + "ldiv", + "fdiv", + "ddiv", + "irem", + "lrem", + "frem", + "drem", + "ineg", + "lneg", + "fneg", + "dneg", + "ishl", + "lshl", + "ishr", + "lshr", + "iushr", + "lushr", + "iand", + "land", + "ior", + "lor", + "ixor", + "lxor", + "iinc", + "i2l", + "i2f", + "i2d", + "l2i", + "l2f", + "l2d", + "f2i", + "f2l", + "f2d", + "d2i", + "d2l", + "d2f", + "i2b", + "i2c", + "i2s", + "lcmp", + "fcmpl", + "fcmpg", + "dcmpl", + "dcmpg", + "ifeq", + "ifne", + "iflt", + "ifge", + "ifgt", + "ifle", + "if_icmpeq", + "if_icmpne", + "if_icmplt", + "if_icmpge", + "if_icmpgt", + "if_icmple", + "if_acmpeq", + "if_acmpne", + "goto", + "jsr", + "ret", + "tableswitch", + "lookupswitch", + "ireturn", + "lreturn", + "freturn", + "dreturn", + "areturn", + "return", + "getstatic", + "putstatic", + "getfield", + "putfield", + "invokevirtual", + "invokespecial", // was "invokenonvirtual", + "invokestatic", + "invokeinterface", + "bytecode 186", //"xxxunusedxxx", + "new", + "newarray", + "anewarray", + "arraylength", + "athrow", + "checkcast", + "instanceof", + "monitorenter", + "monitorexit", + null, // "wide", + "multianewarray", + "ifnull", + "ifnonnull", + "goto_w", + "jsr_w", + "bytecode 202", // "breakpoint", + "bytecode", + "try", + "endtry", + "catch", + "var", + "endvar", + "locals_map", + "stack_map" + }; + + /* Opcode Lengths */ + public static final int opcLengthsTab[] = { + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 3, + 2, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 99, + 99, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 5, + 0, + 3, + 2, + 3, + 1, + 1, + 3, + 3, + 1, + 1, + 0, // wide + 4, + 3, + 3, + 5, + 5, + 1, + 1, 0, 0, 0, 0, 0 // pseudo + }; + + /** + * End of input + */ + public static final int EOF = -1; + + /* + * Flags + */ + public static final int F_VERBOSE = 1 << 0; + public static final int F_DUMP = 1 << 1; + public static final int F_WARNINGS = 1 << 2; + public static final int F_DEBUG = 1 << 3; + public static final int F_OPTIMIZE = 1 << 4; + public static final int F_DEPENDENCIES = 1 << 5; + + /* + * Type codes + */ + public static final int TC_BOOLEAN = 0; + public static final int TC_BYTE = 1; + public static final int TC_CHAR = 2; + public static final int TC_SHORT = 3; + public static final int TC_INT = 4; + public static final int TC_LONG = 5; + public static final int TC_FLOAT = 6; + public static final int TC_DOUBLE = 7; + public static final int TC_NULL = 8; + public static final int TC_ARRAY = 9; + public static final int TC_CLASS = 10; + public static final int TC_VOID = 11; + public static final int TC_METHOD = 12; + public static final int TC_ERROR = 13; + + /* + * Type Masks + */ + public static final int TM_NULL = 1 << TC_NULL; + public static final int TM_VOID = 1 << TC_VOID; + public static final int TM_BOOLEAN = 1 << TC_BOOLEAN; + public static final int TM_BYTE = 1 << TC_BYTE; + public static final int TM_CHAR = 1 << TC_CHAR; + public static final int TM_SHORT = 1 << TC_SHORT; + public static final int TM_INT = 1 << TC_INT; + public static final int TM_LONG = 1 << TC_LONG; + public static final int TM_FLOAT = 1 << TC_FLOAT; + public static final int TM_DOUBLE = 1 << TC_DOUBLE; + public static final int TM_ARRAY = 1 << TC_ARRAY; + public static final int TM_CLASS = 1 << TC_CLASS; + public static final int TM_METHOD = 1 << TC_METHOD; + public static final int TM_ERROR = 1 << TC_ERROR; + + public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; + public static final int TM_NUM32 = TM_INT32 | TM_FLOAT; + public static final int TM_NUM64 = TM_LONG | TM_DOUBLE; + public static final int TM_INTEGER = TM_INT32 | TM_LONG; + public static final int TM_REAL = TM_FLOAT | TM_DOUBLE; + public static final int TM_NUMBER = TM_INTEGER | TM_REAL; + public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; + + /* + * Class status + */ + public static final int CS_UNDEFINED = 0; + public static final int CS_UNDECIDED = 1; + public static final int CS_BINARY = 2; + public static final int CS_SOURCE = 3; + public static final int CS_PARSED = 4; + public static final int CS_COMPILED = 5; + public static final int CS_NOTFOUND = 6; + + /* + * Attributes + */ + public static final int ATT_ALL = -1; + public static final int ATT_CODE = 1; + + /* + * Number of bits used in file offsets + */ + public static final int OFFSETBITS = 19; + public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1; + public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1; + + /* + * Operators + */ + public final int COMMA = 0; + public final int ASSIGN = 1; + + public final int ASGMUL = 2; + public final int ASGDIV = 3; + public final int ASGREM = 4; + public final int ASGADD = 5; + public final int ASGSUB = 6; + public final int ASGLSHIFT = 7; + public final int ASGRSHIFT = 8; + public final int ASGURSHIFT = 9; + public final int ASGBITAND = 10; + public final int ASGBITOR = 11; + public final int ASGBITXOR = 12; + + public final int COND = 13; + public final int OR = 14; + public final int AND = 15; + public final int BITOR = 16; + public final int BITXOR = 17; + public final int BITAND = 18; + public final int NE = 19; + public final int EQ = 20; + public final int GE = 21; + public final int GT = 22; + public final int LE = 23; + public final int LT = 24; + public final int INSTANCEOF = 25; + public final int LSHIFT = 26; + public final int RSHIFT = 27; + public final int URSHIFT = 28; + public final int ADD = 29; + public final int SUB = 30; + public final int DIV = 31; + public final int REM = 32; + public final int MUL = 33; + public final int CAST = 34; // (x)y + public final int POS = 35; // +x + public final int NEG = 36; // -x + public final int NOT = 37; + public final int BITNOT = 38; + public final int PREINC = 39; // ++x + public final int PREDEC = 40; // --x + public final int NEWARRAY = 41; + public final int NEWINSTANCE = 42; + public final int NEWFROMNAME = 43; + public final int POSTINC = 44; // x++ + public final int POSTDEC = 45; // x-- + public final int FIELD = 46; + public final int METHOD = 47; // x(y) + public final int ARRAYACCESS = 48; // x[y] + public final int NEW = 49; + public final int INC = 50; + public final int DEC = 51; + + public final int CONVERT = 55; // implicit conversion + public final int EXPR = 56; // (x) + public final int ARRAY = 57; // {x, y, ...} + public final int GOTO = 58; + + /* + * Value tokens + */ + public final int IDENT = 60; + public final int BOOLEANVAL = 61; + public final int BYTEVAL = 62; + public final int CHARVAL = 63; + public final int SHORTVAL = 64; + public final int INTVAL = 65; + public final int LONGVAL = 66; + public final int FLOATVAL = 67; + public final int DOUBLEVAL = 68; + public final int STRINGVAL = 69; + + /* + * Type keywords + */ + public final int BYTE = 70; + public final int CHAR = 71; + public final int SHORT = 72; + public final int INT = 73; + public final int LONG = 74; + public final int FLOAT = 75; + public final int DOUBLE = 76; + public final int VOID = 77; + public final int BOOLEAN = 78; + + /* + * Expression keywords + */ + public final int TRUE = 80; + public final int FALSE = 81; + public final int THIS = 82; + public final int SUPER = 83; + public final int NULL = 84; + + /* + * Statement keywords + */ + public final int IF = 90; + public final int ELSE = 91; + public final int FOR = 92; + public final int WHILE = 93; + public final int DO = 94; + public final int SWITCH = 95; + public final int CASE = 96; + public final int DEFAULT = 97; + public final int BREAK = 98; + public final int CONTINUE = 99; + public final int RETURN = 100; + public final int TRY = 101; + public final int CATCH = 102; + public final int FINALLY = 103; + public final int THROW = 104; + public final int STAT = 105; + public final int EXPRESSION = 106; + public final int DECLARATION = 107; + public final int VARDECLARATION = 108; + + /* + * Declaration keywords + */ + public final int IMPORT = 110; + public final int CLASS = 111; + public final int EXTENDS = 112; + public final int IMPLEMENTS = 113; + public final int INTERFACE = 114; + public final int PACKAGE = 115; + + /* + * Modifier keywords + */ + public final int PRIVATE = 120; + public final int PUBLIC = 121; + public final int PROTECTED = 122; + public final int CONST = 123; + public final int STATIC = 124; + public final int TRANSIENT = 125; + public final int SYNCHRONIZED = 126; + public final int NATIVE = 127; + public final int FINAL = 128; + public final int VOLATILE = 129; + public final int ABSTRACT = 130; + public final int STRICT = 165; + + /* + * Punctuation + */ + public final int SEMICOLON = 135; + public final int COLON = 136; + public final int QUESTIONMARK = 137; + public final int LBRACE = 138; + public final int RBRACE = 139; + public final int LPAREN = 140; + public final int RPAREN = 141; + public final int LSQBRACKET = 142; + public final int RSQBRACKET = 143; + public final int THROWS = 144; + + /* + * Special tokens + */ + public final int ERROR = 145; // an error + public final int COMMENT = 146; // not used anymore. + public final int TYPE = 147; + public final int LENGTH = 148; + public final int INLINERETURN = 149; + public final int INLINEMETHOD = 150; + public final int INLINENEWINSTANCE = 151; + + /* + * Added for jasm + */ + public final int METHODREF = 152; + public final int FIELDREF = 153; + public final int STACK = 154; + public final int LOCAL = 155; + public final int CPINDEX = 156; + public final int CPNAME = 157; + public final int SIGN = 158; + public final int BITS = 159; + public final int INF = 160; + public final int NAN = 161; + public final int INNERCLASS = 162; + public final int OF = 163; + public final int SYNTHETIC = 164; +// last used=165; + + /* + * Operator precedence + */ + public static final int opPrecedence[] = { + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, + 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, + 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, + 24, 25, 25, 26, 26, 26, 26, 26, 26 + }; + + /* + * Operator names + */ + public static final String opNames[] = { + ",", "=", "*=", "/=", "%=", + "+=", "-=", "<<=", ">>=", "<<<=", + "&=", "|=", "^=", "?:", "||", + "&&", "|", "^", "&", "!=", + "==", ">=", ">", "<=", "<", + "instanceof", "<<", ">>", "<<<", "+", + "-", "/", "%", "*", "cast", + "+", "-", "!", "~", "++", + "--", "new", "new", "new", "++", + "--", "field", "method", "[]", "new", + "++", "--", null, null, null, + + "convert", "expr", "array", "goto", null, + + "Identifier", "Boolean", "Byte", "Char", "Short", + "Integer", "Long", "Float", "Double", "String", + + "byte", "char", "short", "int", "long", + "float", "double", "void", "boolean", null, + + "true", "false", "this", "super", "null", + null, null, null, null, null, + + "if", "else", "for", "while", "do", + "switch", "case", "default", "break", "continue", + "return", "try", "catch", "finally", "throw", + "stat", "expression", "declaration", "declaration", null, + + "import", "class", "extends", "implements", "interface", + "package", null, null, null, null, + + "private", "public", "protected", "const", "static", + "transient", "synchronized", "native", "final", "volatile", + "abstract", null, null, null, null, + + ";", ":", "?", "{", "}", + "(", ")", "[", "]", "throws", + "error", "comment", "type", "length", "inline-return", + "inline-method", "inline-new", + "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN", + "bits", "INF", "NaN", "InnerClass", "of", "synthetic" + }; + + static class AnnotationParser { + + private final boolean textual; + private final boolean iterateArray; + + protected AnnotationParser(boolean textual, boolean iterateArray) { + this.textual = textual; + this.iterateArray = iterateArray; + } + + protected void visitAnnotationStart(String type, boolean top) throws IOException { + } + + protected void visitAnnotationEnd(String type, boolean top) throws IOException { + } + + protected void visitValueStart(String attrName, char type) throws IOException { + } + + protected void visitValueEnd(String attrName, char type) throws IOException { + } + + protected void visitAttr( + String annoType, String attr, String attrType, String value) throws IOException { + } + + protected void visitEnumAttr( + String annoType, String attr, String attrType, String value) throws IOException { + visitAttr(annoType, attr, attrType, value); + } + + /** + * Initialize the parsing with constant pool from + * cd. + * + * @param attr the attribute defining annotations + * @param cd constant pool + * @throws IOException in case I/O fails + */ + public final void parse(byte[] attr, ClassData cd) throws IOException { + ByteArrayInputStream is = new ByteArrayInputStream(attr); + DataInputStream dis = new DataInputStream(is); + try { + read(dis, cd); + } finally { + is.close(); + } + } + + private void read(DataInputStream dis, ClassData cd) throws IOException { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readAnno(dis, cd, true); + } + } + + private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException { + int type = dis.readUnsignedShort(); + String typeName = cd.StringValue(type); + visitAnnotationStart(typeName, top); + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + String attrName = cd.StringValue(dis.readUnsignedShort()); + readValue(dis, cd, typeName, attrName); + } + visitAnnotationEnd(typeName, top); + if (cnt == 0) { + visitAttr(typeName, null, null, null); + } + } + + private void readValue( + DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException { + char type = (char) dis.readByte(); + visitValueStart(attrName, type); + if (type == '@') { + readAnno(dis, cd, false); + } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N + int primitive = dis.readUnsignedShort(); + String val = cd.stringValue(primitive, textual); + String attrType; + if (type == 's') { + attrType = "Ljava_lang_String_2"; + if (textual) { + val = '"' + val + '"'; + } + } else { + attrType = "" + type; + } + visitAttr(typeName, attrName, attrType, val); + } else if (type == 'c') { + int cls = dis.readUnsignedShort(); + } else if (type == '[') { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readValue(dis, cd, typeName, iterateArray ? attrName : null); + } + } else if (type == 'e') { + int enumT = dis.readUnsignedShort(); + String attrType = cd.stringValue(enumT, textual); + int enumN = dis.readUnsignedShort(); + String val = cd.stringValue(enumN, textual); + visitEnumAttr(typeName, attrName, attrType, val); + } else { + throw new IOException("Unknown type " + type); + } + visitValueEnd(attrName, type); + } + } + + /** + * Reads and stores attribute information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class AttrData { + + ClassData cls; + int name_cpx; + int datalen; + byte data[]; + + public AttrData(ClassData cls) { + this.cls = cls; + } + + /** + * Reads unknown attribute. + */ + public void read(int name_cpx, DataInputStream in) throws IOException { + this.name_cpx = name_cpx; + datalen = in.readInt(); + data = new byte[datalen]; + in.readFully(data); + } + + /** + * Reads just the name of known attribute. + */ + public void read(int name_cpx) { + this.name_cpx = name_cpx; + } + + /** + * Returns attribute name. + */ + public String getAttrName() { + return cls.getString(name_cpx); + } + + /** + * Returns attribute data. + */ + public byte[] getData() { + return data; + } + } + + /** + * Stores constant pool entry information with one field. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class CPX { + + int cpx; + + CPX(int cpx) { + this.cpx = cpx; + } + } + + /** + * Stores constant pool entry information with two fields. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class CPX2 { + + int cpx1, cpx2; + + CPX2(int cpx1, int cpx2) { + this.cpx1 = cpx1; + this.cpx2 = cpx2; + } + } + + /** + * Central data repository of the Java Disassembler. Stores all the + * information in java class file. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static final class ClassData { + + private int magic; + private int minor_version; + private int major_version; + private int cpool_count; + private Object cpool[]; + private int access; + private int this_class = 0; + private int super_class; + private int interfaces_count; + private int[] interfaces = new int[0]; + private int fields_count; + private FieldData[] fields; + private int methods_count; + private MethodData[] methods; + private InnerClassData[] innerClasses; + private int attributes_count; + private AttrData[] attrs; + private String classname; + private String superclassname; + private int source_cpx = 0; + private byte tags[]; + private Hashtable indexHashAscii = new Hashtable(); + private String pkgPrefix = ""; + private int pkgPrefixLen = 0; + + /** + * Read classfile to disassemble. + */ + public ClassData(InputStream infile) throws IOException { + this.read(new DataInputStream(infile)); + } + + /** + * Reads and stores class file information. + */ + public void read(DataInputStream in) throws IOException { + // Read the header + magic = in.readInt(); + if (magic != JAVA_MAGIC) { + throw new ClassFormatError("wrong magic: " + + toHex(magic) + ", expected " + + toHex(JAVA_MAGIC)); + } + minor_version = in.readShort(); + major_version = in.readShort(); + if (major_version != JAVA_VERSION) { + } + + // Read the constant pool + readCP(in); + access = in.readUnsignedShort(); + this_class = in.readUnsignedShort(); + super_class = in.readUnsignedShort(); + + //Read interfaces. + interfaces_count = in.readUnsignedShort(); + if (interfaces_count > 0) { + interfaces = new int[interfaces_count]; + } + for (int i = 0; i < interfaces_count; i++) { + interfaces[i] = in.readShort(); + } + + // Read the fields + readFields(in); + + // Read the methods + readMethods(in); + + // Read the attributes + attributes_count = in.readUnsignedShort(); + attrs = new AttrData[attributes_count]; + for (int k = 0; k < attributes_count; k++) { + int name_cpx = in.readUnsignedShort(); + if (getTag(name_cpx) == CONSTANT_UTF8 + && getString(name_cpx).equals("SourceFile")) { + if (in.readInt() != 2) { + throw new ClassFormatError("invalid attr length"); + } + source_cpx = in.readUnsignedShort(); + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + + } else if (getTag(name_cpx) == CONSTANT_UTF8 + && getString(name_cpx).equals("InnerClasses")) { + int length = in.readInt(); + int num = in.readUnsignedShort(); + if (2 + num * 8 != length) { + throw new ClassFormatError("invalid attr length"); + } + innerClasses = new InnerClassData[num]; + for (int j = 0; j < num; j++) { + InnerClassData innerClass = new InnerClassData(this); + innerClass.read(in); + innerClasses[j] = innerClass; + } + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + } else { + AttrData attr = new AttrData(this); + attr.read(name_cpx, in); + attrs[k] = attr; + } + } + in.close(); + } // end ClassData.read() + + /** + * Reads and stores constant pool info. + */ + void readCP(DataInputStream in) throws IOException { + cpool_count = in.readUnsignedShort(); + tags = new byte[cpool_count]; + cpool = new Object[cpool_count]; + for (int i = 1; i < cpool_count; i++) { + byte tag = in.readByte(); + + switch (tags[i] = tag) { + case CONSTANT_UTF8: + String str = in.readUTF(); + indexHashAscii.put(cpool[i] = str, new Integer(i)); + break; + case CONSTANT_INTEGER: + cpool[i] = new Integer(in.readInt()); + break; + case CONSTANT_FLOAT: + cpool[i] = new Float(in.readFloat()); + break; + case CONSTANT_LONG: + cpool[i++] = new Long(in.readLong()); + break; + case CONSTANT_DOUBLE: + cpool[i++] = new Double(in.readDouble()); + break; + case CONSTANT_CLASS: + case CONSTANT_STRING: + cpool[i] = new CPX(in.readUnsignedShort()); + break; + + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_NAMEANDTYPE: + cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); + break; + + case 0: + default: + throw new ClassFormatError("invalid constant type: " + (int) tags[i]); + } + } + } + + /** + * Reads and strores field info. + */ + protected void readFields(DataInputStream in) throws IOException { + int fields_count = in.readUnsignedShort(); + fields = new FieldData[fields_count]; + for (int k = 0; k < fields_count; k++) { + FieldData field = new FieldData(this); + field.read(in); + fields[k] = field; + } + } + + /** + * Reads and strores Method info. + */ + protected void readMethods(DataInputStream in) throws IOException { + int methods_count = in.readUnsignedShort(); + methods = new MethodData[methods_count]; + for (int k = 0; k < methods_count; k++) { + MethodData method = new MethodData(this); + method.read(in); + methods[k] = method; + } + } + + /** + * get a string + */ + public String getString(int n) { + if (n == 0) { + return null; + } else { + return (String) cpool[n]; + } + } + + /** + * get the type of constant given an index + */ + public byte getTag(int n) { + try { + return tags[n]; + } catch (ArrayIndexOutOfBoundsException e) { + return (byte) 100; + } + } + static final String hexString = "0123456789ABCDEF"; + public static char hexTable[] = hexString.toCharArray(); + + static String toHex(long val, int width) { + StringBuffer s = new StringBuffer(); + for (int i = width - 1; i >= 0; i--) { + s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); + } + return "0x" + s.toString(); + } + + static String toHex(long val) { + int width; + for (width = 16; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + static String toHex(int val) { + int width; + for (width = 8; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + /** + * Returns the name of this class. + */ + public String getClassName() { + String res = null; + if (this_class == 0) { + return res; + } + int tcpx; + try { + if (tags[this_class] != CONSTANT_CLASS) { + return res; //" "; + } + tcpx = ((CPX) cpool[this_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String) (cpool[tcpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + } + + /** + * Returns the name of class at perticular index. + */ + public String getClassName(int cpx) { + String res = "#" + cpx; + if (cpx == 0) { + return res; + } + int scpx; + try { + if (tags[cpx] != CONSTANT_CLASS) { + return res; //" "; + } + scpx = ((CPX) cpool[cpx]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + res = "#" + scpx; + try { + return (String) (cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + public int getAccessFlags() { + return access; + } + + /** + * Returns true if it is a class + */ + public boolean isClass() { + if ((access & ACC_INTERFACE) == 0) { + return true; + } + return false; + } + + /** + * Returns true if it is a interface. + */ + public boolean isInterface() { + if ((access & ACC_INTERFACE) != 0) { + return true; + } + return false; + } + + /** + * Returns true if this member is public, false otherwise. + */ + public boolean isPublic() { + return (access & ACC_PUBLIC) != 0; + } + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_ABSTRACT) != 0) { + v.addElement("abstract"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns list of innerclasses. + */ + public InnerClassData[] getInnerClasses() { + return innerClasses; + } + + /** + * Returns list of attributes. + */ + final AttrData[] getAttributes() { + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + return findAttr(n, attrs); + } + + /** + * Returns true if superbit is set. + */ + public boolean isSuperSet() { + if ((access & ACC_SUPER) != 0) { + return true; + } + return false; + } + + /** + * Returns super class name. + */ + public String getSuperClassName() { + String res = null; + if (super_class == 0) { + return res; + } + int scpx; + try { + if (tags[super_class] != CONSTANT_CLASS) { + return res; //" "; + } + scpx = ((CPX) cpool[super_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String) (cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + /** + * Returns list of super interfaces. + */ + public String[] getSuperInterfaces() { + String interfacenames[] = new String[interfaces.length]; + int interfacecpx = -1; + for (int i = 0; i < interfaces.length; i++) { + interfacecpx = ((CPX) cpool[interfaces[i]]).cpx; + interfacenames[i] = (String) (cpool[interfacecpx]); + } + return interfacenames; + } + + /** + * Returns string at prticular constant pool index. + */ + public String getStringValue(int cpoolx) { + try { + return ((String) cpool[cpoolx]); + } catch (ArrayIndexOutOfBoundsException e) { + return "//invalid constant pool index:" + cpoolx; + } catch (ClassCastException e) { + return "//invalid constant pool ref:" + cpoolx; + } + } + + /** + * Returns list of field info. + */ + public FieldData[] getFields() { + return fields; + } + + /** + * Returns list of method info. + */ + public MethodData[] getMethods() { + return methods; + } + + /** + * Returns constant pool entry at that index. + */ + public CPX2 getCpoolEntry(int cpx) { + return ((CPX2) (cpool[cpx])); + } + + public Object getCpoolEntryobj(int cpx) { + return (cpool[cpx]); + } + + /** + * Returns index of this class. + */ + public int getthis_cpx() { + return this_class; + } + + /** + * Returns string at that index. + */ + public String StringValue(int cpx) { + return stringValue(cpx, false); + } + + public String stringValue(int cpx, boolean textual) { + return stringValue(cpx, textual, null); + } + + public String stringValue(int cpx, String[] classRefs) { + return stringValue(cpx, true, classRefs); + } + + private String stringValue(int cpx, boolean textual, String[] refs) { + if (cpx == 0) { + return "#0"; + } + int tag; + Object x; + String suffix = ""; + try { + tag = tags[cpx]; + x = cpool[cpx]; + } catch (IndexOutOfBoundsException e) { + return ""; + } + + if (x == null) { + return ""; + } + switch (tag) { + case CONSTANT_UTF8: { + if (!textual) { + return (String) x; + } + StringBuilder sb = new StringBuilder(); + String s = (String) x; + for (int k = 0; k < s.length(); k++) { + char c = s.charAt(k); + switch (c) { + case '\\': + sb.append('\\').append('\\'); + break; + case '\t': + sb.append('\\').append('t'); + break; + case '\n': + sb.append('\\').append('n'); + break; + case '\r': + sb.append('\\').append('r'); + break; + case '\"': + sb.append('\\').append('\"'); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + case CONSTANT_DOUBLE: { + Double d = (Double) x; + String sd = d.toString(); + if (textual) { + return sd; + } + return sd + "d"; + } + case CONSTANT_FLOAT: { + Float f = (Float) x; + String sf = (f).toString(); + if (textual) { + return sf; + } + return sf + "f"; + } + case CONSTANT_LONG: { + Long ln = (Long) x; + if (textual) { + return ln.toString(); + } + return ln.toString() + 'l'; + } + case CONSTANT_INTEGER: { + Integer in = (Integer) x; + return in.toString(); + } + case CONSTANT_CLASS: + String jn = getClassName(cpx); + if (textual) { + if (refs != null) { + refs[0] = jn; + } + return jn; + } + return javaName(jn); + case CONSTANT_STRING: + String sv = stringValue(((CPX) x).cpx, textual); + if (textual) { + return '"' + sv + '"'; + } else { + return sv; + } + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2); + return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2); + + case CONSTANT_NAMEANDTYPE: + return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2); + default: + return "UnknownTag"; //TBD + } + } + + /** + * Returns resolved java type name. + */ + public String javaName(String name) { + if (name == null) { + return "null"; + } + int len = name.length(); + if (len == 0) { + return "\"\""; + } + int cc = '/'; + fullname: + { // xxx/yyy/zzz + int cp; + for (int k = 0; k < len; k += Character.charCount(cp)) { + cp = name.codePointAt(k); + if (cc == '/') { + if (!isJavaIdentifierStart(cp)) { + break fullname; + } + } else if (cp != '/') { + if (!isJavaIdentifierPart(cp)) { + break fullname; + } + } + cc = cp; + } + return name; + } + return "\"" + name + "\""; + } + + public String getName(int cpx) { + String res; + try { + return javaName((String) cpool[cpx]); //.replace('/','.'); + } catch (ArrayIndexOutOfBoundsException e) { + return ""; + } catch (ClassCastException e) { + return ""; + } + } + + /** + * Returns unqualified class name. + */ + public String getShortClassName(int cpx) { + String classname = javaName(getClassName(cpx)); + pkgPrefixLen = classname.lastIndexOf("/") + 1; + if (pkgPrefixLen != 0) { + pkgPrefix = classname.substring(0, pkgPrefixLen); + if (classname.startsWith(pkgPrefix)) { + return classname.substring(pkgPrefixLen); + } + } + return classname; + } + + /** + * Returns source file name. + */ + public String getSourceName() { + return getName(source_cpx); + } + + /** + * Returns package name. + */ + public String getPkgName() { + String classname = getClassName(this_class); + pkgPrefixLen = classname.lastIndexOf("/") + 1; + if (pkgPrefixLen != 0) { + pkgPrefix = classname.substring(0, pkgPrefixLen); + return ("package " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n"); + } else { + return null; + } + } + + /** + * Returns total constant pool entry count. + */ + public int getCpoolCount() { + return cpool_count; + } + + /** + * Returns minor version of class file. + */ + public int getMinor_version() { + return minor_version; + } + + /** + * Returns major version of class file. + */ + public int getMajor_version() { + return major_version; + } + + private boolean isJavaIdentifierStart(int cp) { + return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); + } + + private boolean isJavaIdentifierPart(int cp) { + return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); + } + + public String[] getNameAndType(int indx) { + return getNameAndType(indx, 0, new String[2]); + } + + private String[] getNameAndType(int indx, int at, String[] arr) { + CPX2 c2 = getCpoolEntry(indx); + arr[at] = StringValue(c2.cpx1); + arr[at + 1] = StringValue(c2.cpx2); + return arr; + } + + public String[] getFieldInfoName(int indx) { + CPX2 c2 = getCpoolEntry(indx); + String[] arr = new String[3]; + arr[0] = getClassName(c2.cpx1); + return getNameAndType(c2.cpx2, 1, arr); + } + + static byte[] findAttr(String n, AttrData[] attrs) { + for (AttrData ad : attrs) { + if (n.equals(ad.getAttrName())) { + return ad.getData(); + } + } + return null; + } + } + + /** + * Strores field data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static class FieldData { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + int value_cpx = 0; + boolean isSynthetic = false; + boolean isDeprecated = false; + Vector attrs; + + public FieldData(ClassData cls) { + this.cls = cls; + } + + /** + * Read and store field info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + // Read the attributes + int attributes_count = in.readUnsignedShort(); + attrs = new Vector(attributes_count); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index = in.readUnsignedShort(); + if (cls.getTag(attr_name_index) != CONSTANT_UTF8) { + continue; + } + String attr_name = cls.getString(attr_name_index); + if (attr_name.equals("ConstantValue")) { + if (in.readInt() != 2) { + throw new ClassFormatError("invalid ConstantValue attr length"); + } + value_cpx = in.readUnsignedShort(); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Synthetic")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isSynthetic = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Deprecated")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isDeprecated = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else { + AttrData attr = new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + + } // end read + + public boolean isStatic() { + return (access & ACC_STATIC) != 0; + } + + /** + * Returns access of a field. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_PRIVATE) != 0) { + v.addElement("private"); + } + if ((access & ACC_PROTECTED) != 0) { + v.addElement("protected"); + } + if ((access & ACC_STATIC) != 0) { + v.addElement("static"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_VOLATILE) != 0) { + v.addElement("volatile"); + } + if ((access & ACC_TRANSIENT) != 0) { + v.addElement("transient"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns name of a field. + */ + public String getName() { + return cls.getStringValue(name_index); + } + + /** + * Returns internal signature of a field + */ + public String getInternalSig() { + return cls.getStringValue(descriptor_index); + } + + /** + * Returns true if field is synthetic. + */ + public boolean isSynthetic() { + return isSynthetic; + } + + /** + * Returns true if field is deprecated. + */ + public boolean isDeprecated() { + return isDeprecated; + } + + /** + * Returns index of constant value in cpool. + */ + public int getConstantValueIndex() { + return (value_cpx); + } + + /** + * Returns list of attributes of field. + */ + public Vector getAttributes() { + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + AttrData[] arr = new AttrData[attrs.size()]; + attrs.copyInto(arr); + return ClassData.findAttr(n, arr); + } + } + + /** + * A JavaScript optimized replacement for Hashtable. + * + * @author Jaroslav Tulach + */ + private static final class Hashtable { + + private Object[] keys; + private Object[] values; + + Hashtable(int i) { + this(); + } + + Hashtable(int i, double d) { + this(); + } + + Hashtable() { + } + + synchronized void put(Object key, Object val) { + int[] where = {-1, -1}; + Object found = get(key, where); + if (where[0] != -1) { + // key exists + values[where[0]] = val; + } else { + if (where[1] != -1) { + // null found + keys[where[1]] = key; + values[where[1]] = val; + } else { + if (keys == null) { + keys = new Object[11]; + values = new Object[11]; + keys[0] = key; + values[0] = val; + } else { + Object[] newKeys = new Object[keys.length * 2]; + Object[] newValues = new Object[values.length * 2]; + for (int i = 0; i < keys.length; i++) { + newKeys[i] = keys[i]; + newValues[i] = values[i]; + } + newKeys[keys.length] = key; + newValues[keys.length] = val; + keys = newKeys; + values = newValues; + } + } + } + } + + Object get(Object key) { + return get(key, null); + } + + private synchronized Object get(Object key, int[] foundAndNull) { + if (keys == null) { + return null; + } + for (int i = 0; i < keys.length; i++) { + if (keys[i] == null) { + if (foundAndNull != null) { + foundAndNull[1] = i; + } + } else if (keys[i].equals(key)) { + if (foundAndNull != null) { + foundAndNull[0] = i; + } + return values[i]; + } + } + return null; + } + } + + /** + * Strores InnerClass data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class InnerClassData { + + ClassData cls; + int inner_class_info_index, outer_class_info_index, inner_name_index, access; + + public InnerClassData(ClassData cls) { + this.cls = cls; + + } + + /** + * Read Innerclass attribute data. + */ + public void read(DataInputStream in) throws IOException { + inner_class_info_index = in.readUnsignedShort(); + outer_class_info_index = in.readUnsignedShort(); + inner_name_index = in.readUnsignedShort(); + access = in.readUnsignedShort(); + } // end read + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_ABSTRACT) != 0) { + v.addElement("abstract"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + } // end InnerClassData + + /** + * Strores LineNumberTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class LineNumData { + + short start_pc, line_number; + + public LineNumData() { + } + + /** + * Read LineNumberTable attribute. + */ + public LineNumData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + line_number = in.readShort(); + + } + } + + /** + * Strores LocalVariableTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class LocVarData { + + short start_pc, length, name_cpx, sig_cpx, slot; + + public LocVarData() { + } + + /** + * Read LocalVariableTable attribute. + */ + public LocVarData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + length = in.readShort(); + name_cpx = in.readShort(); + sig_cpx = in.readShort(); + slot = in.readShort(); + + } + } + /** + * Strores method data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static class MethodData { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + byte[] code; + Vector exception_table = new Vector(0); + Vector lin_num_tb = new Vector(0); + Vector loc_var_tb = new Vector(0); + StackMapTableData[] stackMapTable; + StackMapData[] stackMap; + int[] exc_index_table = null; + Vector attrs = new Vector(0); + Vector code_attrs = new Vector(0); + int max_stack, max_locals; + boolean isSynthetic = false; + boolean isDeprecated = false; + + public MethodData(ClassData cls) { + this.cls = cls; + } + + /** + * Read method info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + int attributes_count = in.readUnsignedShort(); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index = in.readUnsignedShort(); + + readAttr: + { + if (cls.getTag(attr_name_index) == CONSTANT_UTF8) { + String attr_name = cls.getString(attr_name_index); + if (attr_name.equals("Code")) { + readCode(in); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Exceptions")) { + readExceptions(in); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Synthetic")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isSynthetic = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Deprecated")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isDeprecated = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } + } + AttrData attr = new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + } + + /** + * Read code attribute info. + */ + public void readCode(DataInputStream in) throws IOException { + + int attr_length = in.readInt(); + max_stack = in.readUnsignedShort(); + max_locals = in.readUnsignedShort(); + int codelen = in.readInt(); + + code = new byte[codelen]; + int totalread = 0; + while (totalread < codelen) { + totalread += in.read(code, totalread, codelen - totalread); + } + // in.read(code, 0, codelen); + int clen = 0; + readExceptionTable(in); + int code_attributes_count = in.readUnsignedShort(); + + for (int k = 0; k < code_attributes_count; k++) { + int table_name_index = in.readUnsignedShort(); + int table_name_tag = cls.getTag(table_name_index); + AttrData attr = new AttrData(cls); + if (table_name_tag == CONSTANT_UTF8) { + String table_name_tstr = cls.getString(table_name_index); + if (table_name_tstr.equals("LineNumberTable")) { + readLineNumTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("LocalVariableTable")) { + readLocVarTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMapTable")) { + readStackMapTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMap")) { + readStackMap(in); + attr.read(table_name_index); + } else { + attr.read(table_name_index, in); + } + code_attrs.addElement(attr); + continue; + } + + attr.read(table_name_index, in); + code_attrs.addElement(attr); + } + } + + /** + * Read exception table info. + */ + void readExceptionTable(DataInputStream in) throws IOException { + int exception_table_len = in.readUnsignedShort(); + exception_table = new Vector(exception_table_len); + for (int l = 0; l < exception_table_len; l++) { + exception_table.addElement(new TrapData(in, l)); + } + } + + /** + * Read LineNumberTable attribute info. + */ + void readLineNumTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length + int lin_num_tb_len = in.readUnsignedShort(); + lin_num_tb = new Vector(lin_num_tb_len); + for (int l = 0; l < lin_num_tb_len; l++) { + lin_num_tb.addElement(new LineNumData(in)); + } + } + + /** + * Read LocalVariableTable attribute info. + */ + void readLocVarTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length + int loc_var_tb_len = in.readUnsignedShort(); + loc_var_tb = new Vector(loc_var_tb_len); + for (int l = 0; l < loc_var_tb_len; l++) { + loc_var_tb.addElement(new LocVarData(in)); + } + } + + /** + * Read Exception attribute info. + */ + public void readExceptions(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length in prog + int num_exceptions = in.readUnsignedShort(); + exc_index_table = new int[num_exceptions]; + for (int l = 0; l < num_exceptions; l++) { + int exc = in.readShort(); + exc_index_table[l] = exc; + } + } + + /** + * Read StackMapTable attribute info. + */ + void readStackMapTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); //attr_length + int stack_map_tb_len = in.readUnsignedShort(); + stackMapTable = new StackMapTableData[stack_map_tb_len]; + for (int i = 0; i < stack_map_tb_len; i++) { + stackMapTable[i] = StackMapTableData.getInstance(in, this); + } + } + + /** + * Read StackMap attribute info. + */ + void readStackMap(DataInputStream in) throws IOException { + int attr_len = in.readInt(); //attr_length + int stack_map_len = in.readUnsignedShort(); + stackMap = new StackMapData[stack_map_len]; + for (int i = 0; i < stack_map_len; i++) { + stackMap[i] = new StackMapData(in, this); + } + } + + /** + * Return access of the method. + */ + public int getAccess() { + return access; + } + + /** + * Return name of the method. + */ + public String getName() { + return cls.getStringValue(name_index); + } + + /** + * Return internal siganature of the method. + */ + public String getInternalSig() { + return cls.getStringValue(descriptor_index); + } + + /** + * Return code attribute data of a method. + */ + public byte[] getCode() { + return code; + } + + /** + * Return LineNumberTable size. + */ + public int getnumlines() { + return lin_num_tb.size(); + } + + /** + * Return LineNumberTable + */ + public Vector getlin_num_tb() { + return lin_num_tb; + } + + /** + * Return LocalVariableTable size. + */ + public int getloc_var_tbsize() { + return loc_var_tb.size(); + } + + /** + * Return LocalVariableTable. + */ + public Vector getloc_var_tb() { + return loc_var_tb; + } + + /** + * Return StackMap. + */ + public StackMapData[] getStackMap() { + return stackMap; + } + + /** + * Return StackMapTable. + */ + public StackMapTableData[] getStackMapTable() { + return stackMapTable; + } + + public StackMapIterator createStackMapIterator() { + return new StackMapIterator(this); + } + + /** + * Return true if method is static + */ + public boolean isStatic() { + if ((access & ACC_STATIC) != 0) { + return true; + } + return false; + } + + /** + * Return max depth of operand stack. + */ + public int getMaxStack() { + return max_stack; + } + + /** + * Return number of local variables. + */ + public int getMaxLocals() { + return max_locals; + } + + /** + * Return exception index table in Exception attribute. + */ + public int[] get_exc_index_table() { + return exc_index_table; + } + + /** + * Return exception table in code attributre. + */ + public TrapDataIterator getTrapDataIterator() { + return new TrapDataIterator(exception_table); + } + + /** + * Return method attributes. + */ + public Vector getAttributes() { + return attrs; + } + + /** + * Return code attributes. + */ + public Vector getCodeAttributes() { + return code_attrs; + } + + /** + * Return true if method id synthetic. + */ + public boolean isSynthetic() { + return isSynthetic; + } + + /** + * Return true if method is deprecated. + */ + public boolean isDeprecated() { + return isDeprecated; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + AttrData[] arr = new AttrData[attrs.size()]; + attrs.copyInto(arr); + return ClassData.findAttr(n, arr); + } + + public boolean isConstructor() { + return "".equals(getName()); + } + } + + /* represents one entry of StackMap attribute + */ + private static class StackMapData { + + final int offset; + final int[] locals; + final int[] stack; + + StackMapData(int offset, int[] locals, int[] stack) { + this.offset = offset; + this.locals = locals; + this.stack = stack; + } + + StackMapData(DataInputStream in, MethodData method) throws IOException { + offset = in.readUnsignedShort(); + int local_size = in.readUnsignedShort(); + locals = readTypeArray(in, local_size, method); + int stack_size = in.readUnsignedShort(); + stack = readTypeArray(in, stack_size, method); + } + + static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException { + int[] types = new int[length]; + for (int i = 0; i < length; i++) { + types[i] = readType(in, method); + } + return types; + } + + static final int readType(DataInputStream in, MethodData method) throws IOException { + int type = in.readUnsignedByte(); + if (type == ITEM_Object || type == ITEM_NewObject) { + type = type | (in.readUnsignedShort() << 8); + } + return type; + } + } + + static final class StackMapIterator { + + private final StackMapTableData[] stackMapTable; + private final TypeArray argTypes; + private final TypeArray localTypes; + private final TypeArray stackTypes; + private int nextFrameIndex; + private int lastFrameByteCodeOffset; + private int byteCodeOffset; + + StackMapIterator(final MethodData methodData) { + this(methodData.getStackMapTable(), + methodData.getInternalSig(), + methodData.isStatic()); + } + + StackMapIterator(final StackMapTableData[] stackMapTable, + final String methodSignature, + final boolean isStaticMethod) { + this.stackMapTable = (stackMapTable != null) + ? stackMapTable + : new StackMapTableData[0]; + + argTypes = getArgTypes(methodSignature, isStaticMethod); + localTypes = new TypeArray(); + stackTypes = new TypeArray(); + + localTypes.addAll(argTypes); + + lastFrameByteCodeOffset = -1; + advanceBy(0); + } + + public String getFrameAsString() { + return (nextFrameIndex == 0) + ? StackMapTableData.toString("INITIAL", 0, null, null) + : stackMapTable[nextFrameIndex - 1].toString(); + } + + public int getFrameIndex() { + return nextFrameIndex; + } + + public TypeArray getFrameStack() { + return stackTypes; + } + + public TypeArray getFrameLocals() { + return localTypes; + } + + public TypeArray getArguments() { + return argTypes; + } + + public void advanceBy(final int numByteCodes) { + if (numByteCodes < 0) { + throw new IllegalStateException("Forward only iterator"); + } + + byteCodeOffset += numByteCodes; + while ((nextFrameIndex < stackMapTable.length) + && ((byteCodeOffset - lastFrameByteCodeOffset) + >= (stackMapTable[nextFrameIndex].offsetDelta + + 1))) { + final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; + + lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; + nextFrame.applyTo(localTypes, stackTypes); + + ++nextFrameIndex; + } + } + + public void advanceTo(final int nextByteCodeOffset) { + advanceBy(nextByteCodeOffset - byteCodeOffset); + } + + private static TypeArray getArgTypes(final String methodSignature, + final boolean isStaticMethod) { + final TypeArray argTypes = new TypeArray(); + + if (!isStaticMethod) { + argTypes.add(ITEM_Object); + } + + if (methodSignature.charAt(0) != '(') { + throw new IllegalArgumentException("Invalid method signature"); + } + + final int length = methodSignature.length(); + boolean skipType = false; + int argType; + for (int i = 1; i < length; ++i) { + switch (methodSignature.charAt(i)) { + case 'B': + case 'C': + case 'S': + case 'Z': + case 'I': + argType = ITEM_Integer; + break; + case 'J': + argType = ITEM_Long; + break; + case 'F': + argType = ITEM_Float; + break; + case 'D': + argType = ITEM_Double; + break; + case 'L': { + i = methodSignature.indexOf(';', i + 1); + if (i == -1) { + throw new IllegalArgumentException( + "Invalid method signature"); + } + argType = ITEM_Object; + break; + } + case ')': + // not interested in the return value type + return argTypes; + case '[': + if (!skipType) { + argTypes.add(ITEM_Object); + skipType = true; + } + continue; + + default: + throw new IllegalArgumentException( + "Invalid method signature"); + } + + if (!skipType) { + argTypes.add(argType); + } else { + skipType = false; + } + } + + return argTypes; + } + } + /* represents one entry of StackMapTable attribute + */ + + private static abstract class StackMapTableData { + + final int frameType; + int offsetDelta; + + StackMapTableData(int frameType) { + this.frameType = frameType; + } + + abstract void applyTo(TypeArray localTypes, TypeArray stackTypes); + + protected static String toString( + final String frameType, + final int offset, + final int[] localTypes, + final int[] stackTypes) { + final StringBuilder sb = new StringBuilder(frameType); + + sb.append("(off: +").append(offset); + if (localTypes != null) { + sb.append(", locals: "); + appendTypes(sb, localTypes); + } + if (stackTypes != null) { + sb.append(", stack: "); + appendTypes(sb, stackTypes); + } + sb.append(')'); + + return sb.toString(); + } + + private static void appendTypes(final StringBuilder sb, final int[] types) { + sb.append('['); + if (types.length > 0) { + sb.append(TypeArray.typeString(types[0])); + for (int i = 1; i < types.length; ++i) { + sb.append(", "); + sb.append(TypeArray.typeString(types[i])); + } + } + sb.append(']'); + } + + private static class SameFrame extends StackMapTableData { + + SameFrame(int frameType, int offsetDelta) { + super(frameType); + this.offsetDelta = offsetDelta; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED) + ? "_FRAME_EXTENDED" : ""), + offsetDelta, + null, null); + } + } + + private static class SameLocals1StackItem extends StackMapTableData { + + final int[] stack; + + SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) { + super(frameType); + this.offsetDelta = offsetDelta; + this.stack = stack; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.setAll(stack); + } + + @Override + public String toString() { + return toString( + "SAME_LOCALS_1_STACK_ITEM" + + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) + ? "_EXTENDED" : ""), + offsetDelta, + null, stack); + } + } + + private static class ChopFrame extends StackMapTableData { + + ChopFrame(int frameType, int offsetDelta) { + super(frameType); + this.offsetDelta = offsetDelta; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setSize(localTypes.getSize() + - (SAME_FRAME_EXTENDED - frameType)); + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("CHOP", offsetDelta, null, null); + } + } + + private static class AppendFrame extends StackMapTableData { + + final int[] locals; + + AppendFrame(int frameType, int offsetDelta, int[] locals) { + super(frameType); + this.offsetDelta = offsetDelta; + this.locals = locals; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.addAll(locals); + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("APPEND", offsetDelta, locals, null); + } + } + + private static class FullFrame extends StackMapTableData { + + final int[] locals; + final int[] stack; + + FullFrame(int offsetDelta, int[] locals, int[] stack) { + super(FULL_FRAME); + this.offsetDelta = offsetDelta; + this.locals = locals; + this.stack = stack; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setAll(locals); + stackTypes.setAll(stack); + } + + @Override + public String toString() { + return toString("FULL", offsetDelta, locals, stack); + } + } + + static StackMapTableData getInstance(DataInputStream in, MethodData method) + throws IOException { + int frameType = in.readUnsignedByte(); + + if (frameType < SAME_FRAME_BOUND) { + // same_frame + return new SameFrame(frameType, frameType); + } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) { + // same_locals_1_stack_item_frame + // read additional single stack element + return new SameLocals1StackItem(frameType, + (frameType - SAME_FRAME_BOUND), + StackMapData.readTypeArray(in, 1, method)); + } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + // same_locals_1_stack_item_extended + return new SameLocals1StackItem(frameType, + in.readUnsignedShort(), + StackMapData.readTypeArray(in, 1, method)); + } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) { + // chop_frame or same_frame_extended + return new ChopFrame(frameType, in.readUnsignedShort()); + } else if (frameType == SAME_FRAME_EXTENDED) { + // chop_frame or same_frame_extended + return new SameFrame(frameType, in.readUnsignedShort()); + } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) { + // append_frame + return new AppendFrame(frameType, in.readUnsignedShort(), + StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method)); + } else if (frameType == FULL_FRAME) { + // full_frame + int offsetDelta = in.readUnsignedShort(); + int locals_size = in.readUnsignedShort(); + int[] locals = StackMapData.readTypeArray(in, locals_size, method); + int stack_size = in.readUnsignedShort(); + int[] stack = StackMapData.readTypeArray(in, stack_size, method); + return new FullFrame(offsetDelta, locals, stack); + } else { + throw new ClassFormatError("unrecognized frame_type in StackMapTable"); + } + } + } + + /** + * Stores exception table data in code attribute. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static final class TrapData { + + public final short start_pc; + public final short end_pc; + public final short handler_pc; + public final short catch_cpx; + final int num; + + /** + * Read and store exception table data in code attribute. + */ + TrapData(DataInputStream in, int num) throws IOException { + this.num = num; + start_pc = in.readShort(); + end_pc = in.readShort(); + handler_pc = in.readShort(); + catch_cpx = in.readShort(); + } + + /** + * returns recommended identifier + */ + public String ident() { + return "t" + num; + } + } + /** + * + * @author Jaroslav Tulach + */ + static final class TrapDataIterator { + + private final Hashtable exStart = new Hashtable(); + private final Hashtable exStop = new Hashtable(); + private TrapData[] current = new TrapData[10]; + private int currentCount; + + TrapDataIterator(Vector exceptionTable) { + for (int i = 0; i < exceptionTable.size(); i++) { + final TrapData td = (TrapData) exceptionTable.elementAt(i); + put(exStart, td.start_pc, td); + put(exStop, td.end_pc, td); + } + } + + private static void put(Hashtable h, short key, TrapData td) { + Short s = Short.valueOf((short) key); + Vector v = (Vector) h.get(s); + if (v == null) { + v = new Vector(1); + h.put(s, v); + } + v.add(td); + } + + private boolean processAll(Hashtable h, Short key, boolean add) { + boolean change = false; + Vector v = (Vector) h.get(key); + if (v != null) { + int s = v.size(); + for (int i = 0; i < s; i++) { + TrapData td = (TrapData) v.elementAt(i); + if (add) { + add(td); + change = true; + } else { + remove(td); + change = true; + } + } + } + return change; + } + + public boolean advanceTo(int i) { + Short s = Short.valueOf((short) i); + boolean ch1 = processAll(exStart, s, true); + boolean ch2 = processAll(exStop, s, false); + return ch1 || ch2; + } + + public boolean useTry() { + return currentCount > 0; + } + + public TrapData[] current() { + TrapData[] copy = new TrapData[currentCount]; + for (int i = 0; i < currentCount; i++) { + copy[i] = current[i]; + } + return copy; + } + + private void add(TrapData e) { + if (currentCount == current.length) { + TrapData[] data = new TrapData[currentCount * 2]; + for (int i = 0; i < currentCount; i++) { + data[i] = current[i]; + } + current = data; + } + current[currentCount++] = e; + } + + private void remove(TrapData e) { + if (currentCount == 0) { + return; + } + int from = 0; + while (from < currentCount) { + if (e == current[from++]) { + break; + } + } + while (from < currentCount) { + current[from - 1] = current[from]; + current[from] = null; + from++; + } + currentCount--; + } + } + static final class TypeArray { + + private static final int CAPACITY_INCREMENT = 16; + private int[] types; + private int size; + + public TypeArray() { + } + + public TypeArray(final TypeArray initialTypes) { + setAll(initialTypes); + } + + public void add(final int newType) { + ensureCapacity(size + 1); + types[size++] = newType; + } + + public void addAll(final TypeArray newTypes) { + addAll(newTypes.types, 0, newTypes.size); + } + + public void addAll(final int[] newTypes) { + addAll(newTypes, 0, newTypes.length); + } + + public void addAll(final int[] newTypes, + final int offset, + final int count) { + if (count > 0) { + ensureCapacity(size + count); + arraycopy(newTypes, offset, types, size, count); + size += count; + } + } + + public void set(final int index, final int newType) { + types[index] = newType; + } + + public void setAll(final TypeArray newTypes) { + setAll(newTypes.types, 0, newTypes.size); + } + + public void setAll(final int[] newTypes) { + setAll(newTypes, 0, newTypes.length); + } + + public void setAll(final int[] newTypes, + final int offset, + final int count) { + if (count > 0) { + ensureCapacity(count); + arraycopy(newTypes, offset, types, 0, count); + size = count; + } else { + clear(); + } + } + + public void setSize(final int newSize) { + if (size != newSize) { + ensureCapacity(newSize); + + for (int i = size; i < newSize; ++i) { + types[i] = 0; + } + size = newSize; + } + } + + public void clear() { + size = 0; + } + + public int getSize() { + return size; + } + + public int get(final int index) { + return types[index]; + } + + public static String typeString(final int type) { + switch (type & 0xff) { + case ITEM_Bogus: + return "_top_"; + case ITEM_Integer: + return "_int_"; + case ITEM_Float: + return "_float_"; + case ITEM_Double: + return "_double_"; + case ITEM_Long: + return "_long_"; + case ITEM_Null: + return "_null_"; + case ITEM_InitObject: // UninitializedThis + return "_init_"; + case ITEM_Object: + return "_object_"; + case ITEM_NewObject: // Uninitialized + return "_new_"; + default: + throw new IllegalArgumentException("Unknown type"); + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("["); + if (size > 0) { + sb.append(typeString(types[0])); + for (int i = 1; i < size; ++i) { + sb.append(", "); + sb.append(typeString(types[i])); + } + } + + return sb.append(']').toString(); + } + + private void ensureCapacity(final int minCapacity) { + if ((minCapacity == 0) + || (types != null) && (minCapacity <= types.length)) { + return; + } + + final int newCapacity = + ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT) + * CAPACITY_INCREMENT; + final int[] newTypes = new int[newCapacity]; + + if (size > 0) { + arraycopy(types, 0, newTypes, 0, size); + } + + types = newTypes; + } + + // no System.arraycopy + private void arraycopy(final int[] src, final int srcPos, + final int[] dest, final int destPos, + final int length) { + for (int i = 0; i < length; ++i) { + dest[destPos + i] = src[srcPos + i]; + } + } + } + /** + * A JavaScript ready replacement for java.util.Vector + * + * @author Jaroslav Tulach + */ + @JavaScriptPrototype(prototype = "new Array") + private static final class Vector { + + private Object[] arr; + + Vector() { + } + + Vector(int i) { + } + + void add(Object objectType) { + addElement(objectType); + } + + @JavaScriptBody(args = {"obj"}, body = + "this.push(obj);") + void addElement(Object obj) { + final int s = size(); + setSize(s + 1); + setElementAt(obj, s); + } + + @JavaScriptBody(args = {}, body = + "return this.length;") + int size() { + return arr == null ? 0 : arr.length; + } + + @JavaScriptBody(args = {"newArr"}, body = + "for (var i = 0; i < this.length; i++) {\n" + + " newArr[i] = this[i];\n" + + "}\n") + void copyInto(Object[] newArr) { + if (arr == null) { + return; + } + int min = Math.min(newArr.length, arr.length); + for (int i = 0; i < min; i++) { + newArr[i] = arr[i]; + } + } + + @JavaScriptBody(args = {"index"}, body = + "return this[index];") + Object elementAt(int index) { + return arr[index]; + } + + private void setSize(int len) { + Object[] newArr = new Object[len]; + copyInto(newArr); + arr = newArr; + } + + @JavaScriptBody(args = {"val", "index"}, body = + "this[index] = val;") + void setElementAt(Object val, int index) { + arr[index] = val; + } + } + +}