2 * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
25 package org.apidesign.vm4brwsr;
27 import java.io.ByteArrayInputStream;
28 import java.io.DataInputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import org.apidesign.bck2brwsr.core.JavaScriptBody;
32 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
34 /** This is a byte code parser heavily based on original code of JavaP utility.
35 * As such I decided to keep the original Oracle's GPLv2 header.
37 * @author Jaroslav Tulach <jtulach@netbeans.org>
39 final class ByteCodeParser {
40 private ByteCodeParser() {
43 /* Class File Constants */
44 public static final int JAVA_MAGIC = 0xcafebabe;
45 public static final int JAVA_VERSION = 45;
46 public static final int JAVA_MINOR_VERSION = 3;
49 public static final int CONSTANT_UTF8 = 1;
50 public static final int CONSTANT_UNICODE = 2;
51 public static final int CONSTANT_INTEGER = 3;
52 public static final int CONSTANT_FLOAT = 4;
53 public static final int CONSTANT_LONG = 5;
54 public static final int CONSTANT_DOUBLE = 6;
55 public static final int CONSTANT_CLASS = 7;
56 public static final int CONSTANT_STRING = 8;
57 public static final int CONSTANT_FIELD = 9;
58 public static final int CONSTANT_METHOD = 10;
59 public static final int CONSTANT_INTERFACEMETHOD = 11;
60 public static final int CONSTANT_NAMEANDTYPE = 12;
63 public static final int ACC_PUBLIC = 0x00000001;
64 public static final int ACC_PRIVATE = 0x00000002;
65 public static final int ACC_PROTECTED = 0x00000004;
66 public static final int ACC_STATIC = 0x00000008;
67 public static final int ACC_FINAL = 0x00000010;
68 public static final int ACC_SYNCHRONIZED = 0x00000020;
69 public static final int ACC_SUPER = 0x00000020;
70 public static final int ACC_VOLATILE = 0x00000040;
71 public static final int ACC_TRANSIENT = 0x00000080;
72 public static final int ACC_NATIVE = 0x00000100;
73 public static final int ACC_INTERFACE = 0x00000200;
74 public static final int ACC_ABSTRACT = 0x00000400;
75 public static final int ACC_STRICT = 0x00000800;
76 public static final int ACC_EXPLICIT = 0x00001000;
77 public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
79 /* Type codes for StackMap attribute */
80 public static final int ITEM_Bogus =0; // an unknown or uninitialized value
81 public static final int ITEM_Integer =1; // a 32-bit integer
82 public static final int ITEM_Float =2; // not used
83 public static final int ITEM_Double =3; // not used
84 public static final int ITEM_Long =4; // a 64-bit integer
85 public static final int ITEM_Null =5; // the type of null
86 public static final int ITEM_InitObject =6; // "this" in constructor
87 public static final int ITEM_Object =7; // followed by 2-byte index of class name
88 public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new"
90 /* Constants used in StackMapTable attribute */
91 public static final int SAME_FRAME_BOUND = 64;
92 public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128;
93 public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
94 public static final int SAME_FRAME_EXTENDED = 251;
95 public static final int FULL_FRAME = 255;
98 public static final int opc_dead = -2;
99 public static final int opc_label = -1;
100 public static final int opc_nop = 0;
101 public static final int opc_aconst_null = 1;
102 public static final int opc_iconst_m1 = 2;
103 public static final int opc_iconst_0 = 3;
104 public static final int opc_iconst_1 = 4;
105 public static final int opc_iconst_2 = 5;
106 public static final int opc_iconst_3 = 6;
107 public static final int opc_iconst_4 = 7;
108 public static final int opc_iconst_5 = 8;
109 public static final int opc_lconst_0 = 9;
110 public static final int opc_lconst_1 = 10;
111 public static final int opc_fconst_0 = 11;
112 public static final int opc_fconst_1 = 12;
113 public static final int opc_fconst_2 = 13;
114 public static final int opc_dconst_0 = 14;
115 public static final int opc_dconst_1 = 15;
116 public static final int opc_bipush = 16;
117 public static final int opc_sipush = 17;
118 public static final int opc_ldc = 18;
119 public static final int opc_ldc_w = 19;
120 public static final int opc_ldc2_w = 20;
121 public static final int opc_iload = 21;
122 public static final int opc_lload = 22;
123 public static final int opc_fload = 23;
124 public static final int opc_dload = 24;
125 public static final int opc_aload = 25;
126 public static final int opc_iload_0 = 26;
127 public static final int opc_iload_1 = 27;
128 public static final int opc_iload_2 = 28;
129 public static final int opc_iload_3 = 29;
130 public static final int opc_lload_0 = 30;
131 public static final int opc_lload_1 = 31;
132 public static final int opc_lload_2 = 32;
133 public static final int opc_lload_3 = 33;
134 public static final int opc_fload_0 = 34;
135 public static final int opc_fload_1 = 35;
136 public static final int opc_fload_2 = 36;
137 public static final int opc_fload_3 = 37;
138 public static final int opc_dload_0 = 38;
139 public static final int opc_dload_1 = 39;
140 public static final int opc_dload_2 = 40;
141 public static final int opc_dload_3 = 41;
142 public static final int opc_aload_0 = 42;
143 public static final int opc_aload_1 = 43;
144 public static final int opc_aload_2 = 44;
145 public static final int opc_aload_3 = 45;
146 public static final int opc_iaload = 46;
147 public static final int opc_laload = 47;
148 public static final int opc_faload = 48;
149 public static final int opc_daload = 49;
150 public static final int opc_aaload = 50;
151 public static final int opc_baload = 51;
152 public static final int opc_caload = 52;
153 public static final int opc_saload = 53;
154 public static final int opc_istore = 54;
155 public static final int opc_lstore = 55;
156 public static final int opc_fstore = 56;
157 public static final int opc_dstore = 57;
158 public static final int opc_astore = 58;
159 public static final int opc_istore_0 = 59;
160 public static final int opc_istore_1 = 60;
161 public static final int opc_istore_2 = 61;
162 public static final int opc_istore_3 = 62;
163 public static final int opc_lstore_0 = 63;
164 public static final int opc_lstore_1 = 64;
165 public static final int opc_lstore_2 = 65;
166 public static final int opc_lstore_3 = 66;
167 public static final int opc_fstore_0 = 67;
168 public static final int opc_fstore_1 = 68;
169 public static final int opc_fstore_2 = 69;
170 public static final int opc_fstore_3 = 70;
171 public static final int opc_dstore_0 = 71;
172 public static final int opc_dstore_1 = 72;
173 public static final int opc_dstore_2 = 73;
174 public static final int opc_dstore_3 = 74;
175 public static final int opc_astore_0 = 75;
176 public static final int opc_astore_1 = 76;
177 public static final int opc_astore_2 = 77;
178 public static final int opc_astore_3 = 78;
179 public static final int opc_iastore = 79;
180 public static final int opc_lastore = 80;
181 public static final int opc_fastore = 81;
182 public static final int opc_dastore = 82;
183 public static final int opc_aastore = 83;
184 public static final int opc_bastore = 84;
185 public static final int opc_castore = 85;
186 public static final int opc_sastore = 86;
187 public static final int opc_pop = 87;
188 public static final int opc_pop2 = 88;
189 public static final int opc_dup = 89;
190 public static final int opc_dup_x1 = 90;
191 public static final int opc_dup_x2 = 91;
192 public static final int opc_dup2 = 92;
193 public static final int opc_dup2_x1 = 93;
194 public static final int opc_dup2_x2 = 94;
195 public static final int opc_swap = 95;
196 public static final int opc_iadd = 96;
197 public static final int opc_ladd = 97;
198 public static final int opc_fadd = 98;
199 public static final int opc_dadd = 99;
200 public static final int opc_isub = 100;
201 public static final int opc_lsub = 101;
202 public static final int opc_fsub = 102;
203 public static final int opc_dsub = 103;
204 public static final int opc_imul = 104;
205 public static final int opc_lmul = 105;
206 public static final int opc_fmul = 106;
207 public static final int opc_dmul = 107;
208 public static final int opc_idiv = 108;
209 public static final int opc_ldiv = 109;
210 public static final int opc_fdiv = 110;
211 public static final int opc_ddiv = 111;
212 public static final int opc_irem = 112;
213 public static final int opc_lrem = 113;
214 public static final int opc_frem = 114;
215 public static final int opc_drem = 115;
216 public static final int opc_ineg = 116;
217 public static final int opc_lneg = 117;
218 public static final int opc_fneg = 118;
219 public static final int opc_dneg = 119;
220 public static final int opc_ishl = 120;
221 public static final int opc_lshl = 121;
222 public static final int opc_ishr = 122;
223 public static final int opc_lshr = 123;
224 public static final int opc_iushr = 124;
225 public static final int opc_lushr = 125;
226 public static final int opc_iand = 126;
227 public static final int opc_land = 127;
228 public static final int opc_ior = 128;
229 public static final int opc_lor = 129;
230 public static final int opc_ixor = 130;
231 public static final int opc_lxor = 131;
232 public static final int opc_iinc = 132;
233 public static final int opc_i2l = 133;
234 public static final int opc_i2f = 134;
235 public static final int opc_i2d = 135;
236 public static final int opc_l2i = 136;
237 public static final int opc_l2f = 137;
238 public static final int opc_l2d = 138;
239 public static final int opc_f2i = 139;
240 public static final int opc_f2l = 140;
241 public static final int opc_f2d = 141;
242 public static final int opc_d2i = 142;
243 public static final int opc_d2l = 143;
244 public static final int opc_d2f = 144;
245 public static final int opc_i2b = 145;
246 public static final int opc_int2byte = 145;
247 public static final int opc_i2c = 146;
248 public static final int opc_int2char = 146;
249 public static final int opc_i2s = 147;
250 public static final int opc_int2short = 147;
251 public static final int opc_lcmp = 148;
252 public static final int opc_fcmpl = 149;
253 public static final int opc_fcmpg = 150;
254 public static final int opc_dcmpl = 151;
255 public static final int opc_dcmpg = 152;
256 public static final int opc_ifeq = 153;
257 public static final int opc_ifne = 154;
258 public static final int opc_iflt = 155;
259 public static final int opc_ifge = 156;
260 public static final int opc_ifgt = 157;
261 public static final int opc_ifle = 158;
262 public static final int opc_if_icmpeq = 159;
263 public static final int opc_if_icmpne = 160;
264 public static final int opc_if_icmplt = 161;
265 public static final int opc_if_icmpge = 162;
266 public static final int opc_if_icmpgt = 163;
267 public static final int opc_if_icmple = 164;
268 public static final int opc_if_acmpeq = 165;
269 public static final int opc_if_acmpne = 166;
270 public static final int opc_goto = 167;
271 public static final int opc_jsr = 168;
272 public static final int opc_ret = 169;
273 public static final int opc_tableswitch = 170;
274 public static final int opc_lookupswitch = 171;
275 public static final int opc_ireturn = 172;
276 public static final int opc_lreturn = 173;
277 public static final int opc_freturn = 174;
278 public static final int opc_dreturn = 175;
279 public static final int opc_areturn = 176;
280 public static final int opc_return = 177;
281 public static final int opc_getstatic = 178;
282 public static final int opc_putstatic = 179;
283 public static final int opc_getfield = 180;
284 public static final int opc_putfield = 181;
285 public static final int opc_invokevirtual = 182;
286 public static final int opc_invokenonvirtual = 183;
287 public static final int opc_invokespecial = 183;
288 public static final int opc_invokestatic = 184;
289 public static final int opc_invokeinterface = 185;
290 // public static final int opc_xxxunusedxxx = 186;
291 public static final int opc_new = 187;
292 public static final int opc_newarray = 188;
293 public static final int opc_anewarray = 189;
294 public static final int opc_arraylength = 190;
295 public static final int opc_athrow = 191;
296 public static final int opc_checkcast = 192;
297 public static final int opc_instanceof = 193;
298 public static final int opc_monitorenter = 194;
299 public static final int opc_monitorexit = 195;
300 public static final int opc_wide = 196;
301 public static final int opc_multianewarray = 197;
302 public static final int opc_ifnull = 198;
303 public static final int opc_ifnonnull = 199;
304 public static final int opc_goto_w = 200;
305 public static final int opc_jsr_w = 201;
306 /* Pseudo-instructions */
307 public static final int opc_bytecode = 203;
308 public static final int opc_try = 204;
309 public static final int opc_endtry = 205;
310 public static final int opc_catch = 206;
311 public static final int opc_var = 207;
312 public static final int opc_endvar = 208;
313 public static final int opc_localsmap = 209;
314 public static final int opc_stackmap = 210;
315 /* PicoJava prefixes */
316 public static final int opc_nonpriv = 254;
317 public static final int opc_priv = 255;
319 /* Wide instructions *
320 public static final int opc_iload_w = (opc_wide<<8)|opc_iload;
321 public static final int opc_lload_w = (opc_wide<<8)|opc_lload;
322 public static final int opc_fload_w = (opc_wide<<8)|opc_fload;
323 public static final int opc_dload_w = (opc_wide<<8)|opc_dload;
324 public static final int opc_aload_w = (opc_wide<<8)|opc_aload;
325 public static final int opc_istore_w = (opc_wide<<8)|opc_istore;
326 public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore;
327 public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore;
328 public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore;
329 public static final int opc_astore_w = (opc_wide<<8)|opc_astore;
330 public static final int opc_ret_w = (opc_wide<<8)|opc_ret;
331 public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc;
333 static class AnnotationParser {
335 private final boolean textual;
336 private final boolean iterateArray;
338 protected AnnotationParser(boolean textual, boolean iterateArray) {
339 this.textual = textual;
340 this.iterateArray = iterateArray;
343 protected void visitAnnotationStart(String type, boolean top) throws IOException {
346 protected void visitAnnotationEnd(String type, boolean top) throws IOException {
349 protected void visitValueStart(String attrName, char type) throws IOException {
352 protected void visitValueEnd(String attrName, char type) throws IOException {
355 protected void visitAttr(
356 String annoType, String attr, String attrType, String value) throws IOException {
359 protected void visitEnumAttr(
360 String annoType, String attr, String attrType, String value) throws IOException {
361 visitAttr(annoType, attr, attrType, value);
365 * Initialize the parsing with constant pool from
368 * @param attr the attribute defining annotations
369 * @param cd constant pool
370 * @throws IOException in case I/O fails
372 public final void parse(byte[] attr, ClassData cd) throws IOException {
373 ByteArrayInputStream is = new ByteArrayInputStream(attr);
374 DataInputStream dis = new DataInputStream(is);
382 private void read(DataInputStream dis, ClassData cd) throws IOException {
383 int cnt = dis.readUnsignedShort();
384 for (int i = 0; i < cnt; i++) {
385 readAnno(dis, cd, true);
389 private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
390 int type = dis.readUnsignedShort();
391 String typeName = cd.StringValue(type);
392 visitAnnotationStart(typeName, top);
393 int cnt = dis.readUnsignedShort();
394 for (int i = 0; i < cnt; i++) {
395 String attrName = cd.StringValue(dis.readUnsignedShort());
396 readValue(dis, cd, typeName, attrName);
398 visitAnnotationEnd(typeName, top);
400 visitAttr(typeName, null, null, null);
404 private void readValue(
405 DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
406 char type = (char) dis.readByte();
407 visitValueStart(attrName, type);
409 readAnno(dis, cd, false);
410 } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
411 int primitive = dis.readUnsignedShort();
412 String val = cd.stringValue(primitive, textual);
415 attrType = "Ljava_lang_String_2";
417 val = '"' + val + '"';
420 attrType = "" + type;
422 visitAttr(typeName, attrName, attrType, val);
423 } else if (type == 'c') {
424 int cls = dis.readUnsignedShort();
425 } else if (type == '[') {
426 int cnt = dis.readUnsignedShort();
427 for (int i = 0; i < cnt; i++) {
428 readValue(dis, cd, typeName, iterateArray ? attrName : null);
430 } else if (type == 'e') {
431 int enumT = dis.readUnsignedShort();
432 String attrType = cd.stringValue(enumT, textual);
433 int enumN = dis.readUnsignedShort();
434 String val = cd.stringValue(enumN, textual);
435 visitEnumAttr(typeName, attrName, attrType, val);
437 throw new IOException("Unknown type " + type);
439 visitValueEnd(attrName, type);
444 * Reads and stores attribute information.
446 * @author Sucheta Dambalkar (Adopted code from jdis)
448 private static class AttrData {
455 public AttrData(ClassData cls) {
460 * Reads unknown attribute.
462 public void read(int name_cpx, DataInputStream in) throws IOException {
463 this.name_cpx = name_cpx;
464 datalen = in.readInt();
465 data = new byte[datalen];
470 * Reads just the name of known attribute.
472 public void read(int name_cpx) {
473 this.name_cpx = name_cpx;
477 * Returns attribute name.
479 public String getAttrName() {
480 return cls.getString(name_cpx);
484 * Returns attribute data.
486 public byte[] getData() {
492 * Stores constant pool entry information with one field.
494 * @author Sucheta Dambalkar (Adopted code from jdis)
496 private static class CPX {
506 * Stores constant pool entry information with two fields.
508 * @author Sucheta Dambalkar (Adopted code from jdis)
510 private static class CPX2 {
514 CPX2(int cpx1, int cpx2) {
521 * Central data repository of the Java Disassembler. Stores all the
522 * information in java class file.
524 * @author Sucheta Dambalkar (Adopted code from jdis)
526 static final class ClassData {
529 private int minor_version;
530 private int major_version;
531 private int cpool_count;
532 private Object cpool[];
534 private int this_class = 0;
535 private int super_class;
536 private int interfaces_count;
537 private int[] interfaces = new int[0];
538 private FieldData[] fields;
539 private MethodData[] methods;
540 private InnerClassData[] innerClasses;
541 private int attributes_count;
542 private AttrData[] attrs;
543 private int source_cpx = 0;
545 private Hashtable indexHashAscii = new Hashtable();
546 private String pkgPrefix = "";
547 private int pkgPrefixLen = 0;
550 * Read classfile to disassemble.
552 public ClassData(InputStream infile) throws IOException {
553 this.read(new DataInputStream(infile));
557 * Reads and stores class file information.
559 public void read(DataInputStream in) throws IOException {
561 magic = in.readInt();
562 if (magic != JAVA_MAGIC) {
563 throw new ClassFormatError("wrong magic: "
564 + toHex(magic) + ", expected "
565 + toHex(JAVA_MAGIC));
567 minor_version = in.readShort();
568 major_version = in.readShort();
569 if (major_version != JAVA_VERSION) {
572 // Read the constant pool
574 access = in.readUnsignedShort();
575 this_class = in.readUnsignedShort();
576 super_class = in.readUnsignedShort();
579 interfaces_count = in.readUnsignedShort();
580 if (interfaces_count > 0) {
581 interfaces = new int[interfaces_count];
583 for (int i = 0; i < interfaces_count; i++) {
584 interfaces[i] = in.readShort();
593 // Read the attributes
594 attributes_count = in.readUnsignedShort();
595 attrs = new AttrData[attributes_count];
596 for (int k = 0; k < attributes_count; k++) {
597 int name_cpx = in.readUnsignedShort();
598 if (getTag(name_cpx) == CONSTANT_UTF8
599 && getString(name_cpx).equals("SourceFile")) {
600 if (in.readInt() != 2) {
601 throw new ClassFormatError("invalid attr length");
603 source_cpx = in.readUnsignedShort();
604 AttrData attr = new AttrData(this);
608 } else if (getTag(name_cpx) == CONSTANT_UTF8
609 && getString(name_cpx).equals("InnerClasses")) {
610 int length = in.readInt();
611 int num = in.readUnsignedShort();
612 if (2 + num * 8 != length) {
613 throw new ClassFormatError("invalid attr length");
615 innerClasses = new InnerClassData[num];
616 for (int j = 0; j < num; j++) {
617 InnerClassData innerClass = new InnerClassData(this);
619 innerClasses[j] = innerClass;
621 AttrData attr = new AttrData(this);
625 AttrData attr = new AttrData(this);
626 attr.read(name_cpx, in);
631 } // end ClassData.read()
634 * Reads and stores constant pool info.
636 void readCP(DataInputStream in) throws IOException {
637 cpool_count = in.readUnsignedShort();
638 tags = new byte[cpool_count];
639 cpool = new Object[cpool_count];
640 for (int i = 1; i < cpool_count; i++) {
641 byte tag = in.readByte();
643 switch (tags[i] = tag) {
645 String str = in.readUTF();
646 indexHashAscii.put(cpool[i] = str, new Integer(i));
648 case CONSTANT_INTEGER:
649 cpool[i] = new Integer(in.readInt());
652 cpool[i] = new Float(in.readFloat());
655 cpool[i++] = new Long(in.readLong());
657 case CONSTANT_DOUBLE:
658 cpool[i++] = new Double(in.readDouble());
661 case CONSTANT_STRING:
662 cpool[i] = new CPX(in.readUnsignedShort());
666 case CONSTANT_METHOD:
667 case CONSTANT_INTERFACEMETHOD:
668 case CONSTANT_NAMEANDTYPE:
669 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
674 throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
680 * Reads and strores field info.
682 protected void readFields(DataInputStream in) throws IOException {
683 int fields_count = in.readUnsignedShort();
684 fields = new FieldData[fields_count];
685 for (int k = 0; k < fields_count; k++) {
686 FieldData field = new FieldData(this);
693 * Reads and strores Method info.
695 protected void readMethods(DataInputStream in) throws IOException {
696 int methods_count = in.readUnsignedShort();
697 methods = new MethodData[methods_count];
698 for (int k = 0; k < methods_count; k++) {
699 MethodData method = new MethodData(this);
708 public String getString(int n) {
712 return (String) cpool[n];
717 * get the type of constant given an index
719 public byte getTag(int n) {
722 } catch (ArrayIndexOutOfBoundsException e) {
726 static final String hexString = "0123456789ABCDEF";
727 public static char hexTable[] = hexString.toCharArray();
729 static String toHex(long val, int width) {
730 StringBuffer s = new StringBuffer();
731 for (int i = width - 1; i >= 0; i--) {
732 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
734 return "0x" + s.toString();
737 static String toHex(long val) {
739 for (width = 16; width > 0; width--) {
740 if ((val >> (width - 1) * 4) != 0) {
744 return toHex(val, width);
747 static String toHex(int val) {
749 for (width = 8; width > 0; width--) {
750 if ((val >> (width - 1) * 4) != 0) {
754 return toHex(val, width);
758 * Returns the name of this class.
760 public String getClassName() {
762 if (this_class == 0) {
767 if (tags[this_class] != CONSTANT_CLASS) {
768 return res; //"<CP["+cpx+"] is not a Class> ";
770 tcpx = ((CPX) cpool[this_class]).cpx;
771 } catch (ArrayIndexOutOfBoundsException e) {
772 return res; // "#"+cpx+"// invalid constant pool index";
773 } catch (Throwable e) {
774 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
778 return (String) (cpool[tcpx]);
779 } catch (ArrayIndexOutOfBoundsException e) {
780 return res; // "class #"+scpx+"// invalid constant pool index";
781 } catch (ClassCastException e) {
782 return res; // "class #"+scpx+"// invalid constant pool reference";
783 } catch (Throwable e) {
784 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
790 * Returns the name of class at perticular index.
792 public String getClassName(int cpx) {
793 String res = "#" + cpx;
799 if (tags[cpx] != CONSTANT_CLASS) {
800 return res; //"<CP["+cpx+"] is not a Class> ";
802 scpx = ((CPX) cpool[cpx]).cpx;
803 } catch (ArrayIndexOutOfBoundsException e) {
804 return res; // "#"+cpx+"// invalid constant pool index";
805 } catch (Throwable e) {
806 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
810 return (String) (cpool[scpx]);
811 } catch (ArrayIndexOutOfBoundsException e) {
812 return res; // "class #"+scpx+"// invalid constant pool index";
813 } catch (ClassCastException e) {
814 return res; // "class #"+scpx+"// invalid constant pool reference";
815 } catch (Throwable e) {
816 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
820 public int getAccessFlags() {
825 * Returns true if it is a class
827 public boolean isClass() {
828 if ((access & ACC_INTERFACE) == 0) {
835 * Returns true if it is a interface.
837 public boolean isInterface() {
838 if ((access & ACC_INTERFACE) != 0) {
845 * Returns true if this member is public, false otherwise.
847 public boolean isPublic() {
848 return (access & ACC_PUBLIC) != 0;
852 * Returns the access of this class or interface.
854 public String[] getAccess() {
855 Vector v = new Vector();
856 if ((access & ACC_PUBLIC) != 0) {
857 v.addElement("public");
859 if ((access & ACC_FINAL) != 0) {
860 v.addElement("final");
862 if ((access & ACC_ABSTRACT) != 0) {
863 v.addElement("abstract");
865 String[] accflags = new String[v.size()];
866 v.copyInto(accflags);
871 * Returns list of innerclasses.
873 public InnerClassData[] getInnerClasses() {
878 * Returns list of attributes.
880 final AttrData[] getAttributes() {
884 public byte[] findAnnotationData(boolean classRetention) {
885 String n = classRetention
886 ? "RuntimeInvisibleAnnotations" : // NOI18N
887 "RuntimeVisibleAnnotations"; // NOI18N
888 return findAttr(n, attrs);
892 * Returns true if superbit is set.
894 public boolean isSuperSet() {
895 if ((access & ACC_SUPER) != 0) {
902 * Returns super class name.
904 public String getSuperClassName() {
906 if (super_class == 0) {
911 if (tags[super_class] != CONSTANT_CLASS) {
912 return res; //"<CP["+cpx+"] is not a Class> ";
914 scpx = ((CPX) cpool[super_class]).cpx;
915 } catch (ArrayIndexOutOfBoundsException e) {
916 return res; // "#"+cpx+"// invalid constant pool index";
917 } catch (Throwable e) {
918 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
922 return (String) (cpool[scpx]);
923 } catch (ArrayIndexOutOfBoundsException e) {
924 return res; // "class #"+scpx+"// invalid constant pool index";
925 } catch (ClassCastException e) {
926 return res; // "class #"+scpx+"// invalid constant pool reference";
927 } catch (Throwable e) {
928 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
933 * Returns list of super interfaces.
935 public String[] getSuperInterfaces() {
936 String interfacenames[] = new String[interfaces.length];
937 int interfacecpx = -1;
938 for (int i = 0; i < interfaces.length; i++) {
939 interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
940 interfacenames[i] = (String) (cpool[interfacecpx]);
942 return interfacenames;
946 * Returns string at prticular constant pool index.
948 public String getStringValue(int cpoolx) {
950 return ((String) cpool[cpoolx]);
951 } catch (ArrayIndexOutOfBoundsException e) {
952 return "//invalid constant pool index:" + cpoolx;
953 } catch (ClassCastException e) {
954 return "//invalid constant pool ref:" + cpoolx;
959 * Returns list of field info.
961 public FieldData[] getFields() {
966 * Returns list of method info.
968 public MethodData[] getMethods() {
973 * Returns constant pool entry at that index.
975 public CPX2 getCpoolEntry(int cpx) {
976 return ((CPX2) (cpool[cpx]));
979 public Object getCpoolEntryobj(int cpx) {
984 * Returns index of this class.
986 public int getthis_cpx() {
991 * Returns string at that index.
993 public String StringValue(int cpx) {
994 return stringValue(cpx, false);
997 public String stringValue(int cpx, boolean textual) {
998 return stringValue(cpx, textual, null);
1001 public String stringValue(int cpx, String[] classRefs) {
1002 return stringValue(cpx, true, classRefs);
1005 private String stringValue(int cpx, boolean textual, String[] refs) {
1015 } catch (IndexOutOfBoundsException e) {
1016 return "<Incorrect CP index:" + cpx + ">";
1023 case CONSTANT_UTF8: {
1027 StringBuilder sb = new StringBuilder();
1028 String s = (String) x;
1029 for (int k = 0; k < s.length(); k++) {
1030 char c = s.charAt(k);
1033 sb.append('\\').append('\\');
1036 sb.append('\\').append('t');
1039 sb.append('\\').append('n');
1042 sb.append('\\').append('r');
1045 sb.append('\\').append('\"');
1048 sb.append("\\u2028");
1051 sb.append("\\u2029");
1057 return sb.toString();
1059 case CONSTANT_DOUBLE: {
1060 Double d = (Double) x;
1061 String sd = d.toString();
1067 case CONSTANT_FLOAT: {
1068 Float f = (Float) x;
1069 String sf = (f).toString();
1075 case CONSTANT_LONG: {
1078 return ln.toString();
1080 return ln.toString() + 'l';
1082 case CONSTANT_INTEGER: {
1083 Integer in = (Integer) x;
1084 return in.toString();
1086 case CONSTANT_CLASS:
1087 String jn = getClassName(cpx);
1094 return javaName(jn);
1095 case CONSTANT_STRING:
1096 String sv = stringValue(((CPX) x).cpx, textual);
1098 return '"' + sv + '"';
1102 case CONSTANT_FIELD:
1103 case CONSTANT_METHOD:
1104 case CONSTANT_INTERFACEMETHOD:
1105 //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
1106 return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
1108 case CONSTANT_NAMEANDTYPE:
1109 return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
1111 return "UnknownTag"; //TBD
1116 * Returns resolved java type name.
1118 public String javaName(String name) {
1122 int len = name.length();
1130 for (int k = 0; k < len; k += Character.charCount(cp)) {
1131 cp = name.codePointAt(k);
1133 if (!isJavaIdentifierStart(cp)) {
1136 } else if (cp != '/') {
1137 if (!isJavaIdentifierPart(cp)) {
1145 return "\"" + name + "\"";
1148 public String getName(int cpx) {
1151 return javaName((String) cpool[cpx]); //.replace('/','.');
1152 } catch (ArrayIndexOutOfBoundsException e) {
1153 return "<invalid constant pool index:" + cpx + ">";
1154 } catch (ClassCastException e) {
1155 return "<invalid constant pool ref:" + cpx + ">";
1160 * Returns unqualified class name.
1162 public String getShortClassName(int cpx) {
1163 String classname = javaName(getClassName(cpx));
1164 pkgPrefixLen = classname.lastIndexOf("/") + 1;
1165 if (pkgPrefixLen != 0) {
1166 pkgPrefix = classname.substring(0, pkgPrefixLen);
1167 if (classname.startsWith(pkgPrefix)) {
1168 return classname.substring(pkgPrefixLen);
1175 * Returns source file name.
1177 public String getSourceName() {
1178 return getName(source_cpx);
1182 * Returns package name.
1184 public String getPkgName() {
1185 String classname = getClassName(this_class);
1186 pkgPrefixLen = classname.lastIndexOf("/") + 1;
1187 if (pkgPrefixLen != 0) {
1188 pkgPrefix = classname.substring(0, pkgPrefixLen);
1189 return ("package " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
1196 * Returns total constant pool entry count.
1198 public int getCpoolCount() {
1203 * Returns minor version of class file.
1205 public int getMinor_version() {
1206 return minor_version;
1210 * Returns major version of class file.
1212 public int getMajor_version() {
1213 return major_version;
1216 private boolean isJavaIdentifierStart(int cp) {
1217 return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
1220 private boolean isJavaIdentifierPart(int cp) {
1221 return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
1224 public String[] getNameAndType(int indx) {
1225 return getNameAndType(indx, 0, new String[2]);
1228 private String[] getNameAndType(int indx, int at, String[] arr) {
1229 CPX2 c2 = getCpoolEntry(indx);
1230 arr[at] = StringValue(c2.cpx1);
1231 arr[at + 1] = StringValue(c2.cpx2);
1235 public String[] getFieldInfoName(int indx) {
1236 CPX2 c2 = getCpoolEntry(indx);
1237 String[] arr = new String[3];
1238 arr[0] = getClassName(c2.cpx1);
1239 return getNameAndType(c2.cpx2, 1, arr);
1242 static byte[] findAttr(String n, AttrData[] attrs) {
1243 for (AttrData ad : attrs) {
1244 if (n.equals(ad.getAttrName())) {
1245 return ad.getData();
1253 * Strores field data informastion.
1255 * @author Sucheta Dambalkar (Adopted code from jdis)
1257 static class FieldData {
1262 int descriptor_index;
1263 int attributes_count;
1265 boolean isSynthetic = false;
1266 boolean isDeprecated = false;
1269 public FieldData(ClassData cls) {
1274 * Read and store field info.
1276 public void read(DataInputStream in) throws IOException {
1277 access = in.readUnsignedShort();
1278 name_index = in.readUnsignedShort();
1279 descriptor_index = in.readUnsignedShort();
1280 // Read the attributes
1281 int attributes_count = in.readUnsignedShort();
1282 attrs = new Vector(attributes_count);
1283 for (int i = 0; i < attributes_count; i++) {
1284 int attr_name_index = in.readUnsignedShort();
1285 if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
1288 String attr_name = cls.getString(attr_name_index);
1289 if (attr_name.equals("ConstantValue")) {
1290 if (in.readInt() != 2) {
1291 throw new ClassFormatError("invalid ConstantValue attr length");
1293 value_cpx = in.readUnsignedShort();
1294 AttrData attr = new AttrData(cls);
1295 attr.read(attr_name_index);
1296 attrs.addElement(attr);
1297 } else if (attr_name.equals("Synthetic")) {
1298 if (in.readInt() != 0) {
1299 throw new ClassFormatError("invalid Synthetic attr length");
1302 AttrData attr = new AttrData(cls);
1303 attr.read(attr_name_index);
1304 attrs.addElement(attr);
1305 } else if (attr_name.equals("Deprecated")) {
1306 if (in.readInt() != 0) {
1307 throw new ClassFormatError("invalid Synthetic attr length");
1309 isDeprecated = true;
1310 AttrData attr = new AttrData(cls);
1311 attr.read(attr_name_index);
1312 attrs.addElement(attr);
1314 AttrData attr = new AttrData(cls);
1315 attr.read(attr_name_index, in);
1316 attrs.addElement(attr);
1322 public boolean isStatic() {
1323 return (access & ACC_STATIC) != 0;
1327 * Returns access of a field.
1329 public String[] getAccess() {
1330 Vector v = new Vector();
1331 if ((access & ACC_PUBLIC) != 0) {
1332 v.addElement("public");
1334 if ((access & ACC_PRIVATE) != 0) {
1335 v.addElement("private");
1337 if ((access & ACC_PROTECTED) != 0) {
1338 v.addElement("protected");
1340 if ((access & ACC_STATIC) != 0) {
1341 v.addElement("static");
1343 if ((access & ACC_FINAL) != 0) {
1344 v.addElement("final");
1346 if ((access & ACC_VOLATILE) != 0) {
1347 v.addElement("volatile");
1349 if ((access & ACC_TRANSIENT) != 0) {
1350 v.addElement("transient");
1352 String[] accflags = new String[v.size()];
1353 v.copyInto(accflags);
1358 * Returns name of a field.
1360 public String getName() {
1361 return cls.getStringValue(name_index);
1365 * Returns internal signature of a field
1367 public String getInternalSig() {
1368 return cls.getStringValue(descriptor_index);
1372 * Returns true if field is synthetic.
1374 public boolean isSynthetic() {
1379 * Returns true if field is deprecated.
1381 public boolean isDeprecated() {
1382 return isDeprecated;
1386 * Returns index of constant value in cpool.
1388 public int getConstantValueIndex() {
1393 * Returns list of attributes of field.
1395 public Vector getAttributes() {
1399 public byte[] findAnnotationData(boolean classRetention) {
1400 String n = classRetention
1401 ? "RuntimeInvisibleAnnotations" : // NOI18N
1402 "RuntimeVisibleAnnotations"; // NOI18N
1403 AttrData[] arr = new AttrData[attrs.size()];
1404 attrs.copyInto(arr);
1405 return ClassData.findAttr(n, arr);
1410 * A JavaScript optimized replacement for Hashtable.
1412 * @author Jaroslav Tulach <jtulach@netbeans.org>
1414 private static final class Hashtable {
1416 private Object[] keys;
1417 private Object[] values;
1423 Hashtable(int i, double d) {
1430 synchronized void put(Object key, Object val) {
1431 int[] where = {-1, -1};
1432 Object found = get(key, where);
1433 if (where[0] != -1) {
1435 values[where[0]] = val;
1437 if (where[1] != -1) {
1439 keys[where[1]] = key;
1440 values[where[1]] = val;
1443 keys = new Object[11];
1444 values = new Object[11];
1448 Object[] newKeys = new Object[keys.length * 2];
1449 Object[] newValues = new Object[values.length * 2];
1450 for (int i = 0; i < keys.length; i++) {
1451 newKeys[i] = keys[i];
1452 newValues[i] = values[i];
1454 newKeys[keys.length] = key;
1455 newValues[keys.length] = val;
1463 Object get(Object key) {
1464 return get(key, null);
1467 private synchronized Object get(Object key, int[] foundAndNull) {
1471 for (int i = 0; i < keys.length; i++) {
1472 if (keys[i] == null) {
1473 if (foundAndNull != null) {
1474 foundAndNull[1] = i;
1476 } else if (keys[i].equals(key)) {
1477 if (foundAndNull != null) {
1478 foundAndNull[0] = i;
1488 * Strores InnerClass data informastion.
1490 * @author Sucheta Dambalkar (Adopted code from jdis)
1492 private static class InnerClassData {
1495 int inner_class_info_index, outer_class_info_index, inner_name_index, access;
1497 public InnerClassData(ClassData cls) {
1503 * Read Innerclass attribute data.
1505 public void read(DataInputStream in) throws IOException {
1506 inner_class_info_index = in.readUnsignedShort();
1507 outer_class_info_index = in.readUnsignedShort();
1508 inner_name_index = in.readUnsignedShort();
1509 access = in.readUnsignedShort();
1513 * Returns the access of this class or interface.
1515 public String[] getAccess() {
1516 Vector v = new Vector();
1517 if ((access & ACC_PUBLIC) != 0) {
1518 v.addElement("public");
1520 if ((access & ACC_FINAL) != 0) {
1521 v.addElement("final");
1523 if ((access & ACC_ABSTRACT) != 0) {
1524 v.addElement("abstract");
1526 String[] accflags = new String[v.size()];
1527 v.copyInto(accflags);
1530 } // end InnerClassData
1533 * Strores LineNumberTable data information.
1535 * @author Sucheta Dambalkar (Adopted code from jdis)
1537 private static class LineNumData {
1539 short start_pc, line_number;
1541 public LineNumData() {
1545 * Read LineNumberTable attribute.
1547 public LineNumData(DataInputStream in) throws IOException {
1548 start_pc = in.readShort();
1549 line_number = in.readShort();
1555 * Strores LocalVariableTable data information.
1557 * @author Sucheta Dambalkar (Adopted code from jdis)
1559 private static class LocVarData {
1561 short start_pc, length, name_cpx, sig_cpx, slot;
1563 public LocVarData() {
1567 * Read LocalVariableTable attribute.
1569 public LocVarData(DataInputStream in) throws IOException {
1570 start_pc = in.readShort();
1571 length = in.readShort();
1572 name_cpx = in.readShort();
1573 sig_cpx = in.readShort();
1574 slot = in.readShort();
1579 * Strores method data informastion.
1581 * @author Sucheta Dambalkar (Adopted code from jdis)
1583 static class MethodData {
1588 int descriptor_index;
1589 int attributes_count;
1591 Vector exception_table = new Vector(0);
1592 Vector lin_num_tb = new Vector(0);
1593 Vector loc_var_tb = new Vector(0);
1594 StackMapTableData[] stackMapTable;
1595 StackMapData[] stackMap;
1596 int[] exc_index_table = null;
1597 Vector attrs = new Vector(0);
1598 Vector code_attrs = new Vector(0);
1599 int max_stack, max_locals;
1600 boolean isSynthetic = false;
1601 boolean isDeprecated = false;
1603 public MethodData(ClassData cls) {
1610 public void read(DataInputStream in) throws IOException {
1611 access = in.readUnsignedShort();
1612 name_index = in.readUnsignedShort();
1613 descriptor_index = in.readUnsignedShort();
1614 int attributes_count = in.readUnsignedShort();
1615 for (int i = 0; i < attributes_count; i++) {
1616 int attr_name_index = in.readUnsignedShort();
1620 if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
1621 String attr_name = cls.getString(attr_name_index);
1622 if (attr_name.equals("Code")) {
1624 AttrData attr = new AttrData(cls);
1625 attr.read(attr_name_index);
1626 attrs.addElement(attr);
1628 } else if (attr_name.equals("Exceptions")) {
1630 AttrData attr = new AttrData(cls);
1631 attr.read(attr_name_index);
1632 attrs.addElement(attr);
1634 } else if (attr_name.equals("Synthetic")) {
1635 if (in.readInt() != 0) {
1636 throw new ClassFormatError("invalid Synthetic attr length");
1639 AttrData attr = new AttrData(cls);
1640 attr.read(attr_name_index);
1641 attrs.addElement(attr);
1643 } else if (attr_name.equals("Deprecated")) {
1644 if (in.readInt() != 0) {
1645 throw new ClassFormatError("invalid Synthetic attr length");
1647 isDeprecated = true;
1648 AttrData attr = new AttrData(cls);
1649 attr.read(attr_name_index);
1650 attrs.addElement(attr);
1654 AttrData attr = new AttrData(cls);
1655 attr.read(attr_name_index, in);
1656 attrs.addElement(attr);
1662 * Read code attribute info.
1664 public void readCode(DataInputStream in) throws IOException {
1666 int attr_length = in.readInt();
1667 max_stack = in.readUnsignedShort();
1668 max_locals = in.readUnsignedShort();
1669 int codelen = in.readInt();
1671 code = new byte[codelen];
1673 while (totalread < codelen) {
1674 totalread += in.read(code, totalread, codelen - totalread);
1676 // in.read(code, 0, codelen);
1678 readExceptionTable(in);
1679 int code_attributes_count = in.readUnsignedShort();
1681 for (int k = 0; k < code_attributes_count; k++) {
1682 int table_name_index = in.readUnsignedShort();
1683 int table_name_tag = cls.getTag(table_name_index);
1684 AttrData attr = new AttrData(cls);
1685 if (table_name_tag == CONSTANT_UTF8) {
1686 String table_name_tstr = cls.getString(table_name_index);
1687 if (table_name_tstr.equals("LineNumberTable")) {
1688 readLineNumTable(in);
1689 attr.read(table_name_index);
1690 } else if (table_name_tstr.equals("LocalVariableTable")) {
1691 readLocVarTable(in);
1692 attr.read(table_name_index);
1693 } else if (table_name_tstr.equals("StackMapTable")) {
1694 readStackMapTable(in);
1695 attr.read(table_name_index);
1696 } else if (table_name_tstr.equals("StackMap")) {
1698 attr.read(table_name_index);
1700 attr.read(table_name_index, in);
1702 code_attrs.addElement(attr);
1706 attr.read(table_name_index, in);
1707 code_attrs.addElement(attr);
1712 * Read exception table info.
1714 void readExceptionTable(DataInputStream in) throws IOException {
1715 int exception_table_len = in.readUnsignedShort();
1716 exception_table = new Vector(exception_table_len);
1717 for (int l = 0; l < exception_table_len; l++) {
1718 exception_table.addElement(new TrapData(in, l));
1723 * Read LineNumberTable attribute info.
1725 void readLineNumTable(DataInputStream in) throws IOException {
1726 int attr_len = in.readInt(); // attr_length
1727 int lin_num_tb_len = in.readUnsignedShort();
1728 lin_num_tb = new Vector(lin_num_tb_len);
1729 for (int l = 0; l < lin_num_tb_len; l++) {
1730 lin_num_tb.addElement(new LineNumData(in));
1735 * Read LocalVariableTable attribute info.
1737 void readLocVarTable(DataInputStream in) throws IOException {
1738 int attr_len = in.readInt(); // attr_length
1739 int loc_var_tb_len = in.readUnsignedShort();
1740 loc_var_tb = new Vector(loc_var_tb_len);
1741 for (int l = 0; l < loc_var_tb_len; l++) {
1742 loc_var_tb.addElement(new LocVarData(in));
1747 * Read Exception attribute info.
1749 public void readExceptions(DataInputStream in) throws IOException {
1750 int attr_len = in.readInt(); // attr_length in prog
1751 int num_exceptions = in.readUnsignedShort();
1752 exc_index_table = new int[num_exceptions];
1753 for (int l = 0; l < num_exceptions; l++) {
1754 int exc = in.readShort();
1755 exc_index_table[l] = exc;
1760 * Read StackMapTable attribute info.
1762 void readStackMapTable(DataInputStream in) throws IOException {
1763 int attr_len = in.readInt(); //attr_length
1764 int stack_map_tb_len = in.readUnsignedShort();
1765 stackMapTable = new StackMapTableData[stack_map_tb_len];
1766 for (int i = 0; i < stack_map_tb_len; i++) {
1767 stackMapTable[i] = StackMapTableData.getInstance(in, this);
1772 * Read StackMap attribute info.
1774 void readStackMap(DataInputStream in) throws IOException {
1775 int attr_len = in.readInt(); //attr_length
1776 int stack_map_len = in.readUnsignedShort();
1777 stackMap = new StackMapData[stack_map_len];
1778 for (int i = 0; i < stack_map_len; i++) {
1779 stackMap[i] = new StackMapData(in, this);
1784 * Return access of the method.
1786 public int getAccess() {
1791 * Return name of the method.
1793 public String getName() {
1794 return cls.getStringValue(name_index);
1798 * Return internal siganature of the method.
1800 public String getInternalSig() {
1801 return cls.getStringValue(descriptor_index);
1805 * Return code attribute data of a method.
1807 public byte[] getCode() {
1812 * Return LineNumberTable size.
1814 public int getnumlines() {
1815 return lin_num_tb.size();
1819 * Return LineNumberTable
1821 public Vector getlin_num_tb() {
1826 * Return LocalVariableTable size.
1828 public int getloc_var_tbsize() {
1829 return loc_var_tb.size();
1833 * Return LocalVariableTable.
1835 public Vector getloc_var_tb() {
1842 public StackMapData[] getStackMap() {
1847 * Return StackMapTable.
1849 public StackMapTableData[] getStackMapTable() {
1850 return stackMapTable;
1853 public StackMapIterator createStackMapIterator() {
1854 return new StackMapIterator(this);
1858 * Return true if method is static
1860 public boolean isStatic() {
1861 if ((access & ACC_STATIC) != 0) {
1868 * Return max depth of operand stack.
1870 public int getMaxStack() {
1875 * Return number of local variables.
1877 public int getMaxLocals() {
1882 * Return exception index table in Exception attribute.
1884 public int[] get_exc_index_table() {
1885 return exc_index_table;
1889 * Return exception table in code attributre.
1891 public TrapDataIterator getTrapDataIterator() {
1892 return new TrapDataIterator(exception_table);
1896 * Return method attributes.
1898 public Vector getAttributes() {
1903 * Return code attributes.
1905 public Vector getCodeAttributes() {
1910 * Return true if method id synthetic.
1912 public boolean isSynthetic() {
1917 * Return true if method is deprecated.
1919 public boolean isDeprecated() {
1920 return isDeprecated;
1923 public byte[] findAnnotationData(boolean classRetention) {
1924 String n = classRetention
1925 ? "RuntimeInvisibleAnnotations" : // NOI18N
1926 "RuntimeVisibleAnnotations"; // NOI18N
1927 AttrData[] arr = new AttrData[attrs.size()];
1928 attrs.copyInto(arr);
1929 return ClassData.findAttr(n, arr);
1932 public boolean isConstructor() {
1933 return "<init>".equals(getName());
1937 /* represents one entry of StackMap attribute
1939 private static class StackMapData {
1945 StackMapData(int offset, int[] locals, int[] stack) {
1946 this.offset = offset;
1947 this.locals = locals;
1951 StackMapData(DataInputStream in, MethodData method) throws IOException {
1952 offset = in.readUnsignedShort();
1953 int local_size = in.readUnsignedShort();
1954 locals = readTypeArray(in, local_size, method);
1955 int stack_size = in.readUnsignedShort();
1956 stack = readTypeArray(in, stack_size, method);
1959 static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
1960 int[] types = new int[length];
1961 for (int i = 0; i < length; i++) {
1962 types[i] = readType(in, method);
1967 static final int readType(DataInputStream in, MethodData method) throws IOException {
1968 int type = in.readUnsignedByte();
1969 if (type == ITEM_Object || type == ITEM_NewObject) {
1970 type = type | (in.readUnsignedShort() << 8);
1976 static final class StackMapIterator {
1978 private final StackMapTableData[] stackMapTable;
1979 private final TypeArray argTypes;
1980 private final TypeArray localTypes;
1981 private final TypeArray stackTypes;
1982 private int nextFrameIndex;
1983 private int lastFrameByteCodeOffset;
1984 private int byteCodeOffset;
1986 StackMapIterator(final MethodData methodData) {
1987 this(methodData.getStackMapTable(),
1988 methodData.getInternalSig(),
1989 methodData.isStatic());
1992 StackMapIterator(final StackMapTableData[] stackMapTable,
1993 final String methodSignature,
1994 final boolean isStaticMethod) {
1995 this.stackMapTable = (stackMapTable != null)
1997 : new StackMapTableData[0];
1999 argTypes = getArgTypes(methodSignature, isStaticMethod);
2000 localTypes = new TypeArray();
2001 stackTypes = new TypeArray();
2003 localTypes.addAll(argTypes);
2005 lastFrameByteCodeOffset = -1;
2009 public boolean isEmpty() {
2010 return stackMapTable.length == 0;
2013 public String getFrameAsString() {
2014 return (nextFrameIndex == 0)
2015 ? StackMapTableData.toString("INITIAL", 0, null, null)
2016 : stackMapTable[nextFrameIndex - 1].toString();
2019 public int getFrameIndex() {
2020 return nextFrameIndex;
2023 public TypeArray getFrameStack() {
2027 public TypeArray getFrameLocals() {
2031 public TypeArray getArguments() {
2035 public void advanceBy(final int numByteCodes) {
2036 if (numByteCodes < 0) {
2037 throw new IllegalStateException("Forward only iterator");
2040 byteCodeOffset += numByteCodes;
2041 while ((nextFrameIndex < stackMapTable.length)
2042 && ((byteCodeOffset - lastFrameByteCodeOffset)
2043 >= (stackMapTable[nextFrameIndex].offsetDelta
2045 final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
2047 lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
2048 nextFrame.applyTo(localTypes, stackTypes);
2054 public void advanceTo(final int nextByteCodeOffset) {
2055 advanceBy(nextByteCodeOffset - byteCodeOffset);
2058 private static TypeArray getArgTypes(final String methodSignature,
2059 final boolean isStaticMethod) {
2060 final TypeArray argTypes = new TypeArray();
2062 if (!isStaticMethod) {
2063 argTypes.add(ITEM_Object);
2066 if (methodSignature.charAt(0) != '(') {
2067 throw new IllegalArgumentException("Invalid method signature");
2070 final int length = methodSignature.length();
2071 boolean skipType = false;
2073 for (int i = 1; i < length; ++i) {
2074 switch (methodSignature.charAt(i)) {
2080 argType = ITEM_Integer;
2083 argType = ITEM_Long;
2086 argType = ITEM_Float;
2089 argType = ITEM_Double;
2092 i = methodSignature.indexOf(';', i + 1);
2094 throw new IllegalArgumentException(
2095 "Invalid method signature");
2097 argType = ITEM_Object;
2101 // not interested in the return value type
2105 argTypes.add(ITEM_Object);
2111 throw new IllegalArgumentException(
2112 "Invalid method signature");
2116 argTypes.add(argType);
2125 /* represents one entry of StackMapTable attribute
2128 private static abstract class StackMapTableData {
2130 final int frameType;
2133 StackMapTableData(int frameType) {
2134 this.frameType = frameType;
2137 abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
2139 protected static String toString(
2140 final String frameType,
2142 final int[] localTypes,
2143 final int[] stackTypes) {
2144 final StringBuilder sb = new StringBuilder(frameType);
2146 sb.append("(off: +").append(offset);
2147 if (localTypes != null) {
2148 sb.append(", locals: ");
2149 appendTypes(sb, localTypes);
2151 if (stackTypes != null) {
2152 sb.append(", stack: ");
2153 appendTypes(sb, stackTypes);
2157 return sb.toString();
2160 private static void appendTypes(final StringBuilder sb, final int[] types) {
2162 if (types.length > 0) {
2163 sb.append(TypeArray.typeString(types[0]));
2164 for (int i = 1; i < types.length; ++i) {
2166 sb.append(TypeArray.typeString(types[i]));
2172 private static class SameFrame extends StackMapTableData {
2174 SameFrame(int frameType, int offsetDelta) {
2176 this.offsetDelta = offsetDelta;
2180 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2185 public String toString() {
2186 return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
2187 ? "_FRAME_EXTENDED" : ""),
2193 private static class SameLocals1StackItem extends StackMapTableData {
2197 SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
2199 this.offsetDelta = offsetDelta;
2204 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2205 stackTypes.setAll(stack);
2209 public String toString() {
2211 "SAME_LOCALS_1_STACK_ITEM"
2212 + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
2213 ? "_EXTENDED" : ""),
2219 private static class ChopFrame extends StackMapTableData {
2221 ChopFrame(int frameType, int offsetDelta) {
2223 this.offsetDelta = offsetDelta;
2227 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2228 localTypes.setSize(localTypes.getSize()
2229 - (SAME_FRAME_EXTENDED - frameType));
2234 public String toString() {
2235 return toString("CHOP", offsetDelta, null, null);
2239 private static class AppendFrame extends StackMapTableData {
2243 AppendFrame(int frameType, int offsetDelta, int[] locals) {
2245 this.offsetDelta = offsetDelta;
2246 this.locals = locals;
2250 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2251 localTypes.addAll(locals);
2256 public String toString() {
2257 return toString("APPEND", offsetDelta, locals, null);
2261 private static class FullFrame extends StackMapTableData {
2266 FullFrame(int offsetDelta, int[] locals, int[] stack) {
2268 this.offsetDelta = offsetDelta;
2269 this.locals = locals;
2274 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2275 localTypes.setAll(locals);
2276 stackTypes.setAll(stack);
2280 public String toString() {
2281 return toString("FULL", offsetDelta, locals, stack);
2285 static StackMapTableData getInstance(DataInputStream in, MethodData method)
2286 throws IOException {
2287 int frameType = in.readUnsignedByte();
2289 if (frameType < SAME_FRAME_BOUND) {
2291 return new SameFrame(frameType, frameType);
2292 } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
2293 // same_locals_1_stack_item_frame
2294 // read additional single stack element
2295 return new SameLocals1StackItem(frameType,
2296 (frameType - SAME_FRAME_BOUND),
2297 StackMapData.readTypeArray(in, 1, method));
2298 } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
2299 // same_locals_1_stack_item_extended
2300 return new SameLocals1StackItem(frameType,
2301 in.readUnsignedShort(),
2302 StackMapData.readTypeArray(in, 1, method));
2303 } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
2304 // chop_frame or same_frame_extended
2305 return new ChopFrame(frameType, in.readUnsignedShort());
2306 } else if (frameType == SAME_FRAME_EXTENDED) {
2307 // chop_frame or same_frame_extended
2308 return new SameFrame(frameType, in.readUnsignedShort());
2309 } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
2311 return new AppendFrame(frameType, in.readUnsignedShort(),
2312 StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
2313 } else if (frameType == FULL_FRAME) {
2315 int offsetDelta = in.readUnsignedShort();
2316 int locals_size = in.readUnsignedShort();
2317 int[] locals = StackMapData.readTypeArray(in, locals_size, method);
2318 int stack_size = in.readUnsignedShort();
2319 int[] stack = StackMapData.readTypeArray(in, stack_size, method);
2320 return new FullFrame(offsetDelta, locals, stack);
2322 throw new ClassFormatError("unrecognized frame_type in StackMapTable");
2328 * Stores exception table data in code attribute.
2330 * @author Sucheta Dambalkar (Adopted code from jdis)
2332 static final class TrapData {
2334 public final short start_pc;
2335 public final short end_pc;
2336 public final short handler_pc;
2337 public final short catch_cpx;
2341 * Read and store exception table data in code attribute.
2343 TrapData(DataInputStream in, int num) throws IOException {
2345 start_pc = in.readShort();
2346 end_pc = in.readShort();
2347 handler_pc = in.readShort();
2348 catch_cpx = in.readShort();
2352 * returns recommended identifier
2354 public String ident() {
2360 * @author Jaroslav Tulach <jtulach@netbeans.org>
2362 static final class TrapDataIterator {
2364 private final Hashtable exStart = new Hashtable();
2365 private final Hashtable exStop = new Hashtable();
2366 private TrapData[] current = new TrapData[10];
2367 private int currentCount;
2369 TrapDataIterator(Vector exceptionTable) {
2370 for (int i = 0; i < exceptionTable.size(); i++) {
2371 final TrapData td = (TrapData) exceptionTable.elementAt(i);
2372 put(exStart, td.start_pc, td);
2373 put(exStop, td.end_pc, td);
2377 private static void put(Hashtable h, short key, TrapData td) {
2378 Short s = Short.valueOf((short) key);
2379 Vector v = (Vector) h.get(s);
2387 private boolean processAll(Hashtable h, Short key, boolean add) {
2388 boolean change = false;
2389 Vector v = (Vector) h.get(key);
2392 for (int i = 0; i < s; i++) {
2393 TrapData td = (TrapData) v.elementAt(i);
2406 public boolean advanceTo(int i) {
2407 Short s = Short.valueOf((short) i);
2408 boolean ch1 = processAll(exStart, s, true);
2409 boolean ch2 = processAll(exStop, s, false);
2413 public boolean useTry() {
2414 return currentCount > 0;
2417 public TrapData[] current() {
2418 TrapData[] copy = new TrapData[currentCount];
2419 for (int i = 0; i < currentCount; i++) {
2420 copy[i] = current[i];
2425 private void add(TrapData e) {
2426 if (currentCount == current.length) {
2427 TrapData[] data = new TrapData[currentCount * 2];
2428 for (int i = 0; i < currentCount; i++) {
2429 data[i] = current[i];
2433 current[currentCount++] = e;
2436 private void remove(TrapData e) {
2437 if (currentCount == 0) {
2441 while (from < currentCount) {
2442 if (e == current[from++]) {
2446 while (from < currentCount) {
2447 current[from - 1] = current[from];
2448 current[from] = null;
2454 static final class TypeArray {
2456 private static final int CAPACITY_INCREMENT = 16;
2457 private int[] types;
2460 public TypeArray() {
2463 public TypeArray(final TypeArray initialTypes) {
2464 setAll(initialTypes);
2467 public void add(final int newType) {
2468 ensureCapacity(size + 1);
2469 types[size++] = newType;
2472 public void addAll(final TypeArray newTypes) {
2473 addAll(newTypes.types, 0, newTypes.size);
2476 public void addAll(final int[] newTypes) {
2477 addAll(newTypes, 0, newTypes.length);
2480 public void addAll(final int[] newTypes,
2484 ensureCapacity(size + count);
2485 arraycopy(newTypes, offset, types, size, count);
2490 public void set(final int index, final int newType) {
2491 types[index] = newType;
2494 public void setAll(final TypeArray newTypes) {
2495 setAll(newTypes.types, 0, newTypes.size);
2498 public void setAll(final int[] newTypes) {
2499 setAll(newTypes, 0, newTypes.length);
2502 public void setAll(final int[] newTypes,
2506 ensureCapacity(count);
2507 arraycopy(newTypes, offset, types, 0, count);
2514 public void setSize(final int newSize) {
2515 if (size != newSize) {
2516 ensureCapacity(newSize);
2518 for (int i = size; i < newSize; ++i) {
2525 public void clear() {
2529 public int getSize() {
2533 public int get(final int index) {
2534 return types[index];
2537 public static String typeString(final int type) {
2538 switch (type & 0xff) {
2551 case ITEM_InitObject: // UninitializedThis
2555 case ITEM_NewObject: // Uninitialized
2558 throw new IllegalArgumentException("Unknown type");
2563 public String toString() {
2564 final StringBuilder sb = new StringBuilder("[");
2566 sb.append(typeString(types[0]));
2567 for (int i = 1; i < size; ++i) {
2569 sb.append(typeString(types[i]));
2573 return sb.append(']').toString();
2576 private void ensureCapacity(final int minCapacity) {
2577 if ((minCapacity == 0)
2578 || (types != null) && (minCapacity <= types.length)) {
2582 final int newCapacity =
2583 ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
2584 * CAPACITY_INCREMENT;
2585 final int[] newTypes = new int[newCapacity];
2588 arraycopy(types, 0, newTypes, 0, size);
2594 // no System.arraycopy
2595 private void arraycopy(final int[] src, final int srcPos,
2596 final int[] dest, final int destPos,
2598 for (int i = 0; i < length; ++i) {
2599 dest[destPos + i] = src[srcPos + i];
2604 * A JavaScript ready replacement for java.util.Vector
2606 * @author Jaroslav Tulach <jtulach@netbeans.org>
2608 @JavaScriptPrototype(prototype = "new Array")
2609 private static final class Vector {
2611 private Object[] arr;
2619 void add(Object objectType) {
2620 addElement(objectType);
2623 @JavaScriptBody(args = {"obj"}, body =
2625 void addElement(Object obj) {
2626 final int s = size();
2628 setElementAt(obj, s);
2631 @JavaScriptBody(args = {}, body =
2632 "return this.length;")
2634 return arr == null ? 0 : arr.length;
2637 @JavaScriptBody(args = {"newArr"}, body =
2638 "for (var i = 0; i < this.length; i++) {\n"
2639 + " newArr[i] = this[i];\n"
2641 void copyInto(Object[] newArr) {
2645 int min = Math.min(newArr.length, arr.length);
2646 for (int i = 0; i < min; i++) {
2651 @JavaScriptBody(args = {"index"}, body =
2652 "return this[index];")
2653 Object elementAt(int index) {
2657 private void setSize(int len) {
2658 Object[] newArr = new Object[len];
2663 @JavaScriptBody(args = {"val", "index"}, body =
2664 "this[index] = val;")
2665 void setElementAt(Object val, int index) {