1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.impl.enhancer.classfile;
19
20 import java.util.Stack;
21 import java.util.Map;
22
23
24
25
26 /***
27 * A collection of static methods which manipulate type descriptors
28 */
29 public class Descriptor implements VMConstants {
30 /***
31 * Return the number of words of arguments to the method
32 * based on the method signature
33 */
34 public static int countMethodArgWords(String sig) {
35 if (sig.charAt(0) != '(')
36 throw new InsnError ("not a method signature");
37 int count = 0;
38 for (int idx = 1; sig.charAt(idx) != ')'; idx++) {
39 switch (sig.charAt(idx)) {
40 case 'B':
41 case 'C':
42 case 'S':
43 case 'I':
44 case 'F':
45 case 'Z':
46 count++;
47 break;
48 case 'J':
49 case 'D':
50 count += 2;
51 break;
52 case 'L':
53 count++;
54 idx = sig.indexOf(';', idx);
55 break;
56 case '[':
57 count++;
58 while (sig.charAt(idx) == '[' || sig.charAt(idx) == ']')
59 idx++;
60 if (sig.charAt(idx) == 'L')
61 idx = sig.indexOf(';', idx);
62
63 break;
64 default:
65 throw new InsnError("missing case");
66 }
67 }
68 return count;
69 }
70
71 /***
72 * Return the number of words of return value for the method
73 * based on the method signature
74 */
75 public static int countMethodReturnWords(String sig) {
76 int idx = sig.lastIndexOf(')') + 1;
77 if (idx == 0)
78 throw new InsnError ("not a method signature");
79 switch (sig.charAt(idx)) {
80 case 'J':
81 case 'D':
82 return 2;
83 case 'B':
84 case 'C':
85 case 'S':
86 case 'I':
87 case 'F':
88 case 'Z':
89 case 'L':
90 case '[':
91 return 1;
92 case 'V':
93 return 0;
94 default:
95 throw new InsnError("missing case");
96 }
97 }
98
99 /***
100 * Return the stack descriptor for the result of a method
101 * invocation. Void return values yield "V".
102 */
103 public static String extractResultSig(String methodSig) {
104 return methodSig.substring(methodSig.indexOf(')')+1);
105 }
106
107 /***
108 * Return the stack descriptor for the arguments to a method
109 * invocation (not including any "this" argument)
110 */
111 public static String extractArgSig(String methodSig) {
112 return methodSig.substring(1, methodSig.indexOf(')'));
113 }
114
115 /***
116 * Return the reversed stack descriptor for the arguments to a method
117 * invocation (not including any "this" argument). The top of stack
118 * element will be first.
119 */
120 public static String extractReversedArgSig(String methodSig) {
121 StringBuffer buf = new StringBuffer();;
122 reverseArgSig(buf, methodSig, 1);
123 return buf.toString();
124 }
125
126 /***
127 * Given a StringBuffer, a method descriptor, and a index to the
128 * start of an argument descriptor, append the arguments to the
129 * string buffer in reverse order.
130 */
131 private static void reverseArgSig(StringBuffer buf, String methodSig,
132 int idx) {
133 char c = methodSig.charAt(idx);
134 if (c == ')')
135 return;
136 int startIdx = idx;
137
138 switch(c) {
139 case 'B':
140 case 'C':
141 case 'S':
142 case 'I':
143 case 'F':
144 case 'J':
145 case 'D':
146 case 'Z':
147 idx = idx+1;
148 break;
149 case '[':
150 while (methodSig.charAt(idx) == '[' || methodSig.charAt(idx) == ']')
151 idx++;
152 if (methodSig.charAt(idx) != 'L') {
153 idx++;
154 break;
155 }
156
157 case 'L':
158 idx = methodSig.indexOf(';', idx) + 1;
159 break;
160 default:
161 throw new InsnError("bad signature char");
162 }
163
164 reverseArgSig(buf, methodSig, idx);
165 while (startIdx < idx)
166 buf.append(methodSig.charAt(startIdx++));
167 }
168
169 /***
170 * Return the number of words of a field based on its signature.
171 */
172
173 public static int countFieldWords(String sig) {
174 if (sig == null || sig.length() < 1)
175 throw new InsnError ("not a field signature");
176 switch (sig.charAt(0)) {
177 case 'J':
178 case 'D':
179 return 2;
180 case 'B':
181 case 'C':
182 case 'S':
183 case 'I':
184 case 'F':
185 case 'Z':
186 case 'L':
187 case '[':
188 return 1;
189 default:
190 throw new InsnError("missing case");
191 }
192 }
193
194 /***
195 * Return the element type for the first char in the type descriptor string.
196 */
197
198 public static int elementType(String sig) {
199 if (sig == null || sig.length() < 1)
200 throw new InsnError ("not a value signature");
201 switch(sig.charAt(0)) {
202 case 'B':
203 return T_BOOLEAN;
204 case 'C':
205 return T_CHAR;
206 case 'Z':
207 return T_BYTE;
208 case 'S':
209 return T_SHORT;
210 case 'I':
211 return T_INT;
212 case 'J':
213 return T_LONG;
214 case 'F':
215 return T_FLOAT;
216 case 'D':
217 return T_DOUBLE;
218 case '[':
219 return TC_OBJECT;
220 case 'L':
221 return TC_OBJECT;
222 default:
223 throw new InsnError("bad signature char");
224 }
225 }
226
227 /***
228 * Return the element type descriptor char for the element type.
229 * The element type must be one of the T_ or TC_OBJECT.
230 */
231 public static String elementSig(int valueType) {
232 switch(valueType) {
233 case T_BYTE:
234 return "B";
235 case T_CHAR:
236 return "C";
237 case T_BOOLEAN:
238 return "Z";
239 case T_SHORT:
240 return "S";
241 case T_INT:
242 return "I";
243 case T_LONG:
244 return "J";
245 case T_FLOAT:
246 return "F";
247 case T_DOUBLE:
248 return "D";
249 case TC_OBJECT:
250 return "Ljava/lang/Object;";
251 default:
252 throw new InsnError("bad element type");
253 }
254 }
255
256 /***
257 * Return the number of stack words required for a value of the specified
258 * type on the operand stack.
259 */
260 public static int elementSize(int elementType) {
261 switch(elementType) {
262 case T_LONG:
263 case T_DOUBLE:
264 case T_TWOWORD:
265 return 2;
266 default:
267 return 1;
268 }
269 }
270
271 /***
272 * stackSig is a signature for a list of types on the JVM stack with the
273 * last type in the signature intended to be on the top of JVM stack.
274 * For each type in the signature, pushes an Integer objects identifying
275 * the types on top of the input Stack object.
276 */
277 public static void computeStackTypes(String stackSig, Stack stack) {
278 for (int idx = 0; idx < stackSig.length(); idx++) {
279 int tp = 0;
280 switch(stackSig.charAt(idx)) {
281 case 'B':
282 case 'C':
283 case 'Z':
284 case 'S':
285 case 'I':
286 tp = T_INT;
287 break;
288 case 'F':
289 tp = T_FLOAT;
290 break;
291 case 'J':
292 tp = T_LONG;
293 break;
294 case 'D':
295 tp = T_DOUBLE;
296 break;
297 case '?':
298 tp = T_UNKNOWN;
299 break;
300 case 'W':
301 tp = T_WORD;
302 break;
303 case 'X':
304 tp = T_TWOWORD;
305 break;
306 case 'A':
307
308 tp = TC_OBJECT;
309 break;
310 case '[':
311 tp = TC_OBJECT;
312 while (stackSig.charAt(idx) == '[' || stackSig.charAt(idx) == ']')
313 idx++;
314 if (stackSig.charAt(idx) != 'L')
315 break;
316
317 case 'L':
318 tp = TC_OBJECT;
319 idx = stackSig.indexOf(';', idx);
320 break;
321 default:
322 throw new InsnError("bad signature char");
323 }
324 stack.push(new Integer(tp));
325 }
326 }
327
328 /***
329 * stackSig is a signature for the types on the stack with the last
330 * type in the signature on the top of stack. idx is the index of
331 * the start of a valid signature type element. Return the index of
332 * the next element (which may be past the end of the string).
333 */
334 public static int nextSigElement(String stackSig, int idx) {
335 switch(stackSig.charAt(idx)) {
336 case 'B':
337 case 'C':
338 case 'Z':
339 case 'S':
340 case 'I':
341 case 'F':
342 case 'J':
343 case 'D':
344 break;
345 case '[':
346 while (stackSig.charAt(idx) == '[' || stackSig.charAt(idx) == ']')
347 idx++;
348 if (stackSig.charAt(idx) != 'L')
349 break;
350
351 case 'L':
352 idx = stackSig.indexOf(';', idx);
353 break;
354 default:
355 throw new InsnError("bad signature char");
356 }
357
358 idx++;
359 return idx;
360 }
361
362 /***
363 * classTranslations contains a set of mappings of class names.
364 * For any types within the input signature which appear as keys
365 * in the translation table, change the signature to replace the
366 * original type with the translation. Return a string containing
367 * the original signature with any translations applied.
368 */
369 public static String remapTypes(String sig, Map classTranslations) {
370
371 StringBuffer buf = null;
372
373 for (int idx = 0; idx < sig.length(); idx++) {
374 char c;
375 switch(c = sig.charAt(idx)) {
376 case '[':
377
378 while ((c = sig.charAt(idx)) == '[' || c == ']') {
379 idx++;
380 if (buf != null)
381 buf.append(c);
382 }
383
384
385
386 if (sig.charAt(idx) != 'L')
387 break;
388
389 case 'L':
390
391 idx++;
392 int endIdx = sig.indexOf(';', idx);
393 String typeName = sig.substring(idx, endIdx);
394 String mapTo = (String) classTranslations.get(typeName);
395 if (mapTo != null) {
396
397
398 if (buf == null) {
399 buf = new StringBuffer(sig.length() + 20);
400 buf.append(sig.substring(0,idx-1));
401 }
402 typeName = mapTo;
403 }
404
405 if (buf != null) {
406 buf.append('L');
407 buf.append(typeName);
408 }
409 idx = endIdx;
410 c = ';';
411 break;
412 }
413
414 if (buf != null)
415 buf.append(c);
416 }
417 return (buf == null) ? sig : (buf.toString());
418 }
419
420 /***
421 * classTranslations contains a set of mappings of class names.
422 * Translate the class name (which may be an array class) according
423 * to the entries in the translation table.
424 * Return either the original string if no translation applies or
425 * else the translated string.
426 */
427 public static String translateClass(
428 String cls, Map classTranslations) {
429 if (cls.charAt(0) == '[')
430 return remapTypes(cls, classTranslations);
431 else {
432 String mapTo = (String) classTranslations.get(cls);
433 if (mapTo != null)
434 return mapTo;
435 return cls;
436 }
437 }
438
439 /***
440 * Translates a VM type field signature into a user-format signature.
441 * Just a front for the two argument overload of this method.
442 */
443 public static String userFieldSig(String vmSig) {
444 return userFieldSig(vmSig, 0);
445 }
446
447 /***
448 * Translates a VM type field signature into a user-format signature.
449 */
450 public static String userFieldSig(String vmSig, int idx) {
451 String sigElement = "";
452 int arrayDims = 0;
453 boolean moreSig = true;
454 while (moreSig) {
455 moreSig = false;
456 char c = vmSig.charAt(idx);
457 switch (c) {
458 case 'B':
459 sigElement = "byte";
460 break;
461 case 'C':
462 sigElement = "char";
463 break;
464 case 'Z':
465 sigElement = "boolean";
466 break;
467 case 'S':
468 sigElement = "short";
469 break;
470 case 'I':
471 sigElement = "int";
472 break;
473 case 'F':
474 sigElement = "float";
475 break;
476 case 'J':
477 sigElement = "long";
478 break;
479 case 'D':
480 sigElement = "double";
481 break;
482 case 'V':
483
484
485
486 sigElement = "void";
487 break;
488 case '[':
489 idx++;
490 arrayDims++;
491 moreSig = true;
492 break;
493 case 'L':
494 int nextIdx = vmSig.indexOf(';', idx);
495 sigElement = vmSig.substring(idx+1,nextIdx).replace('/','.');
496 break;
497 default:
498 throw new InsnError("bad signature char");
499 }
500 }
501
502
503 if (arrayDims == 0)
504 return sigElement;
505
506
507 StringBuffer buf = new StringBuffer(sigElement.length()
508 + 2 * arrayDims);
509 buf.append(sigElement);
510 while (arrayDims-- > 0)
511 buf.append("[]");
512
513 return buf.toString();
514 }
515
516 /***
517 * Produce a user consumable representation of a method argument list
518 * from the method signature. The return value is ignored.
519 */
520 public static String userMethodArgs(String methodSig) {
521
522 if (methodSig.charAt(0) != '(')
523 throw new InsnError("Invalid method signature");
524
525 StringBuffer buf = new StringBuffer();
526
527 buf.append('(');
528
529 int idx = 1;
530 boolean firstArg = true;
531 while (methodSig.charAt(idx) != ')') {
532 if (firstArg)
533 firstArg = false;
534 else
535 buf.append(", ");
536
537 buf.append(userFieldSig(methodSig, idx));
538 idx = nextSigElement(methodSig, idx);
539 }
540
541 buf.append(')');
542 return buf.toString();
543 }
544
545 /***
546 * Produce a user consumable representation of a method result type
547 * from the method signature. The argument list is ignored.
548 */
549
550 public static String userMethodResult(String methodSig) {
551
552 if (methodSig.charAt(0) != '(')
553 throw new InsnError("Invalid method signature");
554 return userFieldSig(extractResultSig(methodSig));
555 }
556 }