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;
61 public static final int CONSTANT_METHODHANDLE = 15;
62 public static final int CONSTANT_METHODTYPE = 16;
63 public static final int CONSTANT_INVOKEDYNAMIC = 18;
66 public static final int ACC_PUBLIC = 0x00000001;
67 public static final int ACC_PRIVATE = 0x00000002;
68 public static final int ACC_PROTECTED = 0x00000004;
69 public static final int ACC_STATIC = 0x00000008;
70 public static final int ACC_FINAL = 0x00000010;
71 public static final int ACC_SYNCHRONIZED = 0x00000020;
72 public static final int ACC_SUPER = 0x00000020;
73 public static final int ACC_VOLATILE = 0x00000040;
74 public static final int ACC_TRANSIENT = 0x00000080;
75 public static final int ACC_NATIVE = 0x00000100;
76 public static final int ACC_INTERFACE = 0x00000200;
77 public static final int ACC_ABSTRACT = 0x00000400;
78 public static final int ACC_STRICT = 0x00000800;
79 public static final int ACC_EXPLICIT = 0x00001000;
80 public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
81 private static final int ACC_ANNOTATION = 0x00020000;
83 /* Type codes for StackMap attribute */
84 public static final int ITEM_Bogus =0; // an unknown or uninitialized value
85 public static final int ITEM_Integer =1; // a 32-bit integer
86 public static final int ITEM_Float =2; // not used
87 public static final int ITEM_Double =3; // not used
88 public static final int ITEM_Long =4; // a 64-bit integer
89 public static final int ITEM_Null =5; // the type of null
90 public static final int ITEM_InitObject =6; // "this" in constructor
91 public static final int ITEM_Object =7; // followed by 2-byte index of class name
92 public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new"
94 /* Constants used in StackMapTable attribute */
95 public static final int SAME_FRAME_BOUND = 64;
96 public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128;
97 public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
98 public static final int SAME_FRAME_EXTENDED = 251;
99 public static final int FULL_FRAME = 255;
102 public static final int opc_dead = -2;
103 public static final int opc_label = -1;
104 public static final int opc_nop = 0;
105 public static final int opc_aconst_null = 1;
106 public static final int opc_iconst_m1 = 2;
107 public static final int opc_iconst_0 = 3;
108 public static final int opc_iconst_1 = 4;
109 public static final int opc_iconst_2 = 5;
110 public static final int opc_iconst_3 = 6;
111 public static final int opc_iconst_4 = 7;
112 public static final int opc_iconst_5 = 8;
113 public static final int opc_lconst_0 = 9;
114 public static final int opc_lconst_1 = 10;
115 public static final int opc_fconst_0 = 11;
116 public static final int opc_fconst_1 = 12;
117 public static final int opc_fconst_2 = 13;
118 public static final int opc_dconst_0 = 14;
119 public static final int opc_dconst_1 = 15;
120 public static final int opc_bipush = 16;
121 public static final int opc_sipush = 17;
122 public static final int opc_ldc = 18;
123 public static final int opc_ldc_w = 19;
124 public static final int opc_ldc2_w = 20;
125 public static final int opc_iload = 21;
126 public static final int opc_lload = 22;
127 public static final int opc_fload = 23;
128 public static final int opc_dload = 24;
129 public static final int opc_aload = 25;
130 public static final int opc_iload_0 = 26;
131 public static final int opc_iload_1 = 27;
132 public static final int opc_iload_2 = 28;
133 public static final int opc_iload_3 = 29;
134 public static final int opc_lload_0 = 30;
135 public static final int opc_lload_1 = 31;
136 public static final int opc_lload_2 = 32;
137 public static final int opc_lload_3 = 33;
138 public static final int opc_fload_0 = 34;
139 public static final int opc_fload_1 = 35;
140 public static final int opc_fload_2 = 36;
141 public static final int opc_fload_3 = 37;
142 public static final int opc_dload_0 = 38;
143 public static final int opc_dload_1 = 39;
144 public static final int opc_dload_2 = 40;
145 public static final int opc_dload_3 = 41;
146 public static final int opc_aload_0 = 42;
147 public static final int opc_aload_1 = 43;
148 public static final int opc_aload_2 = 44;
149 public static final int opc_aload_3 = 45;
150 public static final int opc_iaload = 46;
151 public static final int opc_laload = 47;
152 public static final int opc_faload = 48;
153 public static final int opc_daload = 49;
154 public static final int opc_aaload = 50;
155 public static final int opc_baload = 51;
156 public static final int opc_caload = 52;
157 public static final int opc_saload = 53;
158 public static final int opc_istore = 54;
159 public static final int opc_lstore = 55;
160 public static final int opc_fstore = 56;
161 public static final int opc_dstore = 57;
162 public static final int opc_astore = 58;
163 public static final int opc_istore_0 = 59;
164 public static final int opc_istore_1 = 60;
165 public static final int opc_istore_2 = 61;
166 public static final int opc_istore_3 = 62;
167 public static final int opc_lstore_0 = 63;
168 public static final int opc_lstore_1 = 64;
169 public static final int opc_lstore_2 = 65;
170 public static final int opc_lstore_3 = 66;
171 public static final int opc_fstore_0 = 67;
172 public static final int opc_fstore_1 = 68;
173 public static final int opc_fstore_2 = 69;
174 public static final int opc_fstore_3 = 70;
175 public static final int opc_dstore_0 = 71;
176 public static final int opc_dstore_1 = 72;
177 public static final int opc_dstore_2 = 73;
178 public static final int opc_dstore_3 = 74;
179 public static final int opc_astore_0 = 75;
180 public static final int opc_astore_1 = 76;
181 public static final int opc_astore_2 = 77;
182 public static final int opc_astore_3 = 78;
183 public static final int opc_iastore = 79;
184 public static final int opc_lastore = 80;
185 public static final int opc_fastore = 81;
186 public static final int opc_dastore = 82;
187 public static final int opc_aastore = 83;
188 public static final int opc_bastore = 84;
189 public static final int opc_castore = 85;
190 public static final int opc_sastore = 86;
191 public static final int opc_pop = 87;
192 public static final int opc_pop2 = 88;
193 public static final int opc_dup = 89;
194 public static final int opc_dup_x1 = 90;
195 public static final int opc_dup_x2 = 91;
196 public static final int opc_dup2 = 92;
197 public static final int opc_dup2_x1 = 93;
198 public static final int opc_dup2_x2 = 94;
199 public static final int opc_swap = 95;
200 public static final int opc_iadd = 96;
201 public static final int opc_ladd = 97;
202 public static final int opc_fadd = 98;
203 public static final int opc_dadd = 99;
204 public static final int opc_isub = 100;
205 public static final int opc_lsub = 101;
206 public static final int opc_fsub = 102;
207 public static final int opc_dsub = 103;
208 public static final int opc_imul = 104;
209 public static final int opc_lmul = 105;
210 public static final int opc_fmul = 106;
211 public static final int opc_dmul = 107;
212 public static final int opc_idiv = 108;
213 public static final int opc_ldiv = 109;
214 public static final int opc_fdiv = 110;
215 public static final int opc_ddiv = 111;
216 public static final int opc_irem = 112;
217 public static final int opc_lrem = 113;
218 public static final int opc_frem = 114;
219 public static final int opc_drem = 115;
220 public static final int opc_ineg = 116;
221 public static final int opc_lneg = 117;
222 public static final int opc_fneg = 118;
223 public static final int opc_dneg = 119;
224 public static final int opc_ishl = 120;
225 public static final int opc_lshl = 121;
226 public static final int opc_ishr = 122;
227 public static final int opc_lshr = 123;
228 public static final int opc_iushr = 124;
229 public static final int opc_lushr = 125;
230 public static final int opc_iand = 126;
231 public static final int opc_land = 127;
232 public static final int opc_ior = 128;
233 public static final int opc_lor = 129;
234 public static final int opc_ixor = 130;
235 public static final int opc_lxor = 131;
236 public static final int opc_iinc = 132;
237 public static final int opc_i2l = 133;
238 public static final int opc_i2f = 134;
239 public static final int opc_i2d = 135;
240 public static final int opc_l2i = 136;
241 public static final int opc_l2f = 137;
242 public static final int opc_l2d = 138;
243 public static final int opc_f2i = 139;
244 public static final int opc_f2l = 140;
245 public static final int opc_f2d = 141;
246 public static final int opc_d2i = 142;
247 public static final int opc_d2l = 143;
248 public static final int opc_d2f = 144;
249 public static final int opc_i2b = 145;
250 public static final int opc_int2byte = 145;
251 public static final int opc_i2c = 146;
252 public static final int opc_int2char = 146;
253 public static final int opc_i2s = 147;
254 public static final int opc_int2short = 147;
255 public static final int opc_lcmp = 148;
256 public static final int opc_fcmpl = 149;
257 public static final int opc_fcmpg = 150;
258 public static final int opc_dcmpl = 151;
259 public static final int opc_dcmpg = 152;
260 public static final int opc_ifeq = 153;
261 public static final int opc_ifne = 154;
262 public static final int opc_iflt = 155;
263 public static final int opc_ifge = 156;
264 public static final int opc_ifgt = 157;
265 public static final int opc_ifle = 158;
266 public static final int opc_if_icmpeq = 159;
267 public static final int opc_if_icmpne = 160;
268 public static final int opc_if_icmplt = 161;
269 public static final int opc_if_icmpge = 162;
270 public static final int opc_if_icmpgt = 163;
271 public static final int opc_if_icmple = 164;
272 public static final int opc_if_acmpeq = 165;
273 public static final int opc_if_acmpne = 166;
274 public static final int opc_goto = 167;
275 public static final int opc_jsr = 168;
276 public static final int opc_ret = 169;
277 public static final int opc_tableswitch = 170;
278 public static final int opc_lookupswitch = 171;
279 public static final int opc_ireturn = 172;
280 public static final int opc_lreturn = 173;
281 public static final int opc_freturn = 174;
282 public static final int opc_dreturn = 175;
283 public static final int opc_areturn = 176;
284 public static final int opc_return = 177;
285 public static final int opc_getstatic = 178;
286 public static final int opc_putstatic = 179;
287 public static final int opc_getfield = 180;
288 public static final int opc_putfield = 181;
289 public static final int opc_invokevirtual = 182;
290 public static final int opc_invokenonvirtual = 183;
291 public static final int opc_invokespecial = 183;
292 public static final int opc_invokestatic = 184;
293 public static final int opc_invokeinterface = 185;
294 public static final int opc_invokedynamic = 186;
295 public static final int opc_new = 187;
296 public static final int opc_newarray = 188;
297 public static final int opc_anewarray = 189;
298 public static final int opc_arraylength = 190;
299 public static final int opc_athrow = 191;
300 public static final int opc_checkcast = 192;
301 public static final int opc_instanceof = 193;
302 public static final int opc_monitorenter = 194;
303 public static final int opc_monitorexit = 195;
304 public static final int opc_wide = 196;
305 public static final int opc_multianewarray = 197;
306 public static final int opc_ifnull = 198;
307 public static final int opc_ifnonnull = 199;
308 public static final int opc_goto_w = 200;
309 public static final int opc_jsr_w = 201;
310 /* Pseudo-instructions */
311 public static final int opc_bytecode = 203;
312 public static final int opc_try = 204;
313 public static final int opc_endtry = 205;
314 public static final int opc_catch = 206;
315 public static final int opc_var = 207;
316 public static final int opc_endvar = 208;
317 public static final int opc_localsmap = 209;
318 public static final int opc_stackmap = 210;
319 /* PicoJava prefixes */
320 public static final int opc_nonpriv = 254;
321 public static final int opc_priv = 255;
323 /* Wide instructions *
324 public static final int opc_iload_w = (opc_wide<<8)|opc_iload;
325 public static final int opc_lload_w = (opc_wide<<8)|opc_lload;
326 public static final int opc_fload_w = (opc_wide<<8)|opc_fload;
327 public static final int opc_dload_w = (opc_wide<<8)|opc_dload;
328 public static final int opc_aload_w = (opc_wide<<8)|opc_aload;
329 public static final int opc_istore_w = (opc_wide<<8)|opc_istore;
330 public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore;
331 public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore;
332 public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore;
333 public static final int opc_astore_w = (opc_wide<<8)|opc_astore;
334 public static final int opc_ret_w = (opc_wide<<8)|opc_ret;
335 public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc;
337 static class AnnotationParser {
339 private final boolean textual;
340 private final boolean iterateArray;
342 protected AnnotationParser(boolean textual, boolean iterateArray) {
343 this.textual = textual;
344 this.iterateArray = iterateArray;
347 protected void visitAnnotationStart(String type, boolean top) throws IOException {
350 protected void visitAnnotationEnd(String type, boolean top) throws IOException {
353 protected void visitValueStart(String attrName, char type) throws IOException {
356 protected void visitValueEnd(String attrName, char type) throws IOException {
359 protected void visitAttr(
360 String annoType, String attr, String attrType, String value
361 ) throws IOException {
364 protected void visitEnumAttr(
365 String annoType, String attr, String attrType, String value
366 ) throws IOException {
367 visitAttr(annoType, attr, attrType, value);
370 protected void visitClassAttr(
371 String annoType, String attr, String className
372 ) throws IOException {
373 visitAttr(annoType, attr, className, className);
377 * Initialize the parsing with constant pool from
380 * @param attr the attribute defining annotations
381 * @param cd constant pool
382 * @throws IOException in case I/O fails
384 public final void parse(byte[] attr, ClassData cd) throws IOException {
385 ByteArrayInputStream is = new ByteArrayInputStream(attr);
386 DataInputStream dis = new DataInputStream(is);
394 private void read(DataInputStream dis, ClassData cd) throws IOException {
395 int cnt = dis.readUnsignedShort();
396 for (int i = 0; i < cnt; i++) {
397 readAnno(dis, cd, true);
401 private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
402 int type = dis.readUnsignedShort();
403 String typeName = cd.StringValue(type);
404 visitAnnotationStart(typeName, top);
405 int cnt = dis.readUnsignedShort();
406 for (int i = 0; i < cnt; i++) {
407 String attrName = cd.StringValue(dis.readUnsignedShort());
408 readValue(dis, cd, typeName, attrName);
410 visitAnnotationEnd(typeName, top);
412 visitAttr(typeName, null, null, null);
416 public void parseDefault(byte[] defaultAttribute, ClassData cd) throws IOException {
417 ByteArrayInputStream is = new ByteArrayInputStream(defaultAttribute);
418 DataInputStream dis = new DataInputStream(is);
420 readValue(dis, cd, null, null);
426 private void readValue(
427 DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
428 char type = (char) dis.readByte();
429 visitValueStart(attrName, type);
431 readAnno(dis, cd, false);
432 } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
433 int primitive = dis.readUnsignedShort();
434 String val = cd.stringValue(primitive, textual);
437 attrType = "Ljava_lang_String_2";
439 val = '"' + val + '"';
442 attrType = "" + type;
444 visitAttr(typeName, attrName, attrType, val);
445 } else if (type == 'c') {
446 int cls = dis.readUnsignedShort();
447 String attrType = cd.stringValue(cls, textual);
448 visitClassAttr(typeName, attrName, attrType);
449 } else if (type == '[') {
450 int cnt = dis.readUnsignedShort();
451 for (int i = 0; i < cnt; i++) {
452 readValue(dis, cd, typeName, iterateArray ? attrName : null);
454 } else if (type == 'e') {
455 int enumT = dis.readUnsignedShort();
456 String attrType = cd.stringValue(enumT, textual);
457 int enumN = dis.readUnsignedShort();
458 String val = cd.stringValue(enumN, textual);
459 visitEnumAttr(typeName, attrName, attrType, val);
461 throw new IOException("Unknown type " + type);
463 visitValueEnd(attrName, type);
468 * Reads and stores attribute information.
470 * @author Sucheta Dambalkar (Adopted code from jdis)
472 private static class AttrData {
479 public AttrData(ClassData cls) {
484 * Reads unknown attribute.
486 public void read(int name_cpx, DataInputStream in) throws IOException {
487 this.name_cpx = name_cpx;
488 datalen = in.readInt();
489 data = new byte[datalen];
494 * Reads just the name of known attribute.
496 public void read(int name_cpx) {
497 this.name_cpx = name_cpx;
501 * Returns attribute name.
503 public String getAttrName() {
504 return cls.getString(name_cpx);
508 * Returns attribute data.
510 public byte[] getData() {
516 * Stores constant pool entry information with one field.
518 * @author Sucheta Dambalkar (Adopted code from jdis)
520 private static class CPX {
530 * Stores constant pool entry information with two fields.
532 * @author Sucheta Dambalkar (Adopted code from jdis)
536 final int cpx1, cpx2;
538 CPX2(int cpx1, int cpx2) {
545 * Central data repository of the Java Disassembler. Stores all the
546 * information in java class file.
548 * @author Sucheta Dambalkar (Adopted code from jdis)
550 static final class ClassData {
553 private int minor_version;
554 private int major_version;
555 private int cpool_count;
556 private Object cpool[];
558 private int this_class = 0;
559 private int super_class;
560 private int interfaces_count;
561 private int[] interfaces = new int[0];
562 private FieldData[] fields;
563 private MethodData[] methods;
564 private InnerClassData[] innerClasses;
565 private BootMethodData[] bootMethods;
566 private int attributes_count;
567 private AttrData[] attrs;
568 private int source_cpx = 0;
570 private Hashtable indexHashAscii = new Hashtable();
571 private String pkgPrefix = "";
572 private int pkgPrefixLen = 0;
573 private boolean hasEnclosingMethod;
576 * Read classfile to disassemble.
578 public ClassData(InputStream infile) throws IOException {
579 this.read(new DataInputStream(infile));
583 * Reads and stores class file information.
585 public void read(DataInputStream in) throws IOException {
587 magic = in.readInt();
588 if (magic != JAVA_MAGIC) {
589 throw new ClassFormatError("wrong magic: "
590 + toHex(magic) + ", expected "
591 + toHex(JAVA_MAGIC));
593 minor_version = in.readShort();
594 major_version = in.readShort();
595 if (major_version != JAVA_VERSION) {
598 // Read the constant pool
600 access = in.readUnsignedShort();
601 this_class = in.readUnsignedShort();
602 super_class = in.readUnsignedShort();
605 interfaces_count = in.readUnsignedShort();
606 if (interfaces_count > 0) {
607 interfaces = new int[interfaces_count];
609 for (int i = 0; i < interfaces_count; i++) {
610 interfaces[i] = in.readShort();
619 // Read the attributes
620 attributes_count = in.readUnsignedShort();
621 attrs = new AttrData[attributes_count];
622 for (int k = 0; k < attributes_count; k++) {
623 int name_cpx = in.readUnsignedShort();
624 if (getTag(name_cpx) == CONSTANT_UTF8) {
625 final String attrName = getString(name_cpx);
626 if (attrName.equals("SourceFile")) {
627 if (in.readInt() != 2) {
628 throw new ClassFormatError("invalid attr length");
630 source_cpx = in.readUnsignedShort();
631 AttrData attr = new AttrData(this);
635 } else if (attrName.equals("InnerClasses")) {
636 int length = in.readInt();
637 int num = in.readUnsignedShort();
638 if (2 + num * 8 != length) {
639 throw new ClassFormatError("invalid attr length");
641 innerClasses = new InnerClassData[num];
642 for (int j = 0; j < num; j++) {
643 InnerClassData innerClass = new InnerClassData(this);
645 innerClasses[j] = innerClass;
647 AttrData attr = new AttrData(this);
650 } else if (attrName.equals("BootstrapMethods")) {
651 AttrData attr = new AttrData(this);
652 bootMethods = readBootstrapMethods(in);
656 if (attrName.equals("EnclosingMethod")) {
657 hasEnclosingMethod = true;
659 AttrData attr = new AttrData(this);
660 attr.read(name_cpx, in);
666 } // end ClassData.read()
668 BootMethodData[] readBootstrapMethods(DataInputStream in) throws IOException {
669 int attr_len = in.readInt(); //attr_lengt
670 int number = in.readShort();
671 BootMethodData[] arr = new BootMethodData[number];
672 for (int i = 0; i < number; i++) {
673 int ref = in.readShort();
674 int len = in.readShort();
675 int[] args = new int[len];
676 for (int j = 0; j < len; j++) {
677 args[j] = in.readShort();
679 arr[i] = new BootMethodData(this, ref, args);
685 * Reads and stores constant pool info.
687 void readCP(DataInputStream in) throws IOException {
688 cpool_count = in.readUnsignedShort();
689 tags = new byte[cpool_count];
690 cpool = new Object[cpool_count];
691 for (int i = 1; i < cpool_count; i++) {
692 byte tag = in.readByte();
694 switch (tags[i] = tag) {
696 String str = in.readUTF();
697 indexHashAscii.put(cpool[i] = str, new Integer(i));
699 case CONSTANT_INTEGER:
700 cpool[i] = new Integer(in.readInt());
703 cpool[i] = new Float(in.readFloat());
706 cpool[i++] = new Long(in.readLong());
708 case CONSTANT_DOUBLE:
709 cpool[i++] = new Double(in.readDouble());
712 case CONSTANT_STRING:
713 cpool[i] = new CPX(in.readUnsignedShort());
717 case CONSTANT_METHOD:
718 case CONSTANT_INTERFACEMETHOD:
719 case CONSTANT_NAMEANDTYPE:
720 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
722 case CONSTANT_METHODHANDLE:
723 cpool[i] = new CPX2(in.readByte(), in.readUnsignedShort());
725 case CONSTANT_METHODTYPE:
726 cpool[i] = new CPX(in.readUnsignedShort());
728 case CONSTANT_INVOKEDYNAMIC:
729 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
733 throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
739 * Reads and strores field info.
741 protected void readFields(DataInputStream in) throws IOException {
742 int fields_count = in.readUnsignedShort();
743 fields = new FieldData[fields_count];
744 for (int k = 0; k < fields_count; k++) {
745 FieldData field = new FieldData(this);
752 * Reads and strores Method info.
754 protected void readMethods(DataInputStream in) throws IOException {
755 int methods_count = in.readUnsignedShort();
756 methods = new MethodData[methods_count];
757 for (int k = 0; k < methods_count; k++) {
758 MethodData method = new MethodData(this);
767 public String getString(int n) {
771 return (String) cpool[n];
776 * get the type of constant given an index
778 public byte getTag(int n) {
781 } catch (ArrayIndexOutOfBoundsException e) {
785 static final String hexString = "0123456789ABCDEF";
786 public static char hexTable[] = hexString.toCharArray();
788 static String toHex(long val, int width) {
789 StringBuffer s = new StringBuffer();
790 for (int i = width - 1; i >= 0; i--) {
791 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
793 return "0x" + s.toString();
796 static String toHex(long val) {
798 for (width = 16; width > 0; width--) {
799 if ((val >> (width - 1) * 4) != 0) {
803 return toHex(val, width);
806 static String toHex(int val) {
808 for (width = 8; width > 0; width--) {
809 if ((val >> (width - 1) * 4) != 0) {
813 return toHex(val, width);
817 * Returns the name of this class.
819 public String getClassName() {
821 if (this_class == 0) {
826 if (tags[this_class] != CONSTANT_CLASS) {
827 return res; //"<CP["+cpx+"] is not a Class> ";
829 tcpx = ((CPX) cpool[this_class]).cpx;
830 } catch (ArrayIndexOutOfBoundsException e) {
831 return res; // "#"+cpx+"// invalid constant pool index";
832 } catch (Throwable e) {
833 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
837 return (String) (cpool[tcpx]);
838 } catch (ArrayIndexOutOfBoundsException e) {
839 return res; // "class #"+scpx+"// invalid constant pool index";
840 } catch (ClassCastException e) {
841 return res; // "class #"+scpx+"// invalid constant pool reference";
842 } catch (Throwable e) {
843 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
849 * Returns the name of class at perticular index.
851 public String getClassName(int cpx) {
852 String res = "#" + cpx;
858 if (tags[cpx] != CONSTANT_CLASS) {
859 return res; //"<CP["+cpx+"] is not a Class> ";
861 scpx = ((CPX) cpool[cpx]).cpx;
862 } catch (ArrayIndexOutOfBoundsException e) {
863 return res; // "#"+cpx+"// invalid constant pool index";
864 } catch (Throwable e) {
865 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
869 return (String) (cpool[scpx]);
870 } catch (ArrayIndexOutOfBoundsException e) {
871 return res; // "class #"+scpx+"// invalid constant pool index";
872 } catch (ClassCastException e) {
873 return res; // "class #"+scpx+"// invalid constant pool reference";
874 } catch (Throwable e) {
875 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
879 public int getAccessFlags() {
883 public boolean hasEnclosingMethod() {
884 return hasEnclosingMethod;
888 * Returns true if it is a class
890 public boolean isClass() {
891 if ((access & ACC_INTERFACE) == 0) {
898 * Returns true if it is a interface.
900 public boolean isInterface() {
901 if ((access & ACC_INTERFACE) != 0) {
907 public boolean isAnnotation() {
908 return (access & ACC_ANNOTATION) != 0;
912 * Returns true if this member is public, false otherwise.
914 public boolean isPublic() {
915 return (access & ACC_PUBLIC) != 0;
919 * Returns the access of this class or interface.
921 public String[] getAccess() {
922 Vector v = new Vector();
923 if ((access & ACC_PUBLIC) != 0) {
924 v.addElement("public");
926 if ((access & ACC_FINAL) != 0) {
927 v.addElement("final");
929 if ((access & ACC_ABSTRACT) != 0) {
930 v.addElement("abstract");
932 String[] accflags = new String[v.size()];
933 v.copyInto(accflags);
938 * Returns list of innerclasses.
940 public InnerClassData[] getInnerClasses() {
945 * Returns list of attributes.
947 final AttrData[] getAttributes() {
951 public byte[] findAnnotationData(boolean classRetention) {
952 String n = classRetention
953 ? "RuntimeInvisibleAnnotations" : // NOI18N
954 "RuntimeVisibleAnnotations"; // NOI18N
955 return findAttr(n, attrs);
959 * Returns true if superbit is set.
961 public boolean isSuperSet() {
962 if ((access & ACC_SUPER) != 0) {
969 * Returns super class name.
971 public String getSuperClassName() {
973 if (super_class == 0) {
978 if (tags[super_class] != CONSTANT_CLASS) {
979 return res; //"<CP["+cpx+"] is not a Class> ";
981 scpx = ((CPX) cpool[super_class]).cpx;
982 } catch (ArrayIndexOutOfBoundsException e) {
983 return res; // "#"+cpx+"// invalid constant pool index";
984 } catch (Throwable e) {
985 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
989 return (String) (cpool[scpx]);
990 } catch (ArrayIndexOutOfBoundsException e) {
991 return res; // "class #"+scpx+"// invalid constant pool index";
992 } catch (ClassCastException e) {
993 return res; // "class #"+scpx+"// invalid constant pool reference";
994 } catch (Throwable e) {
995 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
1000 * Returns list of super interfaces.
1002 public String[] getSuperInterfaces() {
1003 String interfacenames[] = new String[interfaces.length];
1004 int interfacecpx = -1;
1005 for (int i = 0; i < interfaces.length; i++) {
1006 interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
1007 interfacenames[i] = (String) (cpool[interfacecpx]);
1009 return interfacenames;
1013 * Returns string at prticular constant pool index.
1015 public String getStringValue(int cpoolx) {
1017 return ((String) cpool[cpoolx]);
1018 } catch (ArrayIndexOutOfBoundsException e) {
1019 return "//invalid constant pool index:" + cpoolx;
1020 } catch (ClassCastException e) {
1021 return "//invalid constant pool ref:" + cpoolx;
1026 * Returns list of field info.
1028 public FieldData[] getFields() {
1033 * Returns list of method info.
1035 public MethodData[] getMethods() {
1040 * Returns constant pool entry at that index.
1042 public CPX2 getCpoolEntry(int cpx) {
1043 return ((CPX2) (cpool[cpx]));
1046 public Object getCpoolEntryobj(int cpx) {
1047 return (cpool[cpx]);
1051 * Returns index of this class.
1053 public int getthis_cpx() {
1058 * Returns string at that index.
1060 public String StringValue(int cpx) {
1061 return stringValue(cpx, false);
1064 public String stringValue(int cpx, boolean textual) {
1065 return stringValue(cpx, textual, null);
1068 public String stringValue(int cpx, String[] classRefs) {
1069 return stringValue(cpx, true, classRefs);
1072 private String stringValue(int cpx, boolean textual, String[] refs) {
1082 } catch (IndexOutOfBoundsException e) {
1083 return "<Incorrect CP index:" + cpx + ">";
1090 case CONSTANT_UTF8: {
1094 StringBuilder sb = new StringBuilder();
1095 String s = (String) x;
1096 for (int k = 0; k < s.length(); k++) {
1097 char c = s.charAt(k);
1100 sb.append('\\').append('\\');
1103 sb.append('\\').append('t');
1106 sb.append('\\').append('n');
1109 sb.append('\\').append('r');
1112 sb.append('\\').append('\"');
1115 sb.append("\\u2028");
1118 sb.append("\\u2029");
1124 return sb.toString();
1126 case CONSTANT_DOUBLE: {
1127 Double d = (Double) x;
1128 String sd = d.toString();
1134 case CONSTANT_FLOAT: {
1135 Float f = (Float) x;
1136 String sf = (f).toString();
1142 case CONSTANT_LONG: {
1145 return ln.toString();
1147 return ln.toString() + 'l';
1149 case CONSTANT_INTEGER: {
1150 Integer in = (Integer) x;
1151 return in.toString();
1153 case CONSTANT_CLASS:
1154 String jn = getClassName(cpx);
1161 return javaName(jn);
1162 case CONSTANT_STRING:
1163 String sv = stringValue(((CPX) x).cpx, textual);
1165 return '"' + sv + '"';
1169 case CONSTANT_FIELD:
1170 case CONSTANT_METHOD:
1171 case CONSTANT_INTERFACEMETHOD:
1172 //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
1173 return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
1175 case CONSTANT_NAMEANDTYPE:
1176 return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
1177 case CONSTANT_METHODHANDLE:
1178 return "K" + ((CPX2)x).cpx1 + "@" + stringValue(((CPX2)x).cpx2, textual);
1179 case CONSTANT_METHODTYPE:
1180 return stringValue(((CPX)x).cpx, true);
1182 return "UnknownTag" + tag; //TBD
1187 * Returns resolved java type name.
1189 public String javaName(String name) {
1193 int len = name.length();
1201 for (int k = 0; k < len; k += Character.charCount(cp)) {
1202 cp = name.codePointAt(k);
1204 if (!isJavaIdentifierStart(cp)) {
1207 } else if (cp != '/') {
1208 if (!isJavaIdentifierPart(cp)) {
1216 return "\"" + name + "\"";
1219 public String getName(int cpx) {
1222 return javaName((String) cpool[cpx]); //.replace('/','.');
1223 } catch (ArrayIndexOutOfBoundsException e) {
1224 return "<invalid constant pool index:" + cpx + ">";
1225 } catch (ClassCastException e) {
1226 return "<invalid constant pool ref:" + cpx + ">";
1231 * Returns unqualified class name.
1233 public String getShortClassName(int cpx) {
1234 String classname = javaName(getClassName(cpx));
1235 pkgPrefixLen = classname.lastIndexOf("/") + 1;
1236 if (pkgPrefixLen != 0) {
1237 pkgPrefix = classname.substring(0, pkgPrefixLen);
1238 if (classname.startsWith(pkgPrefix)) {
1239 return classname.substring(pkgPrefixLen);
1246 * Returns source file name.
1248 public String getSourceName() {
1249 return getName(source_cpx);
1253 * Returns package name.
1255 public String getPkgName() {
1256 String classname = getClassName(this_class);
1257 pkgPrefixLen = classname.lastIndexOf("/") + 1;
1258 if (pkgPrefixLen != 0) {
1259 pkgPrefix = classname.substring(0, pkgPrefixLen);
1260 return /* ("package " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */;
1266 public BootMethodData getBootMethod(int indx) {
1267 return bootMethods != null ? bootMethods[indx] : null;
1271 * Returns total constant pool entry count.
1273 public int getCpoolCount() {
1278 * Returns minor version of class file.
1280 public int getMinor_version() {
1281 return minor_version;
1285 * Returns major version of class file.
1287 public int getMajor_version() {
1288 return major_version;
1291 private boolean isJavaIdentifierStart(int cp) {
1292 return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
1295 private boolean isJavaIdentifierPart(int cp) {
1296 return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
1299 public String[] getNameAndType(int indx) {
1300 return getNameAndType(indx, 0, new String[2]);
1303 private String[] getNameAndType(int indx, int at, String[] arr) {
1304 CPX2 c2 = getCpoolEntry(indx);
1305 arr[at] = StringValue(c2.cpx1);
1306 arr[at + 1] = StringValue(c2.cpx2);
1310 public String[] getFieldInfoName(int indx) {
1311 CPX2 c2 = getCpoolEntry(indx);
1312 String[] arr = new String[3];
1313 arr[0] = getClassName(c2.cpx1);
1314 return getNameAndType(c2.cpx2, 1, arr);
1317 public MethodData findMethod(String name, String signature) {
1318 for (MethodData md: methods) {
1319 if (md.getName().equals(name)
1320 && md.getInternalSig().equals(signature)) {
1329 public FieldData findField(String name, String signature) {
1330 for (FieldData fd: fields) {
1331 if (fd.getName().equals(name)
1332 && fd.getInternalSig().equals(signature)) {
1341 static byte[] findAttr(String n, AttrData[] attrs) {
1342 for (AttrData ad : attrs) {
1343 if (n.equals(ad.getAttrName())) {
1344 return ad.getData();
1352 * Strores field data informastion.
1354 * @author Sucheta Dambalkar (Adopted code from jdis)
1356 static class FieldData {
1361 int descriptor_index;
1362 int attributes_count;
1364 boolean isSynthetic = false;
1365 boolean isDeprecated = false;
1368 public FieldData(ClassData cls) {
1373 * Read and store field info.
1375 public void read(DataInputStream in) throws IOException {
1376 access = in.readUnsignedShort();
1377 name_index = in.readUnsignedShort();
1378 descriptor_index = in.readUnsignedShort();
1379 // Read the attributes
1380 int attributes_count = in.readUnsignedShort();
1381 attrs = new Vector(attributes_count);
1382 for (int i = 0; i < attributes_count; i++) {
1383 int attr_name_index = in.readUnsignedShort();
1384 if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
1387 String attr_name = cls.getString(attr_name_index);
1388 if (attr_name.equals("ConstantValue")) {
1389 if (in.readInt() != 2) {
1390 throw new ClassFormatError("invalid ConstantValue attr length");
1392 value_cpx = in.readUnsignedShort();
1393 AttrData attr = new AttrData(cls);
1394 attr.read(attr_name_index);
1395 attrs.addElement(attr);
1396 } else if (attr_name.equals("Synthetic")) {
1397 if (in.readInt() != 0) {
1398 throw new ClassFormatError("invalid Synthetic attr length");
1401 AttrData attr = new AttrData(cls);
1402 attr.read(attr_name_index);
1403 attrs.addElement(attr);
1404 } else if (attr_name.equals("Deprecated")) {
1405 if (in.readInt() != 0) {
1406 throw new ClassFormatError("invalid Synthetic attr length");
1408 isDeprecated = true;
1409 AttrData attr = new AttrData(cls);
1410 attr.read(attr_name_index);
1411 attrs.addElement(attr);
1413 AttrData attr = new AttrData(cls);
1414 attr.read(attr_name_index, in);
1415 attrs.addElement(attr);
1421 public boolean isStatic() {
1422 return (access & ACC_STATIC) != 0;
1426 * Returns access of a field.
1428 public String[] getAccess() {
1429 Vector v = new Vector();
1430 if ((access & ACC_PUBLIC) != 0) {
1431 v.addElement("public");
1433 if ((access & ACC_PRIVATE) != 0) {
1434 v.addElement("private");
1436 if ((access & ACC_PROTECTED) != 0) {
1437 v.addElement("protected");
1439 if ((access & ACC_STATIC) != 0) {
1440 v.addElement("static");
1442 if ((access & ACC_FINAL) != 0) {
1443 v.addElement("final");
1445 if ((access & ACC_VOLATILE) != 0) {
1446 v.addElement("volatile");
1448 if ((access & ACC_TRANSIENT) != 0) {
1449 v.addElement("transient");
1451 String[] accflags = new String[v.size()];
1452 v.copyInto(accflags);
1457 * Returns name of a field.
1459 public String getName() {
1460 return cls.getStringValue(name_index);
1464 * Returns internal signature of a field
1466 public String getInternalSig() {
1467 return cls.getStringValue(descriptor_index);
1471 * Returns true if field is synthetic.
1473 public boolean isSynthetic() {
1478 * Returns true if field is deprecated.
1480 public boolean isDeprecated() {
1481 return isDeprecated;
1484 public boolean hasConstantValue() {
1485 return value_cpx != -1;
1489 * Returns list of attributes of field.
1491 public Vector getAttributes() {
1495 public byte[] findAnnotationData(boolean classRetention) {
1496 String n = classRetention
1497 ? "RuntimeInvisibleAnnotations" : // NOI18N
1498 "RuntimeVisibleAnnotations"; // NOI18N
1499 AttrData[] arr = new AttrData[attrs.size()];
1500 attrs.copyInto(arr);
1501 return ClassData.findAttr(n, arr);
1506 * A JavaScript optimized replacement for Hashtable.
1508 * @author Jaroslav Tulach <jtulach@netbeans.org>
1510 private static final class Hashtable {
1512 private Object[] keys;
1513 private Object[] values;
1519 Hashtable(int i, double d) {
1526 synchronized void put(Object key, Object val) {
1527 int[] where = {-1, -1};
1528 Object found = get(key, where);
1529 if (where[0] != -1) {
1531 values[where[0]] = val;
1533 if (where[1] != -1) {
1535 keys[where[1]] = key;
1536 values[where[1]] = val;
1539 keys = new Object[11];
1540 values = new Object[11];
1544 Object[] newKeys = new Object[keys.length * 2];
1545 Object[] newValues = new Object[values.length * 2];
1546 for (int i = 0; i < keys.length; i++) {
1547 newKeys[i] = keys[i];
1548 newValues[i] = values[i];
1550 newKeys[keys.length] = key;
1551 newValues[keys.length] = val;
1559 Object get(Object key) {
1560 return get(key, null);
1563 private synchronized Object get(Object key, int[] foundAndNull) {
1567 for (int i = 0; i < keys.length; i++) {
1568 if (keys[i] == null) {
1569 if (foundAndNull != null) {
1570 foundAndNull[1] = i;
1572 } else if (keys[i].equals(key)) {
1573 if (foundAndNull != null) {
1574 foundAndNull[0] = i;
1584 * Strores InnerClass data informastion.
1586 * @author Sucheta Dambalkar (Adopted code from jdis)
1588 private static class InnerClassData {
1591 int inner_class_info_index, outer_class_info_index, inner_name_index, access;
1593 public InnerClassData(ClassData cls) {
1599 * Read Innerclass attribute data.
1601 public void read(DataInputStream in) throws IOException {
1602 inner_class_info_index = in.readUnsignedShort();
1603 outer_class_info_index = in.readUnsignedShort();
1604 inner_name_index = in.readUnsignedShort();
1605 access = in.readUnsignedShort();
1609 * Returns the access of this class or interface.
1611 public String[] getAccess() {
1612 Vector v = new Vector();
1613 if ((access & ACC_PUBLIC) != 0) {
1614 v.addElement("public");
1616 if ((access & ACC_FINAL) != 0) {
1617 v.addElement("final");
1619 if ((access & ACC_ABSTRACT) != 0) {
1620 v.addElement("abstract");
1622 String[] accflags = new String[v.size()];
1623 v.copyInto(accflags);
1626 } // end InnerClassData
1628 static class BootMethodData {
1629 private final ClassData clazz;
1631 private final int[] args;
1633 private BootMethodData(ClassData clazz, int method, int[] args) {
1635 this.method = method;
1640 public String toString() {
1641 StringBuilder sb = new StringBuilder();
1642 sb.append(clazz.stringValue(method, true));
1644 for (int indx : args) {
1646 sb.append(clazz.stringValue(indx, true));
1649 return sb.toString();
1654 * Strores LineNumberTable data information.
1656 * @author Sucheta Dambalkar (Adopted code from jdis)
1658 private static class LineNumData {
1660 short start_pc, line_number;
1662 public LineNumData() {
1666 * Read LineNumberTable attribute.
1668 public LineNumData(DataInputStream in) throws IOException {
1669 start_pc = in.readShort();
1670 line_number = in.readShort();
1676 * Strores LocalVariableTable data information.
1678 * @author Sucheta Dambalkar (Adopted code from jdis)
1680 private static class LocVarData {
1682 short start_pc, length, name_cpx, sig_cpx, slot;
1684 public LocVarData() {
1688 * Read LocalVariableTable attribute.
1690 public LocVarData(DataInputStream in) throws IOException {
1691 start_pc = in.readShort();
1692 length = in.readShort();
1693 name_cpx = in.readShort();
1694 sig_cpx = in.readShort();
1695 slot = in.readShort();
1700 * Strores method data informastion.
1702 * @author Sucheta Dambalkar (Adopted code from jdis)
1704 static class MethodData {
1709 int descriptor_index;
1710 int attributes_count;
1712 Vector exception_table = new Vector(0);
1713 Vector lin_num_tb = new Vector(0);
1714 Vector loc_var_tb = new Vector(0);
1715 StackMapTableData[] stackMapTable;
1716 StackMapData[] stackMap;
1717 int[] exc_index_table = null;
1718 Vector attrs = new Vector(0);
1719 Vector code_attrs = new Vector(0);
1720 int max_stack, max_locals;
1721 boolean isSynthetic = false;
1722 boolean isDeprecated = false;
1723 private AttrData annotationDefault;
1725 public MethodData(ClassData cls) {
1732 public void read(DataInputStream in) throws IOException {
1733 access = in.readUnsignedShort();
1734 name_index = in.readUnsignedShort();
1735 descriptor_index = in.readUnsignedShort();
1736 int attributes_count = in.readUnsignedShort();
1737 for (int i = 0; i < attributes_count; i++) {
1738 int attr_name_index = in.readUnsignedShort();
1742 if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
1743 String attr_name = cls.getString(attr_name_index);
1744 if (attr_name.equals("Code")) {
1746 AttrData attr = new AttrData(cls);
1747 attr.read(attr_name_index);
1748 attrs.addElement(attr);
1750 } else if (attr_name.equals("Exceptions")) {
1752 AttrData attr = new AttrData(cls);
1753 attr.read(attr_name_index);
1754 attrs.addElement(attr);
1756 } else if (attr_name.equals("Synthetic")) {
1757 if (in.readInt() != 0) {
1758 throw new ClassFormatError("invalid Synthetic attr length");
1761 AttrData attr = new AttrData(cls);
1762 attr.read(attr_name_index);
1763 attrs.addElement(attr);
1765 } else if (attr_name.equals("Deprecated")) {
1766 if (in.readInt() != 0) {
1767 throw new ClassFormatError("invalid Synthetic attr length");
1769 isDeprecated = true;
1770 AttrData attr = new AttrData(cls);
1771 attr.read(attr_name_index);
1772 attrs.addElement(attr);
1774 } else if (attr_name.equals("AnnotationDefault")) {
1775 AttrData attr = new AttrData(cls);
1776 attr.read(attr_name_index, in);
1777 attrs.addElement(attr);
1778 annotationDefault = attr;
1782 AttrData attr = new AttrData(cls);
1783 attr.read(attr_name_index, in);
1784 attrs.addElement(attr);
1790 * Read code attribute info.
1792 public void readCode(DataInputStream in) throws IOException {
1794 int attr_length = in.readInt();
1795 max_stack = in.readUnsignedShort();
1796 max_locals = in.readUnsignedShort();
1797 int codelen = in.readInt();
1799 code = new byte[codelen];
1801 while (totalread < codelen) {
1802 totalread += in.read(code, totalread, codelen - totalread);
1804 // in.read(code, 0, codelen);
1806 readExceptionTable(in);
1807 int code_attributes_count = in.readUnsignedShort();
1809 for (int k = 0; k < code_attributes_count; k++) {
1810 int table_name_index = in.readUnsignedShort();
1811 int table_name_tag = cls.getTag(table_name_index);
1812 AttrData attr = new AttrData(cls);
1813 if (table_name_tag == CONSTANT_UTF8) {
1814 String table_name_tstr = cls.getString(table_name_index);
1815 if (table_name_tstr.equals("LineNumberTable")) {
1816 readLineNumTable(in);
1817 attr.read(table_name_index);
1818 } else if (table_name_tstr.equals("LocalVariableTable")) {
1819 readLocVarTable(in);
1820 attr.read(table_name_index);
1821 } else if (table_name_tstr.equals("StackMapTable")) {
1822 readStackMapTable(in);
1823 attr.read(table_name_index);
1824 } else if (table_name_tstr.equals("StackMap")) {
1826 attr.read(table_name_index);
1828 attr.read(table_name_index, in);
1830 code_attrs.addElement(attr);
1834 attr.read(table_name_index, in);
1835 code_attrs.addElement(attr);
1840 * Read exception table info.
1842 void readExceptionTable(DataInputStream in) throws IOException {
1843 int exception_table_len = in.readUnsignedShort();
1844 exception_table = new Vector(exception_table_len);
1845 for (int l = 0; l < exception_table_len; l++) {
1846 exception_table.addElement(new TrapData(in, l));
1851 * Read LineNumberTable attribute info.
1853 void readLineNumTable(DataInputStream in) throws IOException {
1854 int attr_len = in.readInt(); // attr_length
1855 int lin_num_tb_len = in.readUnsignedShort();
1856 lin_num_tb = new Vector(lin_num_tb_len);
1857 for (int l = 0; l < lin_num_tb_len; l++) {
1858 lin_num_tb.addElement(new LineNumData(in));
1863 * Read LocalVariableTable attribute info.
1865 void readLocVarTable(DataInputStream in) throws IOException {
1866 int attr_len = in.readInt(); // attr_length
1867 int loc_var_tb_len = in.readUnsignedShort();
1868 loc_var_tb = new Vector(loc_var_tb_len);
1869 for (int l = 0; l < loc_var_tb_len; l++) {
1870 loc_var_tb.addElement(new LocVarData(in));
1875 * Read Exception attribute info.
1877 public void readExceptions(DataInputStream in) throws IOException {
1878 int attr_len = in.readInt(); // attr_length in prog
1879 int num_exceptions = in.readUnsignedShort();
1880 exc_index_table = new int[num_exceptions];
1881 for (int l = 0; l < num_exceptions; l++) {
1882 int exc = in.readShort();
1883 exc_index_table[l] = exc;
1888 * Read StackMapTable attribute info.
1890 void readStackMapTable(DataInputStream in) throws IOException {
1891 int attr_len = in.readInt(); //attr_length
1892 int stack_map_tb_len = in.readUnsignedShort();
1893 stackMapTable = new StackMapTableData[stack_map_tb_len];
1894 for (int i = 0; i < stack_map_tb_len; i++) {
1895 stackMapTable[i] = StackMapTableData.getInstance(in, this);
1900 * Read StackMap attribute info.
1902 void readStackMap(DataInputStream in) throws IOException {
1903 int attr_len = in.readInt(); //attr_length
1904 int stack_map_len = in.readUnsignedShort();
1905 stackMap = new StackMapData[stack_map_len];
1906 for (int i = 0; i < stack_map_len; i++) {
1907 stackMap[i] = new StackMapData(in, this);
1912 * Return access of the method.
1914 public int getAccess() {
1919 * Return name of the method.
1921 public String getName() {
1922 return cls.getStringValue(name_index);
1926 * Return internal siganature of the method.
1928 public String getInternalSig() {
1929 return cls.getStringValue(descriptor_index);
1933 * Return code attribute data of a method.
1935 public byte[] getCode() {
1940 * Return LineNumberTable size.
1942 public int getnumlines() {
1943 return lin_num_tb.size();
1947 * Return LineNumberTable
1949 public Vector getlin_num_tb() {
1954 * Return LocalVariableTable size.
1956 public int getloc_var_tbsize() {
1957 return loc_var_tb.size();
1961 * Return LocalVariableTable.
1963 public Vector getloc_var_tb() {
1970 public StackMapData[] getStackMap() {
1975 * Return StackMapTable.
1977 public StackMapTableData[] getStackMapTable() {
1978 return stackMapTable;
1981 public StackMapIterator createStackMapIterator() {
1982 return new StackMapIterator(this);
1986 * Return true if method is static
1988 public boolean isStatic() {
1989 if ((access & ACC_STATIC) != 0) {
1996 * Return max depth of operand stack.
1998 public int getMaxStack() {
2003 * Return number of local variables.
2005 public int getMaxLocals() {
2010 * Return exception index table in Exception attribute.
2012 public int[] get_exc_index_table() {
2013 return exc_index_table;
2017 * Return exception table in code attributre.
2019 public TrapDataIterator getTrapDataIterator() {
2020 return new TrapDataIterator(exception_table);
2024 * Return method attributes.
2026 public Vector getAttributes() {
2031 * Return code attributes.
2033 public Vector getCodeAttributes() {
2037 byte[] getDefaultAttribute() {
2038 return annotationDefault == null ? null : annotationDefault.getData();
2042 * Return true if method id synthetic.
2044 public boolean isSynthetic() {
2049 * Return true if method is deprecated.
2051 public boolean isDeprecated() {
2052 return isDeprecated;
2055 public byte[] findAnnotationData(boolean classRetention) {
2056 String n = classRetention
2057 ? "RuntimeInvisibleAnnotations" : // NOI18N
2058 "RuntimeVisibleAnnotations"; // NOI18N
2059 AttrData[] arr = new AttrData[attrs.size()];
2060 attrs.copyInto(arr);
2061 return ClassData.findAttr(n, arr);
2064 public boolean isConstructor() {
2065 return "<init>".equals(getName());
2069 /* represents one entry of StackMap attribute
2071 private static class StackMapData {
2077 StackMapData(int offset, int[] locals, int[] stack) {
2078 this.offset = offset;
2079 this.locals = locals;
2083 StackMapData(DataInputStream in, MethodData method) throws IOException {
2084 offset = in.readUnsignedShort();
2085 int local_size = in.readUnsignedShort();
2086 locals = readTypeArray(in, local_size, method);
2087 int stack_size = in.readUnsignedShort();
2088 stack = readTypeArray(in, stack_size, method);
2091 static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
2092 int[] types = new int[length];
2093 for (int i = 0; i < length; i++) {
2094 types[i] = readType(in, method);
2099 static final int readType(DataInputStream in, MethodData method) throws IOException {
2100 int type = in.readUnsignedByte();
2101 if (type == ITEM_Object || type == ITEM_NewObject) {
2102 type = type | (in.readUnsignedShort() << 8);
2108 static final class StackMapIterator {
2110 private final StackMapTableData[] stackMapTable;
2111 private final TypeArray argTypes;
2112 private final TypeArray localTypes;
2113 private final TypeArray stackTypes;
2114 private int nextFrameIndex;
2115 private int lastFrameByteCodeOffset;
2116 private int byteCodeOffset;
2118 StackMapIterator(final MethodData methodData) {
2119 this(methodData.getStackMapTable(),
2120 methodData.getInternalSig(),
2121 methodData.isStatic());
2124 StackMapIterator(final StackMapTableData[] stackMapTable,
2125 final String methodSignature,
2126 final boolean isStaticMethod) {
2127 this.stackMapTable = (stackMapTable != null)
2129 : new StackMapTableData[0];
2131 argTypes = getArgTypes(methodSignature, isStaticMethod);
2132 localTypes = new TypeArray();
2133 stackTypes = new TypeArray();
2135 localTypes.addAll(argTypes);
2137 lastFrameByteCodeOffset = -1;
2141 public boolean isEmpty() {
2142 return stackMapTable.length == 0;
2145 public String getFrameAsString() {
2146 return (nextFrameIndex == 0)
2147 ? StackMapTableData.toString("INITIAL", 0, null, null)
2148 : stackMapTable[nextFrameIndex - 1].toString();
2151 public int getFrameIndex() {
2152 return nextFrameIndex;
2155 public TypeArray getFrameStack() {
2159 public TypeArray getFrameLocals() {
2163 public TypeArray getArguments() {
2167 public void advanceBy(final int numByteCodes) {
2168 if (numByteCodes < 0) {
2169 throw new IllegalStateException("Forward only iterator");
2172 byteCodeOffset += numByteCodes;
2173 while ((nextFrameIndex < stackMapTable.length)
2174 && ((byteCodeOffset - lastFrameByteCodeOffset)
2175 >= (stackMapTable[nextFrameIndex].offsetDelta
2177 final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
2179 lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
2180 nextFrame.applyTo(localTypes, stackTypes);
2186 public void advanceTo(final int nextByteCodeOffset) {
2187 advanceBy(nextByteCodeOffset - byteCodeOffset);
2190 private static TypeArray getArgTypes(final String methodSignature,
2191 final boolean isStaticMethod) {
2192 final TypeArray argTypes = new TypeArray();
2194 if (!isStaticMethod) {
2195 argTypes.add(ITEM_Object);
2198 if (methodSignature.charAt(0) != '(') {
2199 throw new IllegalArgumentException("Invalid method signature");
2202 final int length = methodSignature.length();
2203 boolean skipType = false;
2205 for (int i = 1; i < length; ++i) {
2206 switch (methodSignature.charAt(i)) {
2212 argType = ITEM_Integer;
2215 argType = ITEM_Long;
2218 argType = ITEM_Float;
2221 argType = ITEM_Double;
2224 i = methodSignature.indexOf(';', i + 1);
2226 throw new IllegalArgumentException(
2227 "Invalid method signature");
2229 argType = ITEM_Object;
2233 // not interested in the return value type
2237 argTypes.add(ITEM_Object);
2243 throw new IllegalArgumentException(
2244 "Invalid method signature");
2248 argTypes.add(argType);
2257 /* represents one entry of StackMapTable attribute
2260 private static abstract class StackMapTableData {
2262 final int frameType;
2265 StackMapTableData(int frameType) {
2266 this.frameType = frameType;
2269 abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
2271 protected static String toString(
2272 final String frameType,
2274 final int[] localTypes,
2275 final int[] stackTypes) {
2276 final StringBuilder sb = new StringBuilder(frameType);
2278 sb.append("(off: +").append(offset);
2279 if (localTypes != null) {
2280 sb.append(", locals: ");
2281 appendTypes(sb, localTypes);
2283 if (stackTypes != null) {
2284 sb.append(", stack: ");
2285 appendTypes(sb, stackTypes);
2289 return sb.toString();
2292 private static void appendTypes(final StringBuilder sb, final int[] types) {
2294 if (types.length > 0) {
2295 sb.append(TypeArray.typeString(types[0]));
2296 for (int i = 1; i < types.length; ++i) {
2298 sb.append(TypeArray.typeString(types[i]));
2304 private static class SameFrame extends StackMapTableData {
2306 SameFrame(int frameType, int offsetDelta) {
2308 this.offsetDelta = offsetDelta;
2312 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2317 public String toString() {
2318 return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
2319 ? "_FRAME_EXTENDED" : ""),
2325 private static class SameLocals1StackItem extends StackMapTableData {
2329 SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
2331 this.offsetDelta = offsetDelta;
2336 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2337 stackTypes.setAll(stack);
2341 public String toString() {
2343 "SAME_LOCALS_1_STACK_ITEM"
2344 + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
2345 ? "_EXTENDED" : ""),
2351 private static class ChopFrame extends StackMapTableData {
2353 ChopFrame(int frameType, int offsetDelta) {
2355 this.offsetDelta = offsetDelta;
2359 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2360 localTypes.setSize(localTypes.getSize()
2361 - (SAME_FRAME_EXTENDED - frameType));
2366 public String toString() {
2367 return toString("CHOP", offsetDelta, null, null);
2371 private static class AppendFrame extends StackMapTableData {
2375 AppendFrame(int frameType, int offsetDelta, int[] locals) {
2377 this.offsetDelta = offsetDelta;
2378 this.locals = locals;
2382 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2383 localTypes.addAll(locals);
2388 public String toString() {
2389 return toString("APPEND", offsetDelta, locals, null);
2393 private static class FullFrame extends StackMapTableData {
2398 FullFrame(int offsetDelta, int[] locals, int[] stack) {
2400 this.offsetDelta = offsetDelta;
2401 this.locals = locals;
2406 void applyTo(TypeArray localTypes, TypeArray stackTypes) {
2407 localTypes.setAll(locals);
2408 stackTypes.setAll(stack);
2412 public String toString() {
2413 return toString("FULL", offsetDelta, locals, stack);
2417 static StackMapTableData getInstance(DataInputStream in, MethodData method)
2418 throws IOException {
2419 int frameType = in.readUnsignedByte();
2421 if (frameType < SAME_FRAME_BOUND) {
2423 return new SameFrame(frameType, frameType);
2424 } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
2425 // same_locals_1_stack_item_frame
2426 // read additional single stack element
2427 return new SameLocals1StackItem(frameType,
2428 (frameType - SAME_FRAME_BOUND),
2429 StackMapData.readTypeArray(in, 1, method));
2430 } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
2431 // same_locals_1_stack_item_extended
2432 return new SameLocals1StackItem(frameType,
2433 in.readUnsignedShort(),
2434 StackMapData.readTypeArray(in, 1, method));
2435 } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
2436 // chop_frame or same_frame_extended
2437 return new ChopFrame(frameType, in.readUnsignedShort());
2438 } else if (frameType == SAME_FRAME_EXTENDED) {
2439 // chop_frame or same_frame_extended
2440 return new SameFrame(frameType, in.readUnsignedShort());
2441 } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
2443 return new AppendFrame(frameType, in.readUnsignedShort(),
2444 StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
2445 } else if (frameType == FULL_FRAME) {
2447 int offsetDelta = in.readUnsignedShort();
2448 int locals_size = in.readUnsignedShort();
2449 int[] locals = StackMapData.readTypeArray(in, locals_size, method);
2450 int stack_size = in.readUnsignedShort();
2451 int[] stack = StackMapData.readTypeArray(in, stack_size, method);
2452 return new FullFrame(offsetDelta, locals, stack);
2454 throw new ClassFormatError("unrecognized frame_type in StackMapTable");
2460 * Stores exception table data in code attribute.
2462 * @author Sucheta Dambalkar (Adopted code from jdis)
2464 static final class TrapData {
2466 public final short start_pc;
2467 public final short end_pc;
2468 public final short handler_pc;
2469 public final short catch_cpx;
2473 * Read and store exception table data in code attribute.
2475 TrapData(DataInputStream in, int num) throws IOException {
2477 start_pc = in.readShort();
2478 end_pc = in.readShort();
2479 handler_pc = in.readShort();
2480 catch_cpx = in.readShort();
2484 * returns recommended identifier
2486 public String ident() {
2492 * @author Jaroslav Tulach <jtulach@netbeans.org>
2494 static final class TrapDataIterator {
2496 private final Hashtable exStart = new Hashtable();
2497 private final Hashtable exStop = new Hashtable();
2498 private TrapData[] current = new TrapData[10];
2499 private int currentCount;
2501 TrapDataIterator(Vector exceptionTable) {
2502 for (int i = 0; i < exceptionTable.size(); i++) {
2503 final TrapData td = (TrapData) exceptionTable.elementAt(i);
2504 put(exStart, td.start_pc, td);
2505 put(exStop, td.end_pc, td);
2509 private static void put(Hashtable h, short key, TrapData td) {
2510 Short s = Short.valueOf((short) key);
2511 Vector v = (Vector) h.get(s);
2519 private boolean processAll(Hashtable h, Short key, boolean add) {
2520 boolean change = false;
2521 Vector v = (Vector) h.get(key);
2524 for (int i = 0; i < s; i++) {
2525 TrapData td = (TrapData) v.elementAt(i);
2538 public boolean advanceTo(int i) {
2539 Short s = Short.valueOf((short) i);
2540 boolean ch1 = processAll(exStart, s, true);
2541 boolean ch2 = processAll(exStop, s, false);
2545 public boolean useTry() {
2546 return currentCount > 0;
2549 public TrapData[] current() {
2550 TrapData[] copy = new TrapData[currentCount];
2551 for (int i = 0; i < currentCount; i++) {
2552 copy[i] = current[i];
2557 private void add(TrapData e) {
2558 if (currentCount == current.length) {
2559 TrapData[] data = new TrapData[currentCount * 2];
2560 for (int i = 0; i < currentCount; i++) {
2561 data[i] = current[i];
2565 current[currentCount++] = e;
2568 private void remove(TrapData e) {
2569 if (currentCount == 0) {
2573 while (from < currentCount) {
2574 if (e == current[from++]) {
2578 while (from < currentCount) {
2579 current[from - 1] = current[from];
2580 current[from] = null;
2586 static final class TypeArray {
2588 private static final int CAPACITY_INCREMENT = 16;
2589 private int[] types;
2592 public TypeArray() {
2595 public TypeArray(final TypeArray initialTypes) {
2596 setAll(initialTypes);
2599 public void add(final int newType) {
2600 ensureCapacity(size + 1);
2601 types[size++] = newType;
2604 public void addAll(final TypeArray newTypes) {
2605 addAll(newTypes.types, 0, newTypes.size);
2608 public void addAll(final int[] newTypes) {
2609 addAll(newTypes, 0, newTypes.length);
2612 public void addAll(final int[] newTypes,
2616 ensureCapacity(size + count);
2617 arraycopy(newTypes, offset, types, size, count);
2622 public void set(final int index, final int newType) {
2623 types[index] = newType;
2626 public void setAll(final TypeArray newTypes) {
2627 setAll(newTypes.types, 0, newTypes.size);
2630 public void setAll(final int[] newTypes) {
2631 setAll(newTypes, 0, newTypes.length);
2634 public void setAll(final int[] newTypes,
2638 ensureCapacity(count);
2639 arraycopy(newTypes, offset, types, 0, count);
2646 public void setSize(final int newSize) {
2647 if (size != newSize) {
2648 ensureCapacity(newSize);
2650 for (int i = size; i < newSize; ++i) {
2657 public void clear() {
2661 public int getSize() {
2665 public int get(final int index) {
2666 return types[index];
2669 public static String typeString(final int type) {
2670 switch (type & 0xff) {
2683 case ITEM_InitObject: // UninitializedThis
2687 case ITEM_NewObject: // Uninitialized
2690 throw new IllegalArgumentException("Unknown type");
2695 public String toString() {
2696 final StringBuilder sb = new StringBuilder("[");
2698 for (int i = 0; i < size; ++i) {
2699 sb.append(sep).append(VarType.toString(types[i] & 0xff));
2702 return sb.append(']').toString();
2705 private void ensureCapacity(final int minCapacity) {
2706 if ((minCapacity == 0)
2707 || (types != null) && (minCapacity <= types.length)) {
2711 final int newCapacity =
2712 ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
2713 * CAPACITY_INCREMENT;
2714 final int[] newTypes = new int[newCapacity];
2717 arraycopy(types, 0, newTypes, 0, size);
2723 // no System.arraycopy
2724 private void arraycopy(final int[] src, final int srcPos,
2725 final int[] dest, final int destPos,
2727 for (int i = 0; i < length; ++i) {
2728 dest[destPos + i] = src[srcPos + i];
2733 * A JavaScript ready replacement for java.util.Vector
2735 * @author Jaroslav Tulach <jtulach@netbeans.org>
2737 @JavaScriptPrototype(prototype = "new Array")
2738 private static final class Vector {
2740 private Object[] arr;
2748 void add(Object objectType) {
2749 addElement(objectType);
2752 @JavaScriptBody(args = {"obj"}, body =
2754 void addElement(Object obj) {
2755 final int s = size();
2757 setElementAt(obj, s);
2760 @JavaScriptBody(args = {}, body =
2761 "return this.length;")
2763 return arr == null ? 0 : arr.length;
2766 @JavaScriptBody(args = {"newArr"}, body =
2767 "for (var i = 0; i < this.length; i++) {\n"
2768 + " newArr[i] = this[i];\n"
2770 void copyInto(Object[] newArr) {
2774 int min = Math.min(newArr.length, arr.length);
2775 for (int i = 0; i < min; i++) {
2780 @JavaScriptBody(args = {"index"}, body =
2781 "return this[index];")
2782 Object elementAt(int index) {
2786 private void setSize(int len) {
2787 Object[] newArr = new Object[len];
2792 @JavaScriptBody(args = {"val", "index"}, body =
2793 "this[index] = val;")
2794 void setElementAt(Object val, int index) {