|
1 /* |
|
2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
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). |
|
16 * |
|
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. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package com.sun.tools.classfile; |
|
27 |
|
28 import java.io.IOException; |
|
29 |
|
30 /** |
|
31 * See JVMS3, section 4.5. |
|
32 * |
|
33 * <p><b>This is NOT part of any API supported by Sun Microsystems. If |
|
34 * you write code that depends on this, you do so at your own risk. |
|
35 * This code and its internal interfaces are subject to change or |
|
36 * deletion without notice.</b> |
|
37 */ |
|
38 public class ConstantPool { |
|
39 |
|
40 public class InvalidIndex extends ConstantPoolException { |
|
41 InvalidIndex(int index) { |
|
42 super(index); |
|
43 } |
|
44 |
|
45 @Override |
|
46 public String getMessage() { |
|
47 // i18n |
|
48 return "invalid index #" + index; |
|
49 } |
|
50 } |
|
51 |
|
52 public class UnexpectedEntry extends ConstantPoolException { |
|
53 UnexpectedEntry(int index, int expected_tag, int found_tag) { |
|
54 super(index); |
|
55 this.expected_tag = expected_tag; |
|
56 this.found_tag = found_tag; |
|
57 } |
|
58 |
|
59 @Override |
|
60 public String getMessage() { |
|
61 // i18n? |
|
62 return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag; |
|
63 } |
|
64 |
|
65 public final int expected_tag; |
|
66 public final int found_tag; |
|
67 } |
|
68 |
|
69 public class InvalidEntry extends ConstantPoolException { |
|
70 InvalidEntry(int index, int tag) { |
|
71 super(index); |
|
72 this.tag = tag; |
|
73 } |
|
74 |
|
75 @Override |
|
76 public String getMessage() { |
|
77 // i18n? |
|
78 return "unexpected tag at #" + index + ": " + tag; |
|
79 } |
|
80 |
|
81 public final int tag; |
|
82 } |
|
83 |
|
84 public class EntryNotFound extends ConstantPoolException { |
|
85 EntryNotFound(Object value) { |
|
86 super(-1); |
|
87 this.value = value; |
|
88 } |
|
89 |
|
90 @Override |
|
91 public String getMessage() { |
|
92 // i18n? |
|
93 return "value not found: " + value; |
|
94 } |
|
95 |
|
96 public final Object value; |
|
97 } |
|
98 |
|
99 public static final int CONSTANT_Utf8 = 1; |
|
100 public static final int CONSTANT_Integer = 3; |
|
101 public static final int CONSTANT_Float = 4; |
|
102 public static final int CONSTANT_Long = 5; |
|
103 public static final int CONSTANT_Double = 6; |
|
104 public static final int CONSTANT_Class = 7; |
|
105 public static final int CONSTANT_String = 8; |
|
106 public static final int CONSTANT_Fieldref = 9; |
|
107 public static final int CONSTANT_Methodref = 10; |
|
108 public static final int CONSTANT_InterfaceMethodref = 11; |
|
109 public static final int CONSTANT_NameAndType = 12; |
|
110 |
|
111 ConstantPool(ClassReader cr) throws IOException, InvalidEntry { |
|
112 int count = cr.readUnsignedShort(); |
|
113 pool = new CPInfo[count]; |
|
114 for (int i = 1; i < count; i++) { |
|
115 int tag = cr.readUnsignedByte(); |
|
116 switch (tag) { |
|
117 case CONSTANT_Class: |
|
118 pool[i] = new CONSTANT_Class_info(this, cr); |
|
119 break; |
|
120 |
|
121 case CONSTANT_Double: |
|
122 pool[i] = new CONSTANT_Double_info(cr); |
|
123 i++; |
|
124 break; |
|
125 |
|
126 case CONSTANT_Fieldref: |
|
127 pool[i] = new CONSTANT_Fieldref_info(this, cr); |
|
128 break; |
|
129 |
|
130 case CONSTANT_Float: |
|
131 pool[i] = new CONSTANT_Float_info(cr); |
|
132 break; |
|
133 |
|
134 case CONSTANT_Integer: |
|
135 pool[i] = new CONSTANT_Integer_info(cr); |
|
136 break; |
|
137 |
|
138 case CONSTANT_InterfaceMethodref: |
|
139 pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr); |
|
140 break; |
|
141 |
|
142 case CONSTANT_Long: |
|
143 pool[i] = new CONSTANT_Long_info(cr); |
|
144 i++; |
|
145 break; |
|
146 |
|
147 case CONSTANT_Methodref: |
|
148 pool[i] = new CONSTANT_Methodref_info(this, cr); |
|
149 break; |
|
150 |
|
151 case CONSTANT_NameAndType: |
|
152 pool[i] = new CONSTANT_NameAndType_info(this, cr); |
|
153 break; |
|
154 |
|
155 case CONSTANT_String: |
|
156 pool[i] = new CONSTANT_String_info(cr); |
|
157 break; |
|
158 |
|
159 case CONSTANT_Utf8: |
|
160 pool[i] = new CONSTANT_Utf8_info(cr); |
|
161 break; |
|
162 |
|
163 default: |
|
164 throw new InvalidEntry(i, tag); |
|
165 } |
|
166 } |
|
167 } |
|
168 |
|
169 public ConstantPool(CPInfo[] pool) { |
|
170 this.pool = pool; |
|
171 } |
|
172 |
|
173 public int size() { |
|
174 return pool.length; |
|
175 } |
|
176 |
|
177 public CPInfo get(int index) throws InvalidIndex { |
|
178 if (index <= 0 || index >= pool.length) |
|
179 throw new InvalidIndex(index); |
|
180 CPInfo info = pool[index]; |
|
181 if (info == null) { |
|
182 // this occurs for indices referencing the "second half" of an |
|
183 // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long |
|
184 throw new InvalidIndex(index); |
|
185 } |
|
186 return pool[index]; |
|
187 } |
|
188 |
|
189 private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry { |
|
190 CPInfo info = get(index); |
|
191 if (info.getTag() != expected_type) |
|
192 throw new UnexpectedEntry(index, expected_type, info.getTag()); |
|
193 return info; |
|
194 } |
|
195 |
|
196 public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry { |
|
197 return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8)); |
|
198 } |
|
199 |
|
200 public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry { |
|
201 return ((CONSTANT_Class_info) get(index, CONSTANT_Class)); |
|
202 } |
|
203 |
|
204 public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry { |
|
205 return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType)); |
|
206 } |
|
207 |
|
208 public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry { |
|
209 return getUTF8Info(index).value; |
|
210 } |
|
211 |
|
212 public int getUTF8Index(String value) throws EntryNotFound { |
|
213 for (int i = 1; i < pool.length; i++) { |
|
214 CPInfo info = pool[i]; |
|
215 if (info instanceof CONSTANT_Utf8_info && |
|
216 ((CONSTANT_Utf8_info) info).value.equals(value)) |
|
217 return i; |
|
218 } |
|
219 throw new EntryNotFound(value); |
|
220 } |
|
221 |
|
222 private CPInfo[] pool; |
|
223 |
|
224 public interface Visitor<R,P> { |
|
225 R visitClass(CONSTANT_Class_info info, P p); |
|
226 R visitDouble(CONSTANT_Double_info info, P p); |
|
227 R visitFieldref(CONSTANT_Fieldref_info info, P p); |
|
228 R visitFloat(CONSTANT_Float_info info, P p); |
|
229 R visitInteger(CONSTANT_Integer_info info, P p); |
|
230 R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p); |
|
231 R visitLong(CONSTANT_Long_info info, P p); |
|
232 R visitNameAndType(CONSTANT_NameAndType_info info, P p); |
|
233 R visitMethodref(CONSTANT_Methodref_info info, P p); |
|
234 R visitString(CONSTANT_String_info info, P p); |
|
235 R visitUtf8(CONSTANT_Utf8_info info, P p); |
|
236 } |
|
237 |
|
238 public static abstract class CPInfo { |
|
239 CPInfo() { |
|
240 this.cp = null; |
|
241 } |
|
242 |
|
243 CPInfo(ConstantPool cp) { |
|
244 this.cp = cp; |
|
245 } |
|
246 |
|
247 public abstract int getTag(); |
|
248 |
|
249 public abstract <R,D> R accept(Visitor<R,D> visitor, D data); |
|
250 |
|
251 protected final ConstantPool cp; |
|
252 } |
|
253 |
|
254 public static abstract class CPRefInfo extends CPInfo { |
|
255 protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException { |
|
256 super(cp); |
|
257 this.tag = tag; |
|
258 class_index = cr.readUnsignedShort(); |
|
259 name_and_type_index = cr.readUnsignedShort(); |
|
260 } |
|
261 |
|
262 protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) { |
|
263 super(cp); |
|
264 this.tag = tag; |
|
265 this.class_index = class_index; |
|
266 this.name_and_type_index = name_and_type_index; |
|
267 } |
|
268 |
|
269 public int getTag() { |
|
270 return tag; |
|
271 } |
|
272 |
|
273 public CONSTANT_Class_info getClassInfo() throws ConstantPoolException { |
|
274 return cp.getClassInfo(class_index); |
|
275 } |
|
276 |
|
277 public String getClassName() throws ConstantPoolException { |
|
278 return cp.getClassInfo(class_index).getName(); |
|
279 } |
|
280 |
|
281 public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { |
|
282 return cp.getNameAndTypeInfo(name_and_type_index); |
|
283 } |
|
284 |
|
285 public final int tag; |
|
286 public final int class_index; |
|
287 public final int name_and_type_index; |
|
288 } |
|
289 |
|
290 public static class CONSTANT_Class_info extends CPInfo { |
|
291 CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException { |
|
292 super(cp); |
|
293 name_index = cr.readUnsignedShort(); |
|
294 } |
|
295 |
|
296 public CONSTANT_Class_info(ConstantPool cp, int name_index) { |
|
297 super(cp); |
|
298 this.name_index = name_index; |
|
299 } |
|
300 |
|
301 public int getTag() { |
|
302 return CONSTANT_Class; |
|
303 } |
|
304 |
|
305 public String getName() throws ConstantPoolException { |
|
306 return cp.getUTF8Value(name_index); |
|
307 } |
|
308 |
|
309 @Override |
|
310 public String toString() { |
|
311 return "CONSTANT_Class_info[name_index: " + name_index + "]"; |
|
312 } |
|
313 |
|
314 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
315 return visitor.visitClass(this, data); |
|
316 } |
|
317 |
|
318 public final int name_index; |
|
319 } |
|
320 |
|
321 public static class CONSTANT_Double_info extends CPInfo { |
|
322 CONSTANT_Double_info(ClassReader cr) throws IOException { |
|
323 value = cr.readDouble(); |
|
324 } |
|
325 |
|
326 public CONSTANT_Double_info(double value) { |
|
327 this.value = value; |
|
328 } |
|
329 |
|
330 public int getTag() { |
|
331 return CONSTANT_Double; |
|
332 } |
|
333 |
|
334 @Override |
|
335 public String toString() { |
|
336 return "CONSTANT_Double_info[value: " + value + "]"; |
|
337 } |
|
338 |
|
339 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
340 return visitor.visitDouble(this, data); |
|
341 } |
|
342 |
|
343 public final double value; |
|
344 } |
|
345 |
|
346 public static class CONSTANT_Fieldref_info extends CPRefInfo { |
|
347 CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException { |
|
348 super(cp, cr, CONSTANT_Fieldref); |
|
349 } |
|
350 |
|
351 public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) { |
|
352 super(cp, CONSTANT_Fieldref, class_index, name_and_type_index); |
|
353 } |
|
354 |
|
355 @Override |
|
356 public String toString() { |
|
357 return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; |
|
358 } |
|
359 |
|
360 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
361 return visitor.visitFieldref(this, data); |
|
362 } |
|
363 } |
|
364 |
|
365 public static class CONSTANT_Float_info extends CPInfo { |
|
366 CONSTANT_Float_info(ClassReader cr) throws IOException { |
|
367 value = cr.readFloat(); |
|
368 } |
|
369 |
|
370 public CONSTANT_Float_info(float value) { |
|
371 this.value = value; |
|
372 } |
|
373 |
|
374 public int getTag() { |
|
375 return CONSTANT_Float; |
|
376 } |
|
377 |
|
378 @Override |
|
379 public String toString() { |
|
380 return "CONSTANT_Float_info[value: " + value + "]"; |
|
381 } |
|
382 |
|
383 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
384 return visitor.visitFloat(this, data); |
|
385 } |
|
386 |
|
387 public final float value; |
|
388 } |
|
389 |
|
390 public static class CONSTANT_Integer_info extends CPInfo { |
|
391 CONSTANT_Integer_info(ClassReader cr) throws IOException { |
|
392 value = cr.readInt(); |
|
393 } |
|
394 |
|
395 public CONSTANT_Integer_info(int value) { |
|
396 this.value = value; |
|
397 } |
|
398 |
|
399 public int getTag() { |
|
400 return CONSTANT_Integer; |
|
401 } |
|
402 |
|
403 @Override |
|
404 public String toString() { |
|
405 return "CONSTANT_Integer_info[value: " + value + "]"; |
|
406 } |
|
407 |
|
408 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
409 return visitor.visitInteger(this, data); |
|
410 } |
|
411 |
|
412 public final int value; |
|
413 } |
|
414 |
|
415 public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo { |
|
416 CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException { |
|
417 super(cp, cr, CONSTANT_InterfaceMethodref); |
|
418 } |
|
419 |
|
420 public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) { |
|
421 super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index); |
|
422 } |
|
423 |
|
424 @Override |
|
425 public String toString() { |
|
426 return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; |
|
427 } |
|
428 |
|
429 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
430 return visitor.visitInterfaceMethodref(this, data); |
|
431 } |
|
432 } |
|
433 |
|
434 public static class CONSTANT_Long_info extends CPInfo { |
|
435 CONSTANT_Long_info(ClassReader cr) throws IOException { |
|
436 value = cr.readLong(); |
|
437 } |
|
438 |
|
439 public CONSTANT_Long_info(long value) { |
|
440 this.value = value; |
|
441 } |
|
442 |
|
443 public int getTag() { |
|
444 return CONSTANT_Long; |
|
445 } |
|
446 |
|
447 @Override |
|
448 public String toString() { |
|
449 return "CONSTANT_Long_info[value: " + value + "]"; |
|
450 } |
|
451 |
|
452 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
453 return visitor.visitLong(this, data); |
|
454 } |
|
455 |
|
456 public final long value; |
|
457 } |
|
458 |
|
459 public static class CONSTANT_Methodref_info extends CPRefInfo { |
|
460 CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException { |
|
461 super(cp, cr, CONSTANT_Methodref); |
|
462 } |
|
463 |
|
464 public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) { |
|
465 super(cp, CONSTANT_Methodref, class_index, name_and_type_index); |
|
466 } |
|
467 |
|
468 @Override |
|
469 public String toString() { |
|
470 return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; |
|
471 } |
|
472 |
|
473 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
474 return visitor.visitMethodref(this, data); |
|
475 } |
|
476 } |
|
477 |
|
478 public static class CONSTANT_NameAndType_info extends CPInfo { |
|
479 CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException { |
|
480 super(cp); |
|
481 name_index = cr.readUnsignedShort(); |
|
482 type_index = cr.readUnsignedShort(); |
|
483 } |
|
484 |
|
485 public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) { |
|
486 super(cp); |
|
487 this.name_index = name_index; |
|
488 this.type_index = type_index; |
|
489 } |
|
490 |
|
491 public int getTag() { |
|
492 return CONSTANT_NameAndType; |
|
493 } |
|
494 |
|
495 public String getName() throws ConstantPoolException { |
|
496 return cp.getUTF8Value(name_index); |
|
497 } |
|
498 |
|
499 public String getType() throws ConstantPoolException { |
|
500 return cp.getUTF8Value(type_index); |
|
501 } |
|
502 |
|
503 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
504 return visitor.visitNameAndType(this, data); |
|
505 } |
|
506 |
|
507 public final int name_index; |
|
508 public final int type_index; |
|
509 } |
|
510 |
|
511 public static class CONSTANT_String_info extends CPInfo { |
|
512 CONSTANT_String_info(ClassReader cr) throws IOException { |
|
513 string_index = cr.readUnsignedShort(); |
|
514 } |
|
515 |
|
516 public CONSTANT_String_info(ConstantPool cp, int string_index) { |
|
517 super(cp); |
|
518 this.string_index = string_index; |
|
519 } |
|
520 |
|
521 public int getTag() { |
|
522 return CONSTANT_String; |
|
523 } |
|
524 |
|
525 public String getString() throws ConstantPoolException { |
|
526 return cp.getUTF8Value(string_index); |
|
527 } |
|
528 |
|
529 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
530 return visitor.visitString(this, data); |
|
531 } |
|
532 |
|
533 public final int string_index; |
|
534 } |
|
535 |
|
536 public static class CONSTANT_Utf8_info extends CPInfo { |
|
537 CONSTANT_Utf8_info(ClassReader cr) throws IOException { |
|
538 value = cr.readUTF(); |
|
539 } |
|
540 |
|
541 public CONSTANT_Utf8_info(String value) { |
|
542 this.value = value; |
|
543 } |
|
544 |
|
545 public int getTag() { |
|
546 return CONSTANT_Utf8; |
|
547 } |
|
548 |
|
549 @Override |
|
550 public String toString() { |
|
551 return "CONSTANT_Utf8_info[value: " + value + "]"; |
|
552 } |
|
553 |
|
554 public <R, D> R accept(Visitor<R, D> visitor, D data) { |
|
555 return visitor.visitUtf8(this, data); |
|
556 } |
|
557 |
|
558 public final String value; |
|
559 } |
|
560 |
|
561 |
|
562 } |