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