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