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