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 org.drools.asm.util;
030:
031: import java.util.HashMap;
032:
033: import org.drools.asm.AnnotationVisitor;
034: import org.drools.asm.Attribute;
035: import org.drools.asm.Label;
036: import org.drools.asm.MethodVisitor;
037: import org.drools.asm.Opcodes;
038: import org.drools.asm.Type;
039: import org.drools.asm.signature.SignatureReader;
040: import org.drools.asm.util.attrs.Traceable;
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 HashMap 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: final AnnotationVisitor av = super .visitAnnotation(desc,
102: visible);
103: if (this .mv != null) {
104: ((TraceAnnotationVisitor) av).av = this .mv.visitAnnotation(
105: desc, visible);
106: }
107: return av;
108: }
109:
110: public void visitAttribute(final Attribute attr) {
111: this .buf.setLength(0);
112: this .buf.append(this .tab).append("ATTRIBUTE ");
113: appendDescriptor(-1, attr.type);
114:
115: if (attr instanceof Traceable) {
116: ((Traceable) attr).trace(this .buf, this .labelNames);
117: } else {
118: this .buf.append(" : ").append(attr.toString()).append("\n");
119: }
120:
121: this .text.add(this .buf.toString());
122: if (this .mv != null) {
123: this .mv.visitAttribute(attr);
124: }
125: }
126:
127: public AnnotationVisitor visitAnnotationDefault() {
128: this .text.add(this .tab2 + "default=");
129: final TraceAnnotationVisitor tav = new TraceAnnotationVisitor();
130: this .text.add(tav.getText());
131: this .text.add("\n");
132: if (this .mv != null) {
133: tav.av = this .mv.visitAnnotationDefault();
134: }
135: return tav;
136: }
137:
138: public AnnotationVisitor visitParameterAnnotation(
139: final int parameter, final String desc,
140: final boolean visible) {
141: this .buf.setLength(0);
142: this .buf.append(this .tab2).append('@');
143: appendDescriptor(TraceAbstractVisitor.FIELD_DESCRIPTOR, desc);
144: this .buf.append('(');
145: this .text.add(this .buf.toString());
146: final TraceAnnotationVisitor tav = new TraceAnnotationVisitor();
147: this .text.add(tav.getText());
148: this .text.add(visible ? ") // parameter "
149: : ") // invisible, parameter ");
150: this .text.add(new Integer(parameter));
151: this .text.add("\n");
152: if (this .mv != null) {
153: tav.av = this .mv.visitParameterAnnotation(parameter, desc,
154: visible);
155: }
156: return tav;
157: }
158:
159: public void visitCode() {
160: if (this .mv != null) {
161: this .mv.visitCode();
162: }
163: }
164:
165: public void visitInsn(final int opcode) {
166: this .buf.setLength(0);
167: this .buf.append(this .tab2).append(
168: AbstractVisitor.OPCODES[opcode]).append('\n');
169: this .text.add(this .buf.toString());
170:
171: if (this .mv != null) {
172: this .mv.visitInsn(opcode);
173: }
174: }
175:
176: public void visitIntInsn(final int opcode, final int operand) {
177: this .buf.setLength(0);
178: this .buf
179: .append(this .tab2)
180: .append(AbstractVisitor.OPCODES[opcode])
181: .append(' ')
182: .append(
183: opcode == Opcodes.NEWARRAY ? AbstractVisitor.TYPES[operand]
184: : Integer.toString(operand)).append(
185: '\n');
186: this .text.add(this .buf.toString());
187:
188: if (this .mv != null) {
189: this .mv.visitIntInsn(opcode, operand);
190: }
191: }
192:
193: public void visitVarInsn(final int opcode, final int var) {
194: this .buf.setLength(0);
195: this .buf.append(this .tab2).append(
196: AbstractVisitor.OPCODES[opcode]).append(' ')
197: .append(var).append('\n');
198: this .text.add(this .buf.toString());
199:
200: if (this .mv != null) {
201: this .mv.visitVarInsn(opcode, var);
202: }
203: }
204:
205: public void visitTypeInsn(final int opcode, final String desc) {
206: this .buf.setLength(0);
207: this .buf.append(this .tab2).append(
208: AbstractVisitor.OPCODES[opcode]).append(' ');
209: if (desc.startsWith("[")) {
210: appendDescriptor(TraceAbstractVisitor.FIELD_DESCRIPTOR,
211: desc);
212: } else {
213: appendDescriptor(TraceAbstractVisitor.INTERNAL_NAME, desc);
214: }
215: this .buf.append('\n');
216: this .text.add(this .buf.toString());
217:
218: if (this .mv != null) {
219: this .mv.visitTypeInsn(opcode, desc);
220: }
221: }
222:
223: public void visitFieldInsn(final int opcode, final String owner,
224: final String name, final String desc) {
225: this .buf.setLength(0);
226: this .buf.append(this .tab2).append(
227: AbstractVisitor.OPCODES[opcode]).append(' ');
228: appendDescriptor(TraceAbstractVisitor.INTERNAL_NAME, owner);
229: this .buf.append('.').append(name).append(" : ");
230: appendDescriptor(TraceAbstractVisitor.FIELD_DESCRIPTOR, desc);
231: this .buf.append('\n');
232: this .text.add(this .buf.toString());
233:
234: if (this .mv != null) {
235: this .mv.visitFieldInsn(opcode, owner, name, desc);
236: }
237: }
238:
239: public void visitMethodInsn(final int opcode, final String owner,
240: final String name, final String desc) {
241: this .buf.setLength(0);
242: this .buf.append(this .tab2).append(
243: AbstractVisitor.OPCODES[opcode]).append(' ');
244: appendDescriptor(TraceAbstractVisitor.INTERNAL_NAME, owner);
245: this .buf.append('.').append(name).append(' ');
246: appendDescriptor(TraceAbstractVisitor.METHOD_DESCRIPTOR, desc);
247: this .buf.append('\n');
248: this .text.add(this .buf.toString());
249:
250: if (this .mv != null) {
251: this .mv.visitMethodInsn(opcode, owner, name, desc);
252: }
253: }
254:
255: public void visitJumpInsn(final int opcode, final Label label) {
256: this .buf.setLength(0);
257: this .buf.append(this .tab2).append(
258: AbstractVisitor.OPCODES[opcode]).append(' ');
259: appendLabel(label);
260: this .buf.append('\n');
261: this .text.add(this .buf.toString());
262:
263: if (this .mv != null) {
264: this .mv.visitJumpInsn(opcode, label);
265: }
266: }
267:
268: public void visitLabel(final Label label) {
269: this .buf.setLength(0);
270: this .buf.append(this .ltab);
271: appendLabel(label);
272: this .buf.append('\n');
273: this .text.add(this .buf.toString());
274:
275: if (this .mv != null) {
276: this .mv.visitLabel(label);
277: }
278: }
279:
280: public void visitLdcInsn(final Object cst) {
281: this .buf.setLength(0);
282: this .buf.append(this .tab2).append("LDC ");
283: if (cst instanceof String) {
284: AbstractVisitor.appendString(this .buf, (String) cst);
285: } else if (cst instanceof Type) {
286: this .buf.append(((Type) cst).getDescriptor() + ".class");
287: } else {
288: this .buf.append(cst);
289: }
290: this .buf.append('\n');
291: this .text.add(this .buf.toString());
292:
293: if (this .mv != null) {
294: this .mv.visitLdcInsn(cst);
295: }
296: }
297:
298: public void visitIincInsn(final int var, final int increment) {
299: this .buf.setLength(0);
300: this .buf.append(this .tab2).append("IINC ").append(var).append(
301: ' ').append(increment).append('\n');
302: this .text.add(this .buf.toString());
303:
304: if (this .mv != null) {
305: this .mv.visitIincInsn(var, increment);
306: }
307: }
308:
309: public void visitTableSwitchInsn(final int min, final int max,
310: final Label dflt, final Label labels[]) {
311: this .buf.setLength(0);
312: this .buf.append(this .tab2).append("TABLESWITCH\n");
313: for (int i = 0; i < labels.length; ++i) {
314: this .buf.append(this .tab3).append(min + i).append(": ");
315: appendLabel(labels[i]);
316: this .buf.append('\n');
317: }
318: this .buf.append(this .tab3).append("default: ");
319: appendLabel(dflt);
320: this .buf.append('\n');
321: this .text.add(this .buf.toString());
322:
323: if (this .mv != null) {
324: this .mv.visitTableSwitchInsn(min, max, dflt, labels);
325: }
326: }
327:
328: public void visitLookupSwitchInsn(final Label dflt,
329: final int keys[], final Label labels[]) {
330: this .buf.setLength(0);
331: this .buf.append(this .tab2).append("LOOKUPSWITCH\n");
332: for (int i = 0; i < labels.length; ++i) {
333: this .buf.append(this .tab3).append(keys[i]).append(": ");
334: appendLabel(labels[i]);
335: this .buf.append('\n');
336: }
337: this .buf.append(this .tab3).append("default: ");
338: appendLabel(dflt);
339: this .buf.append('\n');
340: this .text.add(this .buf.toString());
341:
342: if (this .mv != null) {
343: this .mv.visitLookupSwitchInsn(dflt, keys, labels);
344: }
345: }
346:
347: public void visitMultiANewArrayInsn(final String desc,
348: final int dims) {
349: this .buf.setLength(0);
350: this .buf.append(this .tab2).append("MULTIANEWARRAY ");
351: appendDescriptor(TraceAbstractVisitor.FIELD_DESCRIPTOR, desc);
352: this .buf.append(' ').append(dims).append('\n');
353: this .text.add(this .buf.toString());
354:
355: if (this .mv != null) {
356: this .mv.visitMultiANewArrayInsn(desc, dims);
357: }
358: }
359:
360: public void visitTryCatchBlock(final Label start, final Label end,
361: final Label handler, final String type) {
362: this .buf.setLength(0);
363: this .buf.append(this .tab2).append("TRYCATCHBLOCK ");
364: appendLabel(start);
365: this .buf.append(' ');
366: appendLabel(end);
367: this .buf.append(' ');
368: appendLabel(handler);
369: this .buf.append(' ');
370: appendDescriptor(TraceAbstractVisitor.INTERNAL_NAME, type);
371: this .buf.append('\n');
372: this .text.add(this .buf.toString());
373:
374: if (this .mv != null) {
375: this .mv.visitTryCatchBlock(start, end, handler, type);
376: }
377: }
378:
379: public void visitLocalVariable(final String name,
380: final String desc, final String signature,
381: final Label start, final Label end, final int index) {
382: this .buf.setLength(0);
383: this .buf.append(this .tab2).append("LOCALVARIABLE ")
384: .append(name).append(' ');
385: appendDescriptor(TraceAbstractVisitor.FIELD_DESCRIPTOR, desc);
386: this .buf.append(' ');
387: appendLabel(start);
388: this .buf.append(' ');
389: appendLabel(end);
390: this .buf.append(' ').append(index).append('\n');
391:
392: if (signature != null) {
393: this .buf.append(this .tab2);
394: appendDescriptor(TraceAbstractVisitor.FIELD_SIGNATURE,
395: signature);
396:
397: final TraceSignatureVisitor sv = new TraceSignatureVisitor(
398: 0);
399: final SignatureReader r = new SignatureReader(signature);
400: r.acceptType(sv);
401: this .buf.append(this .tab2).append("// declaration: ")
402: .append(sv.getDeclaration()).append('\n');
403: }
404: this .text.add(this .buf.toString());
405:
406: if (this .mv != null) {
407: this .mv.visitLocalVariable(name, desc, signature, start,
408: end, index);
409: }
410: }
411:
412: public void visitLineNumber(final int line, final Label start) {
413: this .buf.setLength(0);
414: this .buf.append(this .tab2).append("LINENUMBER ").append(line)
415: .append(' ');
416: appendLabel(start);
417: this .buf.append('\n');
418: this .text.add(this .buf.toString());
419:
420: if (this .mv != null) {
421: this .mv.visitLineNumber(line, start);
422: }
423: }
424:
425: public void visitMaxs(final int maxStack, final int maxLocals) {
426: this .buf.setLength(0);
427: this .buf.append(this .tab2).append("MAXSTACK = ").append(
428: maxStack).append('\n');
429: this .text.add(this .buf.toString());
430:
431: this .buf.setLength(0);
432: this .buf.append(this .tab2).append("MAXLOCALS = ").append(
433: maxLocals).append('\n');
434: this .text.add(this .buf.toString());
435:
436: if (this .mv != null) {
437: this .mv.visitMaxs(maxStack, maxLocals);
438: }
439: }
440:
441: public void visitEnd() {
442: super .visitEnd();
443:
444: if (this .mv != null) {
445: this .mv.visitEnd();
446: }
447: }
448:
449: // ------------------------------------------------------------------------
450: // Utility methods
451: // ------------------------------------------------------------------------
452:
453: /**
454: * Appends the name of the given label to {@link #buf buf}. Creates a new
455: * label name if the given label does not yet have one.
456: *
457: * @param l a label.
458: */
459: public void appendLabel(final Label l) {
460: String name = (String) this .labelNames.get(l);
461: if (name == null) {
462: name = "L" + this.labelNames.size();
463: this.labelNames.put(l, name);
464: }
465: this.buf.append(name);
466: }
467: }
|