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: */
030: package org.objectweb.asm.util;
031:
032: import org.objectweb.asm.AnnotationVisitor;
033: import org.objectweb.asm.MethodVisitor;
034: import org.objectweb.asm.Label;
035: import org.objectweb.asm.Opcodes;
036:
037: import java.util.HashMap;
038:
039: /**
040: * A {@link MethodVisitor} that prints the ASM code that generates the methods
041: * it visits.
042: *
043: * @author Eric Bruneton
044: * @author Eugene Kuleshov
045: */
046: @SuppressWarnings("unchecked")
047: public class ASMifierMethodVisitor extends ASMifierAbstractVisitor
048: implements MethodVisitor {
049:
050: /**
051: * Constructs a new {@link ASMifierMethodVisitor} object.
052: */
053: public ASMifierMethodVisitor() {
054: super ("mv");
055: this .labelNames = new HashMap();
056: }
057:
058: public AnnotationVisitor visitAnnotationDefault() {
059: buf.setLength(0);
060: buf.append("{\n")
061: .append("av0 = mv.visitAnnotationDefault();\n");
062: text.add(buf.toString());
063: ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
064: text.add(av.getText());
065: text.add("}\n");
066: return av;
067: }
068:
069: public AnnotationVisitor visitParameterAnnotation(
070: final int parameter, final String desc,
071: final boolean visible) {
072: buf.setLength(0);
073: buf.append("{\n").append("av0 = mv.visitParameterAnnotation(")
074: .append(parameter).append(", ");
075: appendConstant(desc);
076: buf.append(", ").append(visible).append(");\n");
077: text.add(buf.toString());
078: ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
079: text.add(av.getText());
080: text.add("}\n");
081: return av;
082: }
083:
084: public void visitCode() {
085: text.add("mv.visitCode();\n");
086: }
087:
088: public void visitFrame(final int type, final int nLocal,
089: final Object[] local, final int nStack, final Object[] stack) {
090: buf.setLength(0);
091: switch (type) {
092: case Opcodes.F_NEW:
093: case Opcodes.F_FULL:
094: declareFrameTypes(nLocal, local);
095: declareFrameTypes(nStack, stack);
096: if (type == Opcodes.F_NEW) {
097: buf.append("mv.visitFrame(Opcodes.F_NEW, ");
098: } else {
099: buf.append("mv.visitFrame(Opcodes.F_FULL, ");
100: }
101: buf.append(nLocal).append(", new Object[] {");
102: appendFrameTypes(nLocal, local);
103: buf.append("}, ").append(nStack).append(", new Object[] {");
104: appendFrameTypes(nStack, stack);
105: buf.append("}");
106: break;
107: case Opcodes.F_APPEND:
108: declareFrameTypes(nLocal, local);
109: buf.append("mv.visitFrame(Opcodes.F_APPEND,")
110: .append(nLocal).append(", new Object[] {");
111: appendFrameTypes(nLocal, local);
112: buf.append("}, 0, null");
113: break;
114: case Opcodes.F_CHOP:
115: buf.append("mv.visitFrame(Opcodes.F_CHOP,").append(nLocal)
116: .append(", null, 0, null");
117: break;
118: case Opcodes.F_SAME:
119: buf
120: .append("mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null");
121: break;
122: case Opcodes.F_SAME1:
123: declareFrameTypes(1, stack);
124: buf
125: .append("mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
126: appendFrameTypes(1, stack);
127: buf.append("}");
128: break;
129: }
130: buf.append(");\n");
131: text.add(buf.toString());
132: }
133:
134: public void visitInsn(final int opcode) {
135: buf.setLength(0);
136: buf.append("mv.visitInsn(").append(OPCODES[opcode]).append(
137: ");\n");
138: text.add(buf.toString());
139: }
140:
141: public void visitIntInsn(final int opcode, final int operand) {
142: buf.setLength(0);
143: buf.append("mv.visitIntInsn(").append(OPCODES[opcode]).append(
144: ", ").append(
145: opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
146: .toString(operand)).append(");\n");
147: text.add(buf.toString());
148: }
149:
150: public void visitVarInsn(final int opcode, final int var) {
151: buf.setLength(0);
152: buf.append("mv.visitVarInsn(").append(OPCODES[opcode]).append(
153: ", ").append(var).append(");\n");
154: text.add(buf.toString());
155: }
156:
157: public void visitTypeInsn(final int opcode, final String desc) {
158: buf.setLength(0);
159: buf.append("mv.visitTypeInsn(").append(OPCODES[opcode]).append(
160: ", ");
161: appendConstant(desc);
162: buf.append(");\n");
163: text.add(buf.toString());
164: }
165:
166: public void visitFieldInsn(final int opcode, final String owner,
167: final String name, final String desc) {
168: buf.setLength(0);
169: buf.append("mv.visitFieldInsn(").append(OPCODES[opcode])
170: .append(", ");
171: appendConstant(owner);
172: buf.append(", ");
173: appendConstant(name);
174: buf.append(", ");
175: appendConstant(desc);
176: buf.append(");\n");
177: text.add(buf.toString());
178: }
179:
180: public void visitMethodInsn(final int opcode, final String owner,
181: final String name, final String desc) {
182: buf.setLength(0);
183: buf.append("mv.visitMethodInsn(").append(OPCODES[opcode])
184: .append(", ");
185: appendConstant(owner);
186: buf.append(", ");
187: appendConstant(name);
188: buf.append(", ");
189: appendConstant(desc);
190: buf.append(");\n");
191: text.add(buf.toString());
192: }
193:
194: public void visitJumpInsn(final int opcode, final Label label) {
195: buf.setLength(0);
196: declareLabel(label);
197: buf.append("mv.visitJumpInsn(").append(OPCODES[opcode]).append(
198: ", ");
199: appendLabel(label);
200: buf.append(");\n");
201: text.add(buf.toString());
202: }
203:
204: public void visitLabel(final Label label) {
205: buf.setLength(0);
206: declareLabel(label);
207: buf.append("mv.visitLabel(");
208: appendLabel(label);
209: buf.append(");\n");
210: text.add(buf.toString());
211: }
212:
213: public void visitLdcInsn(final Object cst) {
214: buf.setLength(0);
215: buf.append("mv.visitLdcInsn(");
216: appendConstant(cst);
217: buf.append(");\n");
218: text.add(buf.toString());
219: }
220:
221: public void visitIincInsn(final int var, final int increment) {
222: buf.setLength(0);
223: buf.append("mv.visitIincInsn(").append(var).append(", ")
224: .append(increment).append(");\n");
225: text.add(buf.toString());
226: }
227:
228: public void visitTableSwitchInsn(final int min, final int max,
229: final Label dflt, final Label labels[]) {
230: buf.setLength(0);
231: for (int i = 0; i < labels.length; ++i) {
232: declareLabel(labels[i]);
233: }
234: declareLabel(dflt);
235:
236: buf.append("mv.visitTableSwitchInsn(").append(min).append(", ")
237: .append(max).append(", ");
238: appendLabel(dflt);
239: buf.append(", new Label[] {");
240: for (int i = 0; i < labels.length; ++i) {
241: buf.append(i == 0 ? " " : ", ");
242: appendLabel(labels[i]);
243: }
244: buf.append(" });\n");
245: text.add(buf.toString());
246: }
247:
248: public void visitLookupSwitchInsn(final Label dflt,
249: final int keys[], final Label labels[]) {
250: buf.setLength(0);
251: for (int i = 0; i < labels.length; ++i) {
252: declareLabel(labels[i]);
253: }
254: declareLabel(dflt);
255:
256: buf.append("mv.visitLookupSwitchInsn(");
257: appendLabel(dflt);
258: buf.append(", new int[] {");
259: for (int i = 0; i < keys.length; ++i) {
260: buf.append(i == 0 ? " " : ", ").append(keys[i]);
261: }
262: buf.append(" }, new Label[] {");
263: for (int i = 0; i < labels.length; ++i) {
264: buf.append(i == 0 ? " " : ", ");
265: appendLabel(labels[i]);
266: }
267: buf.append(" });\n");
268: text.add(buf.toString());
269: }
270:
271: public void visitMultiANewArrayInsn(final String desc,
272: final int dims) {
273: buf.setLength(0);
274: buf.append("mv.visitMultiANewArrayInsn(");
275: appendConstant(desc);
276: buf.append(", ").append(dims).append(");\n");
277: text.add(buf.toString());
278: }
279:
280: public void visitTryCatchBlock(final Label start, final Label end,
281: final Label handler, final String type) {
282: buf.setLength(0);
283: declareLabel(start);
284: declareLabel(end);
285: declareLabel(handler);
286: buf.append("mv.visitTryCatchBlock(");
287: appendLabel(start);
288: buf.append(", ");
289: appendLabel(end);
290: buf.append(", ");
291: appendLabel(handler);
292: buf.append(", ");
293: appendConstant(type);
294: buf.append(");\n");
295: text.add(buf.toString());
296: }
297:
298: public void visitLocalVariable(final String name,
299: final String desc, final String signature,
300: final Label start, final Label end, final int index) {
301: buf.setLength(0);
302: buf.append("mv.visitLocalVariable(");
303: appendConstant(name);
304: buf.append(", ");
305: appendConstant(desc);
306: buf.append(", ");
307: appendConstant(signature);
308: buf.append(", ");
309: appendLabel(start);
310: buf.append(", ");
311: appendLabel(end);
312: buf.append(", ").append(index).append(");\n");
313: text.add(buf.toString());
314: }
315:
316: public void visitLineNumber(final int line, final Label start) {
317: buf.setLength(0);
318: buf.append("mv.visitLineNumber(").append(line).append(", ");
319: appendLabel(start);
320: buf.append(");\n");
321: text.add(buf.toString());
322: }
323:
324: public void visitMaxs(final int maxStack, final int maxLocals) {
325: buf.setLength(0);
326: buf.append("mv.visitMaxs(").append(maxStack).append(", ")
327: .append(maxLocals).append(");\n");
328: text.add(buf.toString());
329: }
330:
331: private void declareFrameTypes(final int n, final Object[] o) {
332: for (int i = 0; i < n; ++i) {
333: if (o[i] instanceof Label) {
334: declareLabel((Label) o[i]);
335: }
336: }
337: }
338:
339: private void appendFrameTypes(final int n, final Object[] o) {
340: for (int i = 0; i < n; ++i) {
341: if (i > 0) {
342: buf.append(", ");
343: }
344: if (o[i] instanceof String) {
345: appendConstant(o[i]);
346: } else if (o[i] instanceof Integer) {
347: switch (((Integer) o[i]).intValue()) {
348: case 0:
349: buf.append("Opcodes.TOP");
350: break;
351: case 1:
352: buf.append("Opcodes.INTEGER");
353: break;
354: case 2:
355: buf.append("Opcodes.FLOAT");
356: break;
357: case 3:
358: buf.append("Opcodes.DOUBLE");
359: break;
360: case 4:
361: buf.append("Opcodes.LONG");
362: break;
363: case 5:
364: buf.append("Opcodes.NULL");
365: break;
366: case 6:
367: buf.append("Opcodes.UNINITIALIZED_THIS");
368: break;
369: }
370: } else {
371: appendLabel((Label) o[i]);
372: }
373: }
374: }
375:
376: /**
377: * Appends a declaration of the given label to {@link #buf buf}. This
378: * declaration is of the form "Label lXXX = new Label();". Does nothing if
379: * the given label has already been declared.
380: *
381: * @param l a label.
382: */
383: private void declareLabel(final Label l) {
384: String name = (String) labelNames.get(l);
385: if (name == null) {
386: name = "l" + labelNames.size();
387: labelNames.put(l, name);
388: buf.append("Label ").append(name).append(
389: " = new Label();\n");
390: }
391: }
392:
393: /**
394: * Appends the name of the given label to {@link #buf buf}. The given label
395: * <i>must</i> already have a name. One way to ensure this is to always
396: * call {@link #declareLabel declared} before calling this method.
397: *
398: * @param l a label.
399: */
400: private void appendLabel(final Label l) {
401: buf.append((String) labelNames.get(l));
402: }
403: }
|