author | joehw |
Sun, 13 Aug 2017 21:10:40 -0700 | |
changeset 46174 | 5611d2529b49 |
parent 44797 | 8b3b3b911b8a |
permissions | -rw-r--r-- |
6 | 1 |
/* |
2 |
* reserved comment block |
|
3 |
* DO NOT REMOVE OR ALTER! |
|
4 |
*/ |
|
44797
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
5 |
/* |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
6 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
7 |
* contributor license agreements. See the NOTICE file distributed with |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
8 |
* this work for additional information regarding copyright ownership. |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
9 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
10 |
* (the "License"); you may not use this file except in compliance with |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
11 |
* the License. You may obtain a copy of the License at |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
12 |
* |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
14 |
* |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
15 |
* Unless required by applicable law or agreed to in writing, software |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
18 |
* See the License for the specific language governing permissions and |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
19 |
* limitations under the License. |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
20 |
*/ |
8b3b3b911b8a
8162572: Update License Header for all JAXP sources
joehw
parents:
25868
diff
changeset
|
21 |
|
6 | 22 |
package com.sun.org.apache.bcel.internal.classfile; |
23 |
||
46174 | 24 |
import java.io.DataInput; |
25 |
import java.io.DataOutputStream; |
|
26 |
import java.io.IOException; |
|
6 | 27 |
|
46174 | 28 |
import com.sun.org.apache.bcel.internal.Const; |
6 | 29 |
|
30 |
/** |
|
31 |
* This class represents the constant pool, i.e., a table of constants, of |
|
32 |
* a parsed classfile. It may contain null references, due to the JVM |
|
33 |
* specification that skips an entry after an 8-byte constant (double, |
|
34 |
* long) entry. Those interested in generating constant pools |
|
35 |
* programatically should see <a href="../generic/ConstantPoolGen.html"> |
|
36 |
* ConstantPoolGen</a>. |
|
37 |
||
46174 | 38 |
* @version $Id: ConstantPool.java 1749603 2016-06-21 20:50:19Z ggregory $ |
6 | 39 |
* @see Constant |
40 |
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen |
|
41 |
*/ |
|
46174 | 42 |
public class ConstantPool implements Cloneable, Node { |
6 | 43 |
|
46174 | 44 |
private Constant[] constant_pool; |
45 |
||
6 | 46 |
|
46174 | 47 |
/** |
48 |
* @param constant_pool Array of constants |
|
49 |
*/ |
|
50 |
public ConstantPool(final Constant[] constant_pool) { |
|
51 |
this.constant_pool = constant_pool; |
|
52 |
} |
|
6 | 53 |
|
54 |
||
46174 | 55 |
/** |
56 |
* Read constants from given input stream. |
|
57 |
* |
|
58 |
* @param input Input stream |
|
59 |
* @throws IOException |
|
60 |
* @throws ClassFormatException |
|
61 |
*/ |
|
62 |
public ConstantPool(final DataInput input) throws IOException, ClassFormatException { |
|
63 |
byte tag; |
|
64 |
final int constant_pool_count = input.readUnsignedShort(); |
|
65 |
constant_pool = new Constant[constant_pool_count]; |
|
66 |
/* constant_pool[0] is unused by the compiler and may be used freely |
|
67 |
* by the implementation. |
|
68 |
*/ |
|
69 |
for (int i = 1; i < constant_pool_count; i++) { |
|
70 |
constant_pool[i] = Constant.readConstant(input); |
|
71 |
/* Quote from the JVM specification: |
|
72 |
* "All eight byte constants take up two spots in the constant pool. |
|
73 |
* If this is the n'th byte in the constant pool, then the next item |
|
74 |
* will be numbered n+2" |
|
75 |
* |
|
76 |
* Thus we have to increment the index counter. |
|
77 |
*/ |
|
78 |
tag = constant_pool[i].getTag(); |
|
79 |
if ((tag == Const.CONSTANT_Double) || (tag == Const.CONSTANT_Long)) { |
|
80 |
i++; |
|
81 |
} |
|
82 |
} |
|
83 |
} |
|
6 | 84 |
|
85 |
||
46174 | 86 |
/** |
87 |
* Called by objects that are traversing the nodes of the tree implicitely |
|
88 |
* defined by the contents of a Java class. I.e., the hierarchy of methods, |
|
89 |
* fields, attributes, etc. spawns a tree of objects. |
|
90 |
* |
|
91 |
* @param v Visitor object |
|
92 |
*/ |
|
93 |
@Override |
|
94 |
public void accept( final Visitor v ) { |
|
95 |
v.visitConstantPool(this); |
|
6 | 96 |
} |
97 |
||
98 |
||
46174 | 99 |
/** |
100 |
* Resolve constant to a string representation. |
|
101 |
* |
|
102 |
* @param c Constant to be printed |
|
103 |
* @return String representation |
|
104 |
*/ |
|
105 |
public String constantToString( Constant c ) throws ClassFormatException { |
|
106 |
String str; |
|
107 |
int i; |
|
108 |
final byte tag = c.getTag(); |
|
109 |
switch (tag) { |
|
110 |
case Const.CONSTANT_Class: |
|
111 |
i = ((ConstantClass) c).getNameIndex(); |
|
112 |
c = getConstant(i, Const.CONSTANT_Utf8); |
|
113 |
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); |
|
114 |
break; |
|
115 |
case Const.CONSTANT_String: |
|
116 |
i = ((ConstantString) c).getStringIndex(); |
|
117 |
c = getConstant(i, Const.CONSTANT_Utf8); |
|
118 |
str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; |
|
119 |
break; |
|
120 |
case Const.CONSTANT_Utf8: |
|
121 |
str = ((ConstantUtf8) c).getBytes(); |
|
122 |
break; |
|
123 |
case Const.CONSTANT_Double: |
|
124 |
str = String.valueOf(((ConstantDouble) c).getBytes()); |
|
125 |
break; |
|
126 |
case Const.CONSTANT_Float: |
|
127 |
str = String.valueOf(((ConstantFloat) c).getBytes()); |
|
128 |
break; |
|
129 |
case Const.CONSTANT_Long: |
|
130 |
str = String.valueOf(((ConstantLong) c).getBytes()); |
|
131 |
break; |
|
132 |
case Const.CONSTANT_Integer: |
|
133 |
str = String.valueOf(((ConstantInteger) c).getBytes()); |
|
134 |
break; |
|
135 |
case Const.CONSTANT_NameAndType: |
|
136 |
str = constantToString(((ConstantNameAndType) c).getNameIndex(), |
|
137 |
Const.CONSTANT_Utf8) |
|
138 |
+ ":" + constantToString(((ConstantNameAndType) c).getSignatureIndex(), |
|
139 |
Const.CONSTANT_Utf8); |
|
140 |
break; |
|
141 |
case Const.CONSTANT_InterfaceMethodref: |
|
142 |
case Const.CONSTANT_Methodref: |
|
143 |
case Const.CONSTANT_Fieldref: |
|
144 |
str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) |
|
145 |
+ "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(), |
|
146 |
Const.CONSTANT_NameAndType); |
|
147 |
break; |
|
148 |
case Const.CONSTANT_MethodHandle: |
|
149 |
// Note that the ReferenceIndex may point to a Fieldref, Methodref or |
|
150 |
// InterfaceMethodref - so we need to peek ahead to get the actual type. |
|
151 |
final ConstantMethodHandle cmh = (ConstantMethodHandle) c; |
|
152 |
str = Const.getMethodHandleName(cmh.getReferenceKind()) |
|
153 |
+ " " + constantToString(cmh.getReferenceIndex(), |
|
154 |
getConstant(cmh.getReferenceIndex()).getTag()); |
|
155 |
break; |
|
156 |
case Const.CONSTANT_MethodType: |
|
157 |
final ConstantMethodType cmt = (ConstantMethodType) c; |
|
158 |
str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); |
|
159 |
break; |
|
160 |
case Const.CONSTANT_InvokeDynamic: |
|
161 |
final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; |
|
162 |
str = cid.getBootstrapMethodAttrIndex() |
|
163 |
+ ":" + constantToString(cid.getNameAndTypeIndex(), |
|
164 |
Const.CONSTANT_NameAndType); |
|
165 |
break; |
|
166 |
default: // Never reached |
|
167 |
throw new RuntimeException("Unknown constant type " + tag); |
|
168 |
} |
|
169 |
return str; |
|
6 | 170 |
} |
171 |
||
46174 | 172 |
|
173 |
private static String escape( final String str ) { |
|
174 |
final int len = str.length(); |
|
175 |
final StringBuilder buf = new StringBuilder(len + 5); |
|
176 |
final char[] ch = str.toCharArray(); |
|
177 |
for (int i = 0; i < len; i++) { |
|
178 |
switch (ch[i]) { |
|
179 |
case '\n': |
|
180 |
buf.append("\\n"); |
|
181 |
break; |
|
182 |
case '\r': |
|
183 |
buf.append("\\r"); |
|
184 |
break; |
|
185 |
case '\t': |
|
186 |
buf.append("\\t"); |
|
187 |
break; |
|
188 |
case '\b': |
|
189 |
buf.append("\\b"); |
|
190 |
break; |
|
191 |
case '"': |
|
192 |
buf.append("\\\""); |
|
193 |
break; |
|
194 |
default: |
|
195 |
buf.append(ch[i]); |
|
196 |
} |
|
197 |
} |
|
198 |
return buf.toString(); |
|
199 |
} |
|
6 | 200 |
|
201 |
||
46174 | 202 |
/** |
203 |
* Retrieve constant at `index' from constant pool and resolve it to |
|
204 |
* a string representation. |
|
205 |
* |
|
206 |
* @param index of constant in constant pool |
|
207 |
* @param tag expected type |
|
208 |
* @return String representation |
|
209 |
*/ |
|
210 |
public String constantToString( final int index, final byte tag ) throws ClassFormatException { |
|
211 |
final Constant c = getConstant(index, tag); |
|
212 |
return constantToString(c); |
|
213 |
} |
|
214 |
||
6 | 215 |
|
46174 | 216 |
/** |
217 |
* Dump constant pool to file stream in binary format. |
|
218 |
* |
|
219 |
* @param file Output file stream |
|
220 |
* @throws IOException |
|
221 |
*/ |
|
222 |
public void dump( final DataOutputStream file ) throws IOException { |
|
223 |
file.writeShort(constant_pool.length); |
|
224 |
for (int i = 1; i < constant_pool.length; i++) { |
|
225 |
if (constant_pool[i] != null) { |
|
226 |
constant_pool[i].dump(file); |
|
227 |
} |
|
228 |
} |
|
229 |
} |
|
6 | 230 |
|
231 |
||
46174 | 232 |
/** |
233 |
* Get constant from constant pool. |
|
234 |
* |
|
235 |
* @param index Index in constant pool |
|
236 |
* @return Constant value |
|
237 |
* @see Constant |
|
238 |
*/ |
|
239 |
public Constant getConstant( final int index ) { |
|
240 |
if (index >= constant_pool.length || index < 0) { |
|
241 |
throw new ClassFormatException("Invalid constant pool reference: " + index |
|
242 |
+ ". Constant pool size is: " + constant_pool.length); |
|
243 |
} |
|
244 |
return constant_pool[index]; |
|
245 |
} |
|
6 | 246 |
|
247 |
||
46174 | 248 |
/** |
249 |
* Get constant from constant pool and check whether it has the |
|
250 |
* expected type. |
|
251 |
* |
|
252 |
* @param index Index in constant pool |
|
253 |
* @param tag Tag of expected constant, i.e., its type |
|
254 |
* @return Constant value |
|
255 |
* @see Constant |
|
256 |
* @throws ClassFormatException |
|
257 |
*/ |
|
258 |
public Constant getConstant( final int index, final byte tag ) throws ClassFormatException { |
|
259 |
Constant c; |
|
260 |
c = getConstant(index); |
|
261 |
if (c == null) { |
|
262 |
throw new ClassFormatException("Constant pool at index " + index + " is null."); |
|
263 |
} |
|
264 |
if (c.getTag() != tag) { |
|
265 |
throw new ClassFormatException("Expected class `" + Const.getConstantName(tag) |
|
266 |
+ "' at index " + index + " and got " + c); |
|
267 |
} |
|
268 |
return c; |
|
269 |
} |
|
6 | 270 |
|
271 |
||
46174 | 272 |
/** |
273 |
* @return Array of constants. |
|
274 |
* @see Constant |
|
6 | 275 |
*/ |
46174 | 276 |
public Constant[] getConstantPool() { |
277 |
return constant_pool; |
|
6 | 278 |
} |
279 |
||
280 |
||
46174 | 281 |
/** |
282 |
* Get string from constant pool and bypass the indirection of |
|
283 |
* `ConstantClass' and `ConstantString' objects. I.e. these classes have |
|
284 |
* an index field that points to another entry of the constant pool of |
|
285 |
* type `ConstantUtf8' which contains the real data. |
|
286 |
* |
|
287 |
* @param index Index in constant pool |
|
288 |
* @param tag Tag of expected constant, either ConstantClass or ConstantString |
|
289 |
* @return Contents of string reference |
|
290 |
* @see ConstantClass |
|
291 |
* @see ConstantString |
|
292 |
* @throws ClassFormatException |
|
293 |
*/ |
|
294 |
public String getConstantString( final int index, final byte tag ) throws ClassFormatException { |
|
295 |
Constant c; |
|
296 |
int i; |
|
297 |
c = getConstant(index, tag); |
|
298 |
/* This switch() is not that elegant, since the two classes have the |
|
299 |
* same contents, they just differ in the name of the index |
|
300 |
* field variable. |
|
301 |
* But we want to stick to the JVM naming conventions closely though |
|
302 |
* we could have solved these more elegantly by using the same |
|
303 |
* variable name or by subclassing. |
|
304 |
*/ |
|
305 |
switch (tag) { |
|
306 |
case Const.CONSTANT_Class: |
|
307 |
i = ((ConstantClass) c).getNameIndex(); |
|
308 |
break; |
|
309 |
case Const.CONSTANT_String: |
|
310 |
i = ((ConstantString) c).getStringIndex(); |
|
311 |
break; |
|
312 |
default: |
|
313 |
throw new RuntimeException("getConstantString called with illegal tag " + tag); |
|
314 |
} |
|
315 |
// Finally get the string from the constant pool |
|
316 |
c = getConstant(i, Const.CONSTANT_Utf8); |
|
317 |
return ((ConstantUtf8) c).getBytes(); |
|
318 |
} |
|
6 | 319 |
|
320 |
||
46174 | 321 |
/** |
322 |
* @return Length of constant pool. |
|
323 |
*/ |
|
324 |
public int getLength() { |
|
325 |
return constant_pool == null ? 0 : constant_pool.length; |
|
6 | 326 |
} |
327 |
||
46174 | 328 |
|
329 |
/** |
|
330 |
* @param constant Constant to set |
|
331 |
*/ |
|
332 |
public void setConstant( final int index, final Constant constant ) { |
|
333 |
constant_pool[index] = constant; |
|
334 |
} |
|
335 |
||
336 |
||
337 |
/** |
|
338 |
* @param constant_pool |
|
339 |
*/ |
|
340 |
public void setConstantPool( final Constant[] constant_pool ) { |
|
341 |
this.constant_pool = constant_pool; |
|
342 |
} |
|
343 |
||
344 |
||
345 |
/** |
|
346 |
* @return String representation. |
|
347 |
*/ |
|
348 |
@Override |
|
349 |
public String toString() { |
|
350 |
final StringBuilder buf = new StringBuilder(); |
|
351 |
for (int i = 1; i < constant_pool.length; i++) { |
|
352 |
buf.append(i).append(")").append(constant_pool[i]).append("\n"); |
|
353 |
} |
|
354 |
return buf.toString(); |
|
355 |
} |
|
356 |
||
357 |
||
358 |
/** |
|
359 |
* @return deep copy of this constant pool |
|
360 |
*/ |
|
361 |
public ConstantPool copy() { |
|
362 |
ConstantPool c = null; |
|
363 |
try { |
|
364 |
c = (ConstantPool) clone(); |
|
365 |
c.constant_pool = new Constant[constant_pool.length]; |
|
366 |
for (int i = 1; i < constant_pool.length; i++) { |
|
367 |
if (constant_pool[i] != null) { |
|
368 |
c.constant_pool[i] = constant_pool[i].copy(); |
|
369 |
} |
|
370 |
} |
|
371 |
} catch (final CloneNotSupportedException e) { |
|
372 |
// TODO should this throw? |
|
373 |
} |
|
374 |
return c; |
|
375 |
} |
|
6 | 376 |
} |