001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package com.tc.asm.util;
030:
031: import com.tc.asm.AnnotationVisitor;
032: import com.tc.asm.Attribute;
033: import com.tc.asm.Label;
034: import com.tc.asm.MethodVisitor;
035: import com.tc.asm.Opcodes;
036: import com.tc.asm.Type;
037: import com.tc.asm.signature.SignatureReader;
038:
039: import java.util.HashMap;
040:
041: /**
042: * A {@link MethodVisitor} that prints a disassembled view of the methods it
043: * visits.
044: *
045: * @author Eric Bruneton
046: */
047: public class TraceMethodVisitor extends TraceAbstractVisitor implements
048: MethodVisitor {
049:
050: /**
051: * The {@link MethodVisitor} to which this visitor delegates calls. May be
052: * <tt>null</tt>.
053: */
054: protected MethodVisitor mv;
055:
056: /**
057: * Tab for bytecode instructions.
058: */
059: protected String tab2 = " ";
060:
061: /**
062: * Tab for table and lookup switch instructions.
063: */
064: protected String tab3 = " ";
065:
066: /**
067: * Tab for labels.
068: */
069: protected String ltab = " ";
070:
071: /**
072: * The label names. This map associate String values to Label keys.
073: */
074: protected final HashMap labelNames;
075:
076: /**
077: * Constructs a new {@link TraceMethodVisitor}.
078: */
079: public TraceMethodVisitor() {
080: this (null);
081: }
082:
083: /**
084: * Constructs a new {@link TraceMethodVisitor}.
085: *
086: * @param mv the {@link MethodVisitor} to which this visitor delegates
087: * calls. May be <tt>null</tt>.
088: */
089: public TraceMethodVisitor(final MethodVisitor mv) {
090: this .labelNames = new HashMap();
091: this .mv = mv;
092: }
093:
094: // ------------------------------------------------------------------------
095: // Implementation of the MethodVisitor interface
096: // ------------------------------------------------------------------------
097:
098: public AnnotationVisitor visitAnnotation(final String desc,
099: final boolean visible) {
100: AnnotationVisitor av = super .visitAnnotation(desc, visible);
101: if (mv != null) {
102: ((TraceAnnotationVisitor) av).av = mv.visitAnnotation(desc,
103: visible);
104: }
105: return av;
106: }
107:
108: public void visitAttribute(final Attribute attr) {
109: buf.setLength(0);
110: buf.append(tab).append("ATTRIBUTE ");
111: appendDescriptor(-1, attr.type);
112:
113: if (attr instanceof Traceable) {
114: ((Traceable) attr).trace(buf, labelNames);
115: } else {
116: buf.append(" : unknown\n");
117: }
118:
119: text.add(buf.toString());
120: if (mv != null) {
121: mv.visitAttribute(attr);
122: }
123: }
124:
125: public AnnotationVisitor visitAnnotationDefault() {
126: text.add(tab2 + "default=");
127: TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
128: text.add(tav.getText());
129: text.add("\n");
130: if (mv != null) {
131: tav.av = mv.visitAnnotationDefault();
132: }
133: return tav;
134: }
135:
136: public AnnotationVisitor visitParameterAnnotation(
137: final int parameter, final String desc,
138: final boolean visible) {
139: buf.setLength(0);
140: buf.append(tab2).append('@');
141: appendDescriptor(FIELD_DESCRIPTOR, desc);
142: buf.append('(');
143: text.add(buf.toString());
144: TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
145: text.add(tav.getText());
146: text.add(visible ? ") // parameter "
147: : ") // invisible, parameter ");
148: text.add(new Integer(parameter));
149: text.add("\n");
150: if (mv != null) {
151: tav.av = mv.visitParameterAnnotation(parameter, desc,
152: visible);
153: }
154: return tav;
155: }
156:
157: public void visitCode() {
158: if (mv != null) {
159: mv.visitCode();
160: }
161: }
162:
163: public void visitFrame(final int type, final int nLocal,
164: final Object[] local, final int nStack, final Object[] stack) {
165: buf.setLength(0);
166: buf.append(ltab);
167: buf.append("FRAME ");
168: switch (type) {
169: case Opcodes.F_NEW:
170: case Opcodes.F_FULL:
171: buf.append("FULL [");
172: appendFrameTypes(nLocal, local);
173: buf.append("] [");
174: appendFrameTypes(nStack, stack);
175: buf.append("]");
176: break;
177: case Opcodes.F_APPEND:
178: buf.append("APPEND [");
179: appendFrameTypes(nLocal, local);
180: buf.append("]");
181: break;
182: case Opcodes.F_CHOP:
183: buf.append("CHOP ").append(nLocal);
184: break;
185: case Opcodes.F_SAME:
186: buf.append("SAME");
187: break;
188: case Opcodes.F_SAME1:
189: buf.append("SAME1 ");
190: appendFrameTypes(1, stack);
191: break;
192: }
193: buf.append("\n");
194: text.add(buf.toString());
195:
196: if (mv != null) {
197: mv.visitFrame(type, nLocal, local, nStack, stack);
198: }
199: }
200:
201: public void visitInsn(final int opcode) {
202: buf.setLength(0);
203: buf.append(tab2).append(OPCODES[opcode]).append('\n');
204: text.add(buf.toString());
205:
206: if (mv != null) {
207: mv.visitInsn(opcode);
208: }
209: }
210:
211: public void visitIntInsn(final int opcode, final int operand) {
212: buf.setLength(0);
213: buf.append(tab2).append(OPCODES[opcode]).append(' ').append(
214: opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
215: .toString(operand)).append('\n');
216: text.add(buf.toString());
217:
218: if (mv != null) {
219: mv.visitIntInsn(opcode, operand);
220: }
221: }
222:
223: public void visitVarInsn(final int opcode, final int var) {
224: buf.setLength(0);
225: buf.append(tab2).append(OPCODES[opcode]).append(' ')
226: .append(var).append('\n');
227: text.add(buf.toString());
228:
229: if (mv != null) {
230: mv.visitVarInsn(opcode, var);
231: }
232: }
233:
234: public void visitTypeInsn(final int opcode, final String desc) {
235: buf.setLength(0);
236: buf.append(tab2).append(OPCODES[opcode]).append(' ');
237: if (desc.startsWith("[")) {
238: appendDescriptor(FIELD_DESCRIPTOR, desc);
239: } else {
240: appendDescriptor(INTERNAL_NAME, desc);
241: }
242: buf.append('\n');
243: text.add(buf.toString());
244:
245: if (mv != null) {
246: mv.visitTypeInsn(opcode, desc);
247: }
248: }
249:
250: public void visitFieldInsn(final int opcode, final String owner,
251: final String name, final String desc) {
252: buf.setLength(0);
253: buf.append(tab2).append(OPCODES[opcode]).append(' ');
254: appendDescriptor(INTERNAL_NAME, owner);
255: buf.append('.').append(name).append(" : ");
256: appendDescriptor(FIELD_DESCRIPTOR, desc);
257: buf.append('\n');
258: text.add(buf.toString());
259:
260: if (mv != null) {
261: mv.visitFieldInsn(opcode, owner, name, desc);
262: }
263: }
264:
265: public void visitMethodInsn(final int opcode, final String owner,
266: final String name, final String desc) {
267: buf.setLength(0);
268: buf.append(tab2).append(OPCODES[opcode]).append(' ');
269: appendDescriptor(INTERNAL_NAME, owner);
270: buf.append('.').append(name).append(' ');
271: appendDescriptor(METHOD_DESCRIPTOR, desc);
272: buf.append('\n');
273: text.add(buf.toString());
274:
275: if (mv != null) {
276: mv.visitMethodInsn(opcode, owner, name, desc);
277: }
278: }
279:
280: public void visitJumpInsn(final int opcode, final Label label) {
281: buf.setLength(0);
282: buf.append(tab2).append(OPCODES[opcode]).append(' ');
283: appendLabel(label);
284: buf.append('\n');
285: text.add(buf.toString());
286:
287: if (mv != null) {
288: mv.visitJumpInsn(opcode, label);
289: }
290: }
291:
292: public void visitLabel(final Label label) {
293: buf.setLength(0);
294: buf.append(ltab);
295: appendLabel(label);
296: buf.append('\n');
297: text.add(buf.toString());
298:
299: if (mv != null) {
300: mv.visitLabel(label);
301: }
302: }
303:
304: public void visitLdcInsn(final Object cst) {
305: buf.setLength(0);
306: buf.append(tab2).append("LDC ");
307: if (cst instanceof String) {
308: AbstractVisitor.appendString(buf, (String) cst);
309: } else if (cst instanceof Type) {
310: buf.append(((Type) cst).getDescriptor() + ".class");
311: } else {
312: buf.append(cst);
313: }
314: buf.append('\n');
315: text.add(buf.toString());
316:
317: if (mv != null) {
318: mv.visitLdcInsn(cst);
319: }
320: }
321:
322: public void visitIincInsn(final int var, final int increment) {
323: buf.setLength(0);
324: buf.append(tab2).append("IINC ").append(var).append(' ')
325: .append(increment).append('\n');
326: text.add(buf.toString());
327:
328: if (mv != null) {
329: mv.visitIincInsn(var, increment);
330: }
331: }
332:
333: public void visitTableSwitchInsn(final int min, final int max,
334: final Label dflt, final Label labels[]) {
335: buf.setLength(0);
336: buf.append(tab2).append("TABLESWITCH\n");
337: for (int i = 0; i < labels.length; ++i) {
338: buf.append(tab3).append(min + i).append(": ");
339: appendLabel(labels[i]);
340: buf.append('\n');
341: }
342: buf.append(tab3).append("default: ");
343: appendLabel(dflt);
344: buf.append('\n');
345: text.add(buf.toString());
346:
347: if (mv != null) {
348: mv.visitTableSwitchInsn(min, max, dflt, labels);
349: }
350: }
351:
352: public void visitLookupSwitchInsn(final Label dflt,
353: final int keys[], final Label labels[]) {
354: buf.setLength(0);
355: buf.append(tab2).append("LOOKUPSWITCH\n");
356: for (int i = 0; i < labels.length; ++i) {
357: buf.append(tab3).append(keys[i]).append(": ");
358: appendLabel(labels[i]);
359: buf.append('\n');
360: }
361: buf.append(tab3).append("default: ");
362: appendLabel(dflt);
363: buf.append('\n');
364: text.add(buf.toString());
365:
366: if (mv != null) {
367: mv.visitLookupSwitchInsn(dflt, keys, labels);
368: }
369: }
370:
371: public void visitMultiANewArrayInsn(final String desc,
372: final int dims) {
373: buf.setLength(0);
374: buf.append(tab2).append("MULTIANEWARRAY ");
375: appendDescriptor(FIELD_DESCRIPTOR, desc);
376: buf.append(' ').append(dims).append('\n');
377: text.add(buf.toString());
378:
379: if (mv != null) {
380: mv.visitMultiANewArrayInsn(desc, dims);
381: }
382: }
383:
384: public void visitTryCatchBlock(final Label start, final Label end,
385: final Label handler, final String type) {
386: buf.setLength(0);
387: buf.append(tab2).append("TRYCATCHBLOCK ");
388: appendLabel(start);
389: buf.append(' ');
390: appendLabel(end);
391: buf.append(' ');
392: appendLabel(handler);
393: buf.append(' ');
394: appendDescriptor(INTERNAL_NAME, type);
395: buf.append('\n');
396: text.add(buf.toString());
397:
398: if (mv != null) {
399: mv.visitTryCatchBlock(start, end, handler, type);
400: }
401: }
402:
403: public void visitLocalVariable(final String name,
404: final String desc, final String signature,
405: final Label start, final Label end, final int index) {
406: buf.setLength(0);
407: buf.append(tab2).append("LOCALVARIABLE ").append(name).append(
408: ' ');
409: appendDescriptor(FIELD_DESCRIPTOR, desc);
410: buf.append(' ');
411: appendLabel(start);
412: buf.append(' ');
413: appendLabel(end);
414: buf.append(' ').append(index).append('\n');
415:
416: if (signature != null) {
417: buf.append(tab2);
418: appendDescriptor(FIELD_SIGNATURE, signature);
419:
420: TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
421: SignatureReader r = new SignatureReader(signature);
422: r.acceptType(sv);
423: buf.append(tab2).append("// declaration: ").append(
424: sv.getDeclaration()).append('\n');
425: }
426: text.add(buf.toString());
427:
428: if (mv != null) {
429: mv.visitLocalVariable(name, desc, signature, start, end,
430: index);
431: }
432: }
433:
434: public void visitLineNumber(final int line, final Label start) {
435: buf.setLength(0);
436: buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
437: appendLabel(start);
438: buf.append('\n');
439: text.add(buf.toString());
440:
441: if (mv != null) {
442: mv.visitLineNumber(line, start);
443: }
444: }
445:
446: public void visitMaxs(final int maxStack, final int maxLocals) {
447: buf.setLength(0);
448: buf.append(tab2).append("MAXSTACK = ").append(maxStack).append(
449: '\n');
450: text.add(buf.toString());
451:
452: buf.setLength(0);
453: buf.append(tab2).append("MAXLOCALS = ").append(maxLocals)
454: .append('\n');
455: text.add(buf.toString());
456:
457: if (mv != null) {
458: mv.visitMaxs(maxStack, maxLocals);
459: }
460: }
461:
462: public void visitEnd() {
463: super .visitEnd();
464:
465: if (mv != null) {
466: mv.visitEnd();
467: }
468: }
469:
470: // ------------------------------------------------------------------------
471: // Utility methods
472: // ------------------------------------------------------------------------
473:
474: private void appendFrameTypes(final int n, final Object[] o) {
475: for (int i = 0; i < n; ++i) {
476: if (i > 0) {
477: buf.append(' ');
478: }
479: if (o[i] instanceof String) {
480: String desc = (String) o[i];
481: if (desc.startsWith("[")) {
482: appendDescriptor(FIELD_DESCRIPTOR, desc);
483: } else {
484: appendDescriptor(INTERNAL_NAME, desc);
485: }
486: } else if (o[i] instanceof Integer) {
487: switch (((Integer) o[i]).intValue()) {
488: case 0:
489: appendDescriptor(FIELD_DESCRIPTOR, "T");
490: break;
491: case 1:
492: appendDescriptor(FIELD_DESCRIPTOR, "I");
493: break;
494: case 2:
495: appendDescriptor(FIELD_DESCRIPTOR, "F");
496: break;
497: case 3:
498: appendDescriptor(FIELD_DESCRIPTOR, "D");
499: break;
500: case 4:
501: appendDescriptor(FIELD_DESCRIPTOR, "J");
502: break;
503: case 5:
504: appendDescriptor(FIELD_DESCRIPTOR, "N");
505: break;
506: case 6:
507: appendDescriptor(FIELD_DESCRIPTOR, "U");
508: break;
509: }
510: } else {
511: appendLabel((Label) o[i]);
512: }
513: }
514: }
515:
516: /**
517: * Appends the name of the given label to {@link #buf buf}. Creates a new
518: * label name if the given label does not yet have one.
519: *
520: * @param l a label.
521: */
522: protected void appendLabel(final Label l) {
523: String name = (String) labelNames.get(l);
524: if (name == null) {
525: name = "L" + labelNames.size();
526: labelNames.put(l, name);
527: }
528: buf.append(name);
529: }
530: }
|