rlm@10
|
1 /***
|
rlm@10
|
2 * ASM: a very small and fast Java bytecode manipulation framework
|
rlm@10
|
3 * Copyright (c) 2000-2005 INRIA, France Telecom
|
rlm@10
|
4 * All rights reserved.
|
rlm@10
|
5 *
|
rlm@10
|
6 * Redistribution and use in source and binary forms, with or without
|
rlm@10
|
7 * modification, are permitted provided that the following conditions
|
rlm@10
|
8 * are met:
|
rlm@10
|
9 * 1. Redistributions of source code must retain the above copyright
|
rlm@10
|
10 * notice, this list of conditions and the following disclaimer.
|
rlm@10
|
11 * 2. Redistributions in binary form must reproduce the above copyright
|
rlm@10
|
12 * notice, this list of conditions and the following disclaimer in the
|
rlm@10
|
13 * documentation and/or other materials provided with the distribution.
|
rlm@10
|
14 * 3. Neither the name of the copyright holders nor the names of its
|
rlm@10
|
15 * contributors may be used to endorse or promote products derived from
|
rlm@10
|
16 * this software without specific prior written permission.
|
rlm@10
|
17 *
|
rlm@10
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
rlm@10
|
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
rlm@10
|
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
rlm@10
|
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
rlm@10
|
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
rlm@10
|
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
rlm@10
|
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
rlm@10
|
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
rlm@10
|
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
rlm@10
|
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
rlm@10
|
28 * THE POSSIBILITY OF SUCH DAMAGE.
|
rlm@10
|
29 */
|
rlm@10
|
30 package clojure.asm;
|
rlm@10
|
31
|
rlm@10
|
32 import java.lang.reflect.Constructor;
|
rlm@10
|
33 import java.lang.reflect.Method;
|
rlm@10
|
34
|
rlm@10
|
35 /**
|
rlm@10
|
36 * A Java type. This class can be used to make it easier to manipulate type and
|
rlm@10
|
37 * method descriptors.
|
rlm@10
|
38 *
|
rlm@10
|
39 * @author Eric Bruneton
|
rlm@10
|
40 * @author Chris Nokleberg
|
rlm@10
|
41 */
|
rlm@10
|
42 public class Type{
|
rlm@10
|
43
|
rlm@10
|
44 /**
|
rlm@10
|
45 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
46 */
|
rlm@10
|
47 public final static int VOID = 0;
|
rlm@10
|
48
|
rlm@10
|
49 /**
|
rlm@10
|
50 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
51 */
|
rlm@10
|
52 public final static int BOOLEAN = 1;
|
rlm@10
|
53
|
rlm@10
|
54 /**
|
rlm@10
|
55 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
56 */
|
rlm@10
|
57 public final static int CHAR = 2;
|
rlm@10
|
58
|
rlm@10
|
59 /**
|
rlm@10
|
60 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
61 */
|
rlm@10
|
62 public final static int BYTE = 3;
|
rlm@10
|
63
|
rlm@10
|
64 /**
|
rlm@10
|
65 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
66 */
|
rlm@10
|
67 public final static int SHORT = 4;
|
rlm@10
|
68
|
rlm@10
|
69 /**
|
rlm@10
|
70 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
71 */
|
rlm@10
|
72 public final static int INT = 5;
|
rlm@10
|
73
|
rlm@10
|
74 /**
|
rlm@10
|
75 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
76 */
|
rlm@10
|
77 public final static int FLOAT = 6;
|
rlm@10
|
78
|
rlm@10
|
79 /**
|
rlm@10
|
80 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
81 */
|
rlm@10
|
82 public final static int LONG = 7;
|
rlm@10
|
83
|
rlm@10
|
84 /**
|
rlm@10
|
85 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
|
rlm@10
|
86 */
|
rlm@10
|
87 public final static int DOUBLE = 8;
|
rlm@10
|
88
|
rlm@10
|
89 /**
|
rlm@10
|
90 * The sort of array reference types. See {@link #getSort getSort}.
|
rlm@10
|
91 */
|
rlm@10
|
92 public final static int ARRAY = 9;
|
rlm@10
|
93
|
rlm@10
|
94 /**
|
rlm@10
|
95 * The sort of object reference type. See {@link #getSort getSort}.
|
rlm@10
|
96 */
|
rlm@10
|
97 public final static int OBJECT = 10;
|
rlm@10
|
98
|
rlm@10
|
99 /**
|
rlm@10
|
100 * The <tt>void</tt> type.
|
rlm@10
|
101 */
|
rlm@10
|
102 public final static Type VOID_TYPE = new Type(VOID);
|
rlm@10
|
103
|
rlm@10
|
104 /**
|
rlm@10
|
105 * The <tt>boolean</tt> type.
|
rlm@10
|
106 */
|
rlm@10
|
107 public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
|
rlm@10
|
108
|
rlm@10
|
109 /**
|
rlm@10
|
110 * The <tt>char</tt> type.
|
rlm@10
|
111 */
|
rlm@10
|
112 public final static Type CHAR_TYPE = new Type(CHAR);
|
rlm@10
|
113
|
rlm@10
|
114 /**
|
rlm@10
|
115 * The <tt>byte</tt> type.
|
rlm@10
|
116 */
|
rlm@10
|
117 public final static Type BYTE_TYPE = new Type(BYTE);
|
rlm@10
|
118
|
rlm@10
|
119 /**
|
rlm@10
|
120 * The <tt>short</tt> type.
|
rlm@10
|
121 */
|
rlm@10
|
122 public final static Type SHORT_TYPE = new Type(SHORT);
|
rlm@10
|
123
|
rlm@10
|
124 /**
|
rlm@10
|
125 * The <tt>int</tt> type.
|
rlm@10
|
126 */
|
rlm@10
|
127 public final static Type INT_TYPE = new Type(INT);
|
rlm@10
|
128
|
rlm@10
|
129 /**
|
rlm@10
|
130 * The <tt>float</tt> type.
|
rlm@10
|
131 */
|
rlm@10
|
132 public final static Type FLOAT_TYPE = new Type(FLOAT);
|
rlm@10
|
133
|
rlm@10
|
134 /**
|
rlm@10
|
135 * The <tt>long</tt> type.
|
rlm@10
|
136 */
|
rlm@10
|
137 public final static Type LONG_TYPE = new Type(LONG);
|
rlm@10
|
138
|
rlm@10
|
139 /**
|
rlm@10
|
140 * The <tt>double</tt> type.
|
rlm@10
|
141 */
|
rlm@10
|
142 public final static Type DOUBLE_TYPE = new Type(DOUBLE);
|
rlm@10
|
143
|
rlm@10
|
144 // ------------------------------------------------------------------------
|
rlm@10
|
145 // Fields
|
rlm@10
|
146 // ------------------------------------------------------------------------
|
rlm@10
|
147
|
rlm@10
|
148 /**
|
rlm@10
|
149 * The sort of this Java type.
|
rlm@10
|
150 */
|
rlm@10
|
151 private final int sort;
|
rlm@10
|
152
|
rlm@10
|
153 /**
|
rlm@10
|
154 * A buffer containing the descriptor of this Java type. This field is only
|
rlm@10
|
155 * used for reference types.
|
rlm@10
|
156 */
|
rlm@10
|
157 private char[] buf;
|
rlm@10
|
158
|
rlm@10
|
159 /**
|
rlm@10
|
160 * The offset of the descriptor of this Java type in {@link #buf buf}. This
|
rlm@10
|
161 * field is only used for reference types.
|
rlm@10
|
162 */
|
rlm@10
|
163 private int off;
|
rlm@10
|
164
|
rlm@10
|
165 /**
|
rlm@10
|
166 * The length of the descriptor of this Java type.
|
rlm@10
|
167 */
|
rlm@10
|
168 private int len;
|
rlm@10
|
169
|
rlm@10
|
170 // ------------------------------------------------------------------------
|
rlm@10
|
171 // Constructors
|
rlm@10
|
172 // ------------------------------------------------------------------------
|
rlm@10
|
173
|
rlm@10
|
174 /**
|
rlm@10
|
175 * Constructs a primitive type.
|
rlm@10
|
176 *
|
rlm@10
|
177 * @param sort the sort of the primitive type to be constructed.
|
rlm@10
|
178 */
|
rlm@10
|
179 private Type(final int sort){
|
rlm@10
|
180 this.sort = sort;
|
rlm@10
|
181 this.len = 1;
|
rlm@10
|
182 }
|
rlm@10
|
183
|
rlm@10
|
184 /**
|
rlm@10
|
185 * Constructs a reference type.
|
rlm@10
|
186 *
|
rlm@10
|
187 * @param sort the sort of the reference type to be constructed.
|
rlm@10
|
188 * @param buf a buffer containing the descriptor of the previous type.
|
rlm@10
|
189 * @param off the offset of this descriptor in the previous buffer.
|
rlm@10
|
190 * @param len the length of this descriptor.
|
rlm@10
|
191 */
|
rlm@10
|
192 private Type(final int sort, final char[] buf, final int off, final int len){
|
rlm@10
|
193 this.sort = sort;
|
rlm@10
|
194 this.buf = buf;
|
rlm@10
|
195 this.off = off;
|
rlm@10
|
196 this.len = len;
|
rlm@10
|
197 }
|
rlm@10
|
198
|
rlm@10
|
199 /**
|
rlm@10
|
200 * Returns the Java type corresponding to the given type descriptor.
|
rlm@10
|
201 *
|
rlm@10
|
202 * @param typeDescriptor a type descriptor.
|
rlm@10
|
203 * @return the Java type corresponding to the given type descriptor.
|
rlm@10
|
204 */
|
rlm@10
|
205 public static Type getType(final String typeDescriptor){
|
rlm@10
|
206 return getType(typeDescriptor.toCharArray(), 0);
|
rlm@10
|
207 }
|
rlm@10
|
208
|
rlm@10
|
209 /**
|
rlm@10
|
210 * Returns the Java type corresponding to the given class.
|
rlm@10
|
211 *
|
rlm@10
|
212 * @param c a class.
|
rlm@10
|
213 * @return the Java type corresponding to the given class.
|
rlm@10
|
214 */
|
rlm@10
|
215 public static Type getType(final Class c){
|
rlm@10
|
216 if(c.isPrimitive())
|
rlm@10
|
217 {
|
rlm@10
|
218 if(c == Integer.TYPE)
|
rlm@10
|
219 {
|
rlm@10
|
220 return INT_TYPE;
|
rlm@10
|
221 }
|
rlm@10
|
222 else if(c == Void.TYPE)
|
rlm@10
|
223 {
|
rlm@10
|
224 return VOID_TYPE;
|
rlm@10
|
225 }
|
rlm@10
|
226 else if(c == Boolean.TYPE)
|
rlm@10
|
227 {
|
rlm@10
|
228 return BOOLEAN_TYPE;
|
rlm@10
|
229 }
|
rlm@10
|
230 else if(c == Byte.TYPE)
|
rlm@10
|
231 {
|
rlm@10
|
232 return BYTE_TYPE;
|
rlm@10
|
233 }
|
rlm@10
|
234 else if(c == Character.TYPE)
|
rlm@10
|
235 {
|
rlm@10
|
236 return CHAR_TYPE;
|
rlm@10
|
237 }
|
rlm@10
|
238 else if(c == Short.TYPE)
|
rlm@10
|
239 {
|
rlm@10
|
240 return SHORT_TYPE;
|
rlm@10
|
241 }
|
rlm@10
|
242 else if(c == Double.TYPE)
|
rlm@10
|
243 {
|
rlm@10
|
244 return DOUBLE_TYPE;
|
rlm@10
|
245 }
|
rlm@10
|
246 else if(c == Float.TYPE)
|
rlm@10
|
247 {
|
rlm@10
|
248 return FLOAT_TYPE;
|
rlm@10
|
249 }
|
rlm@10
|
250 else /* if (c == Long.TYPE) */
|
rlm@10
|
251 {
|
rlm@10
|
252 return LONG_TYPE;
|
rlm@10
|
253 }
|
rlm@10
|
254 }
|
rlm@10
|
255 else
|
rlm@10
|
256 {
|
rlm@10
|
257 return getType(getDescriptor(c));
|
rlm@10
|
258 }
|
rlm@10
|
259 }
|
rlm@10
|
260
|
rlm@10
|
261 /**
|
rlm@10
|
262 * Returns the {@link Type#OBJECT} type for the given internal class name.
|
rlm@10
|
263 * This is a shortcut method for <code>Type.getType("L"+name+";")</code>.
|
rlm@10
|
264 * <i>Note that opposed to {@link Type#getType(String)}, this method takes
|
rlm@10
|
265 * internal class names and not class descriptor.</i>
|
rlm@10
|
266 *
|
rlm@10
|
267 * @param name an internal class name.
|
rlm@10
|
268 * @return the the {@link Type#OBJECT} type for the given class name.
|
rlm@10
|
269 */
|
rlm@10
|
270 public static Type getObjectType(String name){
|
rlm@10
|
271 int l = name.length();
|
rlm@10
|
272 char[] buf = new char[l + 2];
|
rlm@10
|
273 buf[0] = 'L';
|
rlm@10
|
274 buf[l + 1] = ';';
|
rlm@10
|
275 name.getChars(0, l, buf, 1);
|
rlm@10
|
276 return new Type(OBJECT, buf, 0, l + 2);
|
rlm@10
|
277 }
|
rlm@10
|
278
|
rlm@10
|
279 /**
|
rlm@10
|
280 * Returns the Java types corresponding to the argument types of the given
|
rlm@10
|
281 * method descriptor.
|
rlm@10
|
282 *
|
rlm@10
|
283 * @param methodDescriptor a method descriptor.
|
rlm@10
|
284 * @return the Java types corresponding to the argument types of the given
|
rlm@10
|
285 * method descriptor.
|
rlm@10
|
286 */
|
rlm@10
|
287 public static Type[] getArgumentTypes(final String methodDescriptor){
|
rlm@10
|
288 char[] buf = methodDescriptor.toCharArray();
|
rlm@10
|
289 int off = 1;
|
rlm@10
|
290 int size = 0;
|
rlm@10
|
291 while(true)
|
rlm@10
|
292 {
|
rlm@10
|
293 char car = buf[off++];
|
rlm@10
|
294 if(car == ')')
|
rlm@10
|
295 {
|
rlm@10
|
296 break;
|
rlm@10
|
297 }
|
rlm@10
|
298 else if(car == 'L')
|
rlm@10
|
299 {
|
rlm@10
|
300 while(buf[off++] != ';')
|
rlm@10
|
301 {
|
rlm@10
|
302 }
|
rlm@10
|
303 ++size;
|
rlm@10
|
304 }
|
rlm@10
|
305 else if(car != '[')
|
rlm@10
|
306 {
|
rlm@10
|
307 ++size;
|
rlm@10
|
308 }
|
rlm@10
|
309 }
|
rlm@10
|
310 Type[] args = new Type[size];
|
rlm@10
|
311 off = 1;
|
rlm@10
|
312 size = 0;
|
rlm@10
|
313 while(buf[off] != ')')
|
rlm@10
|
314 {
|
rlm@10
|
315 args[size] = getType(buf, off);
|
rlm@10
|
316 off += args[size].len;
|
rlm@10
|
317 size += 1;
|
rlm@10
|
318 }
|
rlm@10
|
319 return args;
|
rlm@10
|
320 }
|
rlm@10
|
321
|
rlm@10
|
322 /**
|
rlm@10
|
323 * Returns the Java types corresponding to the argument types of the given
|
rlm@10
|
324 * method.
|
rlm@10
|
325 *
|
rlm@10
|
326 * @param method a method.
|
rlm@10
|
327 * @return the Java types corresponding to the argument types of the given
|
rlm@10
|
328 * method.
|
rlm@10
|
329 */
|
rlm@10
|
330 public static Type[] getArgumentTypes(final Method method){
|
rlm@10
|
331 Class[] classes = method.getParameterTypes();
|
rlm@10
|
332 Type[] types = new Type[classes.length];
|
rlm@10
|
333 for(int i = classes.length - 1; i >= 0; --i)
|
rlm@10
|
334 {
|
rlm@10
|
335 types[i] = getType(classes[i]);
|
rlm@10
|
336 }
|
rlm@10
|
337 return types;
|
rlm@10
|
338 }
|
rlm@10
|
339
|
rlm@10
|
340 /**
|
rlm@10
|
341 * Returns the Java type corresponding to the return type of the given
|
rlm@10
|
342 * method descriptor.
|
rlm@10
|
343 *
|
rlm@10
|
344 * @param methodDescriptor a method descriptor.
|
rlm@10
|
345 * @return the Java type corresponding to the return type of the given
|
rlm@10
|
346 * method descriptor.
|
rlm@10
|
347 */
|
rlm@10
|
348 public static Type getReturnType(final String methodDescriptor){
|
rlm@10
|
349 char[] buf = methodDescriptor.toCharArray();
|
rlm@10
|
350 return getType(buf, methodDescriptor.indexOf(')') + 1);
|
rlm@10
|
351 }
|
rlm@10
|
352
|
rlm@10
|
353 /**
|
rlm@10
|
354 * Returns the Java type corresponding to the return type of the given
|
rlm@10
|
355 * method.
|
rlm@10
|
356 *
|
rlm@10
|
357 * @param method a method.
|
rlm@10
|
358 * @return the Java type corresponding to the return type of the given
|
rlm@10
|
359 * method.
|
rlm@10
|
360 */
|
rlm@10
|
361 public static Type getReturnType(final Method method){
|
rlm@10
|
362 return getType(method.getReturnType());
|
rlm@10
|
363 }
|
rlm@10
|
364
|
rlm@10
|
365 /**
|
rlm@10
|
366 * Returns the Java type corresponding to the given type descriptor.
|
rlm@10
|
367 *
|
rlm@10
|
368 * @param buf a buffer containing a type descriptor.
|
rlm@10
|
369 * @param off the offset of this descriptor in the previous buffer.
|
rlm@10
|
370 * @return the Java type corresponding to the given type descriptor.
|
rlm@10
|
371 */
|
rlm@10
|
372 private static Type getType(final char[] buf, final int off){
|
rlm@10
|
373 int len;
|
rlm@10
|
374 switch(buf[off])
|
rlm@10
|
375 {
|
rlm@10
|
376 case'V':
|
rlm@10
|
377 return VOID_TYPE;
|
rlm@10
|
378 case'Z':
|
rlm@10
|
379 return BOOLEAN_TYPE;
|
rlm@10
|
380 case'C':
|
rlm@10
|
381 return CHAR_TYPE;
|
rlm@10
|
382 case'B':
|
rlm@10
|
383 return BYTE_TYPE;
|
rlm@10
|
384 case'S':
|
rlm@10
|
385 return SHORT_TYPE;
|
rlm@10
|
386 case'I':
|
rlm@10
|
387 return INT_TYPE;
|
rlm@10
|
388 case'F':
|
rlm@10
|
389 return FLOAT_TYPE;
|
rlm@10
|
390 case'J':
|
rlm@10
|
391 return LONG_TYPE;
|
rlm@10
|
392 case'D':
|
rlm@10
|
393 return DOUBLE_TYPE;
|
rlm@10
|
394 case'[':
|
rlm@10
|
395 len = 1;
|
rlm@10
|
396 while(buf[off + len] == '[')
|
rlm@10
|
397 {
|
rlm@10
|
398 ++len;
|
rlm@10
|
399 }
|
rlm@10
|
400 if(buf[off + len] == 'L')
|
rlm@10
|
401 {
|
rlm@10
|
402 ++len;
|
rlm@10
|
403 while(buf[off + len] != ';')
|
rlm@10
|
404 {
|
rlm@10
|
405 ++len;
|
rlm@10
|
406 }
|
rlm@10
|
407 }
|
rlm@10
|
408 return new Type(ARRAY, buf, off, len + 1);
|
rlm@10
|
409 // case 'L':
|
rlm@10
|
410 default:
|
rlm@10
|
411 len = 1;
|
rlm@10
|
412 while(buf[off + len] != ';')
|
rlm@10
|
413 {
|
rlm@10
|
414 ++len;
|
rlm@10
|
415 }
|
rlm@10
|
416 return new Type(OBJECT, buf, off, len + 1);
|
rlm@10
|
417 }
|
rlm@10
|
418 }
|
rlm@10
|
419
|
rlm@10
|
420 // ------------------------------------------------------------------------
|
rlm@10
|
421 // Accessors
|
rlm@10
|
422 // ------------------------------------------------------------------------
|
rlm@10
|
423
|
rlm@10
|
424 /**
|
rlm@10
|
425 * Returns the sort of this Java type.
|
rlm@10
|
426 *
|
rlm@10
|
427 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
|
rlm@10
|
428 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
|
rlm@10
|
429 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
|
rlm@10
|
430 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or
|
rlm@10
|
431 * {@link #OBJECT OBJECT}.
|
rlm@10
|
432 */
|
rlm@10
|
433 public int getSort(){
|
rlm@10
|
434 return sort;
|
rlm@10
|
435 }
|
rlm@10
|
436
|
rlm@10
|
437 /**
|
rlm@10
|
438 * Returns the number of dimensions of this array type. This method should
|
rlm@10
|
439 * only be used for an array type.
|
rlm@10
|
440 *
|
rlm@10
|
441 * @return the number of dimensions of this array type.
|
rlm@10
|
442 */
|
rlm@10
|
443 public int getDimensions(){
|
rlm@10
|
444 int i = 1;
|
rlm@10
|
445 while(buf[off + i] == '[')
|
rlm@10
|
446 {
|
rlm@10
|
447 ++i;
|
rlm@10
|
448 }
|
rlm@10
|
449 return i;
|
rlm@10
|
450 }
|
rlm@10
|
451
|
rlm@10
|
452 /**
|
rlm@10
|
453 * Returns the type of the elements of this array type. This method should
|
rlm@10
|
454 * only be used for an array type.
|
rlm@10
|
455 *
|
rlm@10
|
456 * @return Returns the type of the elements of this array type.
|
rlm@10
|
457 */
|
rlm@10
|
458 public Type getElementType(){
|
rlm@10
|
459 return getType(buf, off + getDimensions());
|
rlm@10
|
460 }
|
rlm@10
|
461
|
rlm@10
|
462 /**
|
rlm@10
|
463 * Returns the name of the class corresponding to this type.
|
rlm@10
|
464 *
|
rlm@10
|
465 * @return the fully qualified name of the class corresponding to this type.
|
rlm@10
|
466 */
|
rlm@10
|
467 public String getClassName(){
|
rlm@10
|
468 switch(sort)
|
rlm@10
|
469 {
|
rlm@10
|
470 case VOID:
|
rlm@10
|
471 return "void";
|
rlm@10
|
472 case BOOLEAN:
|
rlm@10
|
473 return "boolean";
|
rlm@10
|
474 case CHAR:
|
rlm@10
|
475 return "char";
|
rlm@10
|
476 case BYTE:
|
rlm@10
|
477 return "byte";
|
rlm@10
|
478 case SHORT:
|
rlm@10
|
479 return "short";
|
rlm@10
|
480 case INT:
|
rlm@10
|
481 return "int";
|
rlm@10
|
482 case FLOAT:
|
rlm@10
|
483 return "float";
|
rlm@10
|
484 case LONG:
|
rlm@10
|
485 return "long";
|
rlm@10
|
486 case DOUBLE:
|
rlm@10
|
487 return "double";
|
rlm@10
|
488 case ARRAY:
|
rlm@10
|
489 StringBuffer b = new StringBuffer(getElementType().getClassName());
|
rlm@10
|
490 for(int i = getDimensions(); i > 0; --i)
|
rlm@10
|
491 {
|
rlm@10
|
492 b.append("[]");
|
rlm@10
|
493 }
|
rlm@10
|
494 return b.toString();
|
rlm@10
|
495 // case OBJECT:
|
rlm@10
|
496 default:
|
rlm@10
|
497 return new String(buf, off + 1, len - 2).replace('/', '.');
|
rlm@10
|
498 }
|
rlm@10
|
499 }
|
rlm@10
|
500
|
rlm@10
|
501 /**
|
rlm@10
|
502 * Returns the internal name of the class corresponding to this object type.
|
rlm@10
|
503 * The internal name of a class is its fully qualified name, where '.' are
|
rlm@10
|
504 * replaced by '/'. This method should only be used for an object type.
|
rlm@10
|
505 *
|
rlm@10
|
506 * @return the internal name of the class corresponding to this object type.
|
rlm@10
|
507 */
|
rlm@10
|
508 public String getInternalName(){
|
rlm@10
|
509 return new String(buf, off + 1, len - 2);
|
rlm@10
|
510 }
|
rlm@10
|
511
|
rlm@10
|
512 // ------------------------------------------------------------------------
|
rlm@10
|
513 // Conversion to type descriptors
|
rlm@10
|
514 // ------------------------------------------------------------------------
|
rlm@10
|
515
|
rlm@10
|
516 /**
|
rlm@10
|
517 * Returns the descriptor corresponding to this Java type.
|
rlm@10
|
518 *
|
rlm@10
|
519 * @return the descriptor corresponding to this Java type.
|
rlm@10
|
520 */
|
rlm@10
|
521 public String getDescriptor(){
|
rlm@10
|
522 StringBuffer buf = new StringBuffer();
|
rlm@10
|
523 getDescriptor(buf);
|
rlm@10
|
524 return buf.toString();
|
rlm@10
|
525 }
|
rlm@10
|
526
|
rlm@10
|
527 /**
|
rlm@10
|
528 * Returns the descriptor corresponding to the given argument and return
|
rlm@10
|
529 * types.
|
rlm@10
|
530 *
|
rlm@10
|
531 * @param returnType the return type of the method.
|
rlm@10
|
532 * @param argumentTypes the argument types of the method.
|
rlm@10
|
533 * @return the descriptor corresponding to the given argument and return
|
rlm@10
|
534 * types.
|
rlm@10
|
535 */
|
rlm@10
|
536 public static String getMethodDescriptor(
|
rlm@10
|
537 final Type returnType,
|
rlm@10
|
538 final Type[] argumentTypes){
|
rlm@10
|
539 StringBuffer buf = new StringBuffer();
|
rlm@10
|
540 buf.append('(');
|
rlm@10
|
541 for(int i = 0; i < argumentTypes.length; ++i)
|
rlm@10
|
542 {
|
rlm@10
|
543 argumentTypes[i].getDescriptor(buf);
|
rlm@10
|
544 }
|
rlm@10
|
545 buf.append(')');
|
rlm@10
|
546 returnType.getDescriptor(buf);
|
rlm@10
|
547 return buf.toString();
|
rlm@10
|
548 }
|
rlm@10
|
549
|
rlm@10
|
550 /**
|
rlm@10
|
551 * Appends the descriptor corresponding to this Java type to the given
|
rlm@10
|
552 * string buffer.
|
rlm@10
|
553 *
|
rlm@10
|
554 * @param buf the string buffer to which the descriptor must be appended.
|
rlm@10
|
555 */
|
rlm@10
|
556 private void getDescriptor(final StringBuffer buf){
|
rlm@10
|
557 switch(sort)
|
rlm@10
|
558 {
|
rlm@10
|
559 case VOID:
|
rlm@10
|
560 buf.append('V');
|
rlm@10
|
561 return;
|
rlm@10
|
562 case BOOLEAN:
|
rlm@10
|
563 buf.append('Z');
|
rlm@10
|
564 return;
|
rlm@10
|
565 case CHAR:
|
rlm@10
|
566 buf.append('C');
|
rlm@10
|
567 return;
|
rlm@10
|
568 case BYTE:
|
rlm@10
|
569 buf.append('B');
|
rlm@10
|
570 return;
|
rlm@10
|
571 case SHORT:
|
rlm@10
|
572 buf.append('S');
|
rlm@10
|
573 return;
|
rlm@10
|
574 case INT:
|
rlm@10
|
575 buf.append('I');
|
rlm@10
|
576 return;
|
rlm@10
|
577 case FLOAT:
|
rlm@10
|
578 buf.append('F');
|
rlm@10
|
579 return;
|
rlm@10
|
580 case LONG:
|
rlm@10
|
581 buf.append('J');
|
rlm@10
|
582 return;
|
rlm@10
|
583 case DOUBLE:
|
rlm@10
|
584 buf.append('D');
|
rlm@10
|
585 return;
|
rlm@10
|
586 // case ARRAY:
|
rlm@10
|
587 // case OBJECT:
|
rlm@10
|
588 default:
|
rlm@10
|
589 buf.append(this.buf, off, len);
|
rlm@10
|
590 }
|
rlm@10
|
591 }
|
rlm@10
|
592
|
rlm@10
|
593 // ------------------------------------------------------------------------
|
rlm@10
|
594 // Direct conversion from classes to type descriptors,
|
rlm@10
|
595 // without intermediate Type objects
|
rlm@10
|
596 // ------------------------------------------------------------------------
|
rlm@10
|
597
|
rlm@10
|
598 /**
|
rlm@10
|
599 * Returns the internal name of the given class. The internal name of a
|
rlm@10
|
600 * class is its fully qualified name, where '.' are replaced by '/'.
|
rlm@10
|
601 *
|
rlm@10
|
602 * @param c an object class.
|
rlm@10
|
603 * @return the internal name of the given class.
|
rlm@10
|
604 */
|
rlm@10
|
605 public static String getInternalName(final Class c){
|
rlm@10
|
606 return c.getName().replace('.', '/');
|
rlm@10
|
607 }
|
rlm@10
|
608
|
rlm@10
|
609 /**
|
rlm@10
|
610 * Returns the descriptor corresponding to the given Java type.
|
rlm@10
|
611 *
|
rlm@10
|
612 * @param c an object class, a primitive class or an array class.
|
rlm@10
|
613 * @return the descriptor corresponding to the given class.
|
rlm@10
|
614 */
|
rlm@10
|
615 public static String getDescriptor(final Class c){
|
rlm@10
|
616 StringBuffer buf = new StringBuffer();
|
rlm@10
|
617 getDescriptor(buf, c);
|
rlm@10
|
618 return buf.toString();
|
rlm@10
|
619 }
|
rlm@10
|
620
|
rlm@10
|
621 /**
|
rlm@10
|
622 * Returns the descriptor corresponding to the given constructor.
|
rlm@10
|
623 *
|
rlm@10
|
624 * @param c a {@link Constructor Constructor} object.
|
rlm@10
|
625 * @return the descriptor of the given constructor.
|
rlm@10
|
626 */
|
rlm@10
|
627 public static String getConstructorDescriptor(final Constructor c){
|
rlm@10
|
628 Class[] parameters = c.getParameterTypes();
|
rlm@10
|
629 StringBuffer buf = new StringBuffer();
|
rlm@10
|
630 buf.append('(');
|
rlm@10
|
631 for(int i = 0; i < parameters.length; ++i)
|
rlm@10
|
632 {
|
rlm@10
|
633 getDescriptor(buf, parameters[i]);
|
rlm@10
|
634 }
|
rlm@10
|
635 return buf.append(")V").toString();
|
rlm@10
|
636 }
|
rlm@10
|
637
|
rlm@10
|
638 /**
|
rlm@10
|
639 * Returns the descriptor corresponding to the given method.
|
rlm@10
|
640 *
|
rlm@10
|
641 * @param m a {@link Method Method} object.
|
rlm@10
|
642 * @return the descriptor of the given method.
|
rlm@10
|
643 */
|
rlm@10
|
644 public static String getMethodDescriptor(final Method m){
|
rlm@10
|
645 Class[] parameters = m.getParameterTypes();
|
rlm@10
|
646 StringBuffer buf = new StringBuffer();
|
rlm@10
|
647 buf.append('(');
|
rlm@10
|
648 for(int i = 0; i < parameters.length; ++i)
|
rlm@10
|
649 {
|
rlm@10
|
650 getDescriptor(buf, parameters[i]);
|
rlm@10
|
651 }
|
rlm@10
|
652 buf.append(')');
|
rlm@10
|
653 getDescriptor(buf, m.getReturnType());
|
rlm@10
|
654 return buf.toString();
|
rlm@10
|
655 }
|
rlm@10
|
656
|
rlm@10
|
657 /**
|
rlm@10
|
658 * Appends the descriptor of the given class to the given string buffer.
|
rlm@10
|
659 *
|
rlm@10
|
660 * @param buf the string buffer to which the descriptor must be appended.
|
rlm@10
|
661 * @param c the class whose descriptor must be computed.
|
rlm@10
|
662 */
|
rlm@10
|
663 private static void getDescriptor(final StringBuffer buf, final Class c){
|
rlm@10
|
664 Class d = c;
|
rlm@10
|
665 while(true)
|
rlm@10
|
666 {
|
rlm@10
|
667 if(d.isPrimitive())
|
rlm@10
|
668 {
|
rlm@10
|
669 char car;
|
rlm@10
|
670 if(d == Integer.TYPE)
|
rlm@10
|
671 {
|
rlm@10
|
672 car = 'I';
|
rlm@10
|
673 }
|
rlm@10
|
674 else if(d == Void.TYPE)
|
rlm@10
|
675 {
|
rlm@10
|
676 car = 'V';
|
rlm@10
|
677 }
|
rlm@10
|
678 else if(d == Boolean.TYPE)
|
rlm@10
|
679 {
|
rlm@10
|
680 car = 'Z';
|
rlm@10
|
681 }
|
rlm@10
|
682 else if(d == Byte.TYPE)
|
rlm@10
|
683 {
|
rlm@10
|
684 car = 'B';
|
rlm@10
|
685 }
|
rlm@10
|
686 else if(d == Character.TYPE)
|
rlm@10
|
687 {
|
rlm@10
|
688 car = 'C';
|
rlm@10
|
689 }
|
rlm@10
|
690 else if(d == Short.TYPE)
|
rlm@10
|
691 {
|
rlm@10
|
692 car = 'S';
|
rlm@10
|
693 }
|
rlm@10
|
694 else if(d == Double.TYPE)
|
rlm@10
|
695 {
|
rlm@10
|
696 car = 'D';
|
rlm@10
|
697 }
|
rlm@10
|
698 else if(d == Float.TYPE)
|
rlm@10
|
699 {
|
rlm@10
|
700 car = 'F';
|
rlm@10
|
701 }
|
rlm@10
|
702 else /* if (d == Long.TYPE) */
|
rlm@10
|
703 {
|
rlm@10
|
704 car = 'J';
|
rlm@10
|
705 }
|
rlm@10
|
706 buf.append(car);
|
rlm@10
|
707 return;
|
rlm@10
|
708 }
|
rlm@10
|
709 else if(d.isArray())
|
rlm@10
|
710 {
|
rlm@10
|
711 buf.append('[');
|
rlm@10
|
712 d = d.getComponentType();
|
rlm@10
|
713 }
|
rlm@10
|
714 else
|
rlm@10
|
715 {
|
rlm@10
|
716 buf.append('L');
|
rlm@10
|
717 String name = d.getName();
|
rlm@10
|
718 int len = name.length();
|
rlm@10
|
719 for(int i = 0; i < len; ++i)
|
rlm@10
|
720 {
|
rlm@10
|
721 char car = name.charAt(i);
|
rlm@10
|
722 buf.append(car == '.' ? '/' : car);
|
rlm@10
|
723 }
|
rlm@10
|
724 buf.append(';');
|
rlm@10
|
725 return;
|
rlm@10
|
726 }
|
rlm@10
|
727 }
|
rlm@10
|
728 }
|
rlm@10
|
729
|
rlm@10
|
730 // ------------------------------------------------------------------------
|
rlm@10
|
731 // Corresponding size and opcodes
|
rlm@10
|
732 // ------------------------------------------------------------------------
|
rlm@10
|
733
|
rlm@10
|
734 /**
|
rlm@10
|
735 * Returns the size of values of this type.
|
rlm@10
|
736 *
|
rlm@10
|
737 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
|
rlm@10
|
738 * <tt>double</tt>, and 1 otherwise.
|
rlm@10
|
739 */
|
rlm@10
|
740 public int getSize(){
|
rlm@10
|
741 return sort == LONG || sort == DOUBLE ? 2 : 1;
|
rlm@10
|
742 }
|
rlm@10
|
743
|
rlm@10
|
744 /**
|
rlm@10
|
745 * Returns a JVM instruction opcode adapted to this Java type.
|
rlm@10
|
746 *
|
rlm@10
|
747 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
|
rlm@10
|
748 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
|
rlm@10
|
749 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
|
rlm@10
|
750 * @return an opcode that is similar to the given opcode, but adapted to
|
rlm@10
|
751 * this Java type. For example, if this type is <tt>float</tt> and
|
rlm@10
|
752 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
|
rlm@10
|
753 */
|
rlm@10
|
754 public int getOpcode(final int opcode){
|
rlm@10
|
755 if(opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE)
|
rlm@10
|
756 {
|
rlm@10
|
757 switch(sort)
|
rlm@10
|
758 {
|
rlm@10
|
759 case BOOLEAN:
|
rlm@10
|
760 case BYTE:
|
rlm@10
|
761 return opcode + 5;
|
rlm@10
|
762 case CHAR:
|
rlm@10
|
763 return opcode + 6;
|
rlm@10
|
764 case SHORT:
|
rlm@10
|
765 return opcode + 7;
|
rlm@10
|
766 case INT:
|
rlm@10
|
767 return opcode;
|
rlm@10
|
768 case FLOAT:
|
rlm@10
|
769 return opcode + 2;
|
rlm@10
|
770 case LONG:
|
rlm@10
|
771 return opcode + 1;
|
rlm@10
|
772 case DOUBLE:
|
rlm@10
|
773 return opcode + 3;
|
rlm@10
|
774 // case ARRAY:
|
rlm@10
|
775 // case OBJECT:
|
rlm@10
|
776 default:
|
rlm@10
|
777 return opcode + 4;
|
rlm@10
|
778 }
|
rlm@10
|
779 }
|
rlm@10
|
780 else
|
rlm@10
|
781 {
|
rlm@10
|
782 switch(sort)
|
rlm@10
|
783 {
|
rlm@10
|
784 case VOID:
|
rlm@10
|
785 return opcode + 5;
|
rlm@10
|
786 case BOOLEAN:
|
rlm@10
|
787 case CHAR:
|
rlm@10
|
788 case BYTE:
|
rlm@10
|
789 case SHORT:
|
rlm@10
|
790 case INT:
|
rlm@10
|
791 return opcode;
|
rlm@10
|
792 case FLOAT:
|
rlm@10
|
793 return opcode + 2;
|
rlm@10
|
794 case LONG:
|
rlm@10
|
795 return opcode + 1;
|
rlm@10
|
796 case DOUBLE:
|
rlm@10
|
797 return opcode + 3;
|
rlm@10
|
798 // case ARRAY:
|
rlm@10
|
799 // case OBJECT:
|
rlm@10
|
800 default:
|
rlm@10
|
801 return opcode + 4;
|
rlm@10
|
802 }
|
rlm@10
|
803 }
|
rlm@10
|
804 }
|
rlm@10
|
805
|
rlm@10
|
806 // ------------------------------------------------------------------------
|
rlm@10
|
807 // Equals, hashCode and toString
|
rlm@10
|
808 // ------------------------------------------------------------------------
|
rlm@10
|
809
|
rlm@10
|
810 /**
|
rlm@10
|
811 * Tests if the given object is equal to this type.
|
rlm@10
|
812 *
|
rlm@10
|
813 * @param o the object to be compared to this type.
|
rlm@10
|
814 * @return <tt>true</tt> if the given object is equal to this type.
|
rlm@10
|
815 */
|
rlm@10
|
816 public boolean equals(final Object o){
|
rlm@10
|
817 if(this == o)
|
rlm@10
|
818 {
|
rlm@10
|
819 return true;
|
rlm@10
|
820 }
|
rlm@10
|
821 if(!(o instanceof Type))
|
rlm@10
|
822 {
|
rlm@10
|
823 return false;
|
rlm@10
|
824 }
|
rlm@10
|
825 Type t = (Type) o;
|
rlm@10
|
826 if(sort != t.sort)
|
rlm@10
|
827 {
|
rlm@10
|
828 return false;
|
rlm@10
|
829 }
|
rlm@10
|
830 if(sort == Type.OBJECT || sort == Type.ARRAY)
|
rlm@10
|
831 {
|
rlm@10
|
832 if(len != t.len)
|
rlm@10
|
833 {
|
rlm@10
|
834 return false;
|
rlm@10
|
835 }
|
rlm@10
|
836 for(int i = off, j = t.off, end = i + len; i < end; i++, j++)
|
rlm@10
|
837 {
|
rlm@10
|
838 if(buf[i] != t.buf[j])
|
rlm@10
|
839 {
|
rlm@10
|
840 return false;
|
rlm@10
|
841 }
|
rlm@10
|
842 }
|
rlm@10
|
843 }
|
rlm@10
|
844 return true;
|
rlm@10
|
845 }
|
rlm@10
|
846
|
rlm@10
|
847 /**
|
rlm@10
|
848 * Returns a hash code value for this type.
|
rlm@10
|
849 *
|
rlm@10
|
850 * @return a hash code value for this type.
|
rlm@10
|
851 */
|
rlm@10
|
852 public int hashCode(){
|
rlm@10
|
853 int hc = 13 * sort;
|
rlm@10
|
854 if(sort == Type.OBJECT || sort == Type.ARRAY)
|
rlm@10
|
855 {
|
rlm@10
|
856 for(int i = off, end = i + len; i < end; i++)
|
rlm@10
|
857 {
|
rlm@10
|
858 hc = 17 * (hc + buf[i]);
|
rlm@10
|
859 }
|
rlm@10
|
860 }
|
rlm@10
|
861 return hc;
|
rlm@10
|
862 }
|
rlm@10
|
863
|
rlm@10
|
864 /**
|
rlm@10
|
865 * Returns a string representation of this type.
|
rlm@10
|
866 *
|
rlm@10
|
867 * @return the descriptor of this type.
|
rlm@10
|
868 */
|
rlm@10
|
869 public String toString(){
|
rlm@10
|
870 return getDescriptor();
|
rlm@10
|
871 }
|
rlm@10
|
872 }
|