ASMifierMethodVisitor.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package org.mockito.asm.util; 31 32import org.mockito.asm.AnnotationVisitor; 33import org.mockito.asm.Label; 34import org.mockito.asm.MethodVisitor; 35import org.mockito.asm.Opcodes; 36 37import java.util.HashMap; 38 39/** 40 * A {@link MethodVisitor} that prints the ASM code that generates the methods 41 * it visits. 42 * 43 * @author Eric Bruneton 44 * @author Eugene Kuleshov 45 */ 46public class ASMifierMethodVisitor extends ASMifierAbstractVisitor implements 47 MethodVisitor 48{ 49 50 /** 51 * Constructs a new {@link ASMifierMethodVisitor} object. 52 */ 53 public ASMifierMethodVisitor() { 54 super("mv"); 55 this.labelNames = new HashMap(); 56 } 57 58 public AnnotationVisitor visitAnnotationDefault() { 59 buf.setLength(0); 60 buf.append("{\n").append("av0 = mv.visitAnnotationDefault();\n"); 61 text.add(buf.toString()); 62 ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); 63 text.add(av.getText()); 64 text.add("}\n"); 65 return av; 66 } 67 68 public AnnotationVisitor visitParameterAnnotation( 69 final int parameter, 70 final String desc, 71 final boolean visible) 72 { 73 buf.setLength(0); 74 buf.append("{\n") 75 .append("av0 = mv.visitParameterAnnotation(") 76 .append(parameter) 77 .append(", "); 78 appendConstant(desc); 79 buf.append(", ").append(visible).append(");\n"); 80 text.add(buf.toString()); 81 ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0); 82 text.add(av.getText()); 83 text.add("}\n"); 84 return av; 85 } 86 87 public void visitCode() { 88 text.add("mv.visitCode();\n"); 89 } 90 91 public void visitFrame( 92 final int type, 93 final int nLocal, 94 final Object[] local, 95 final int nStack, 96 final Object[] stack) 97 { 98 buf.setLength(0); 99 switch (type) { 100 case Opcodes.F_NEW: 101 case Opcodes.F_FULL: 102 declareFrameTypes(nLocal, local); 103 declareFrameTypes(nStack, stack); 104 if (type == Opcodes.F_NEW) { 105 buf.append("mv.visitFrame(Opcodes.F_NEW, "); 106 } else { 107 buf.append("mv.visitFrame(Opcodes.F_FULL, "); 108 } 109 buf.append(nLocal).append(", new Object[] {"); 110 appendFrameTypes(nLocal, local); 111 buf.append("}, ").append(nStack).append(", new Object[] {"); 112 appendFrameTypes(nStack, stack); 113 buf.append('}'); 114 break; 115 case Opcodes.F_APPEND: 116 declareFrameTypes(nLocal, local); 117 buf.append("mv.visitFrame(Opcodes.F_APPEND,") 118 .append(nLocal) 119 .append(", new Object[] {"); 120 appendFrameTypes(nLocal, local); 121 buf.append("}, 0, null"); 122 break; 123 case Opcodes.F_CHOP: 124 buf.append("mv.visitFrame(Opcodes.F_CHOP,") 125 .append(nLocal) 126 .append(", null, 0, null"); 127 break; 128 case Opcodes.F_SAME: 129 buf.append("mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null"); 130 break; 131 case Opcodes.F_SAME1: 132 declareFrameTypes(1, stack); 133 buf.append("mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); 134 appendFrameTypes(1, stack); 135 buf.append('}'); 136 break; 137 } 138 buf.append(");\n"); 139 text.add(buf.toString()); 140 } 141 142 public void visitInsn(final int opcode) { 143 buf.setLength(0); 144 buf.append("mv.visitInsn(").append(OPCODES[opcode]).append(");\n"); 145 text.add(buf.toString()); 146 } 147 148 public void visitIntInsn(final int opcode, final int operand) { 149 buf.setLength(0); 150 buf.append("mv.visitIntInsn(") 151 .append(OPCODES[opcode]) 152 .append(", ") 153 .append(opcode == Opcodes.NEWARRAY 154 ? TYPES[operand] 155 : Integer.toString(operand)) 156 .append(");\n"); 157 text.add(buf.toString()); 158 } 159 160 public void visitVarInsn(final int opcode, final int var) { 161 buf.setLength(0); 162 buf.append("mv.visitVarInsn(") 163 .append(OPCODES[opcode]) 164 .append(", ") 165 .append(var) 166 .append(");\n"); 167 text.add(buf.toString()); 168 } 169 170 public void visitTypeInsn(final int opcode, final String type) { 171 buf.setLength(0); 172 buf.append("mv.visitTypeInsn(").append(OPCODES[opcode]).append(", "); 173 appendConstant(type); 174 buf.append(");\n"); 175 text.add(buf.toString()); 176 } 177 178 public void visitFieldInsn( 179 final int opcode, 180 final String owner, 181 final String name, 182 final String desc) 183 { 184 buf.setLength(0); 185 buf.append("mv.visitFieldInsn(").append(OPCODES[opcode]).append(", "); 186 appendConstant(owner); 187 buf.append(", "); 188 appendConstant(name); 189 buf.append(", "); 190 appendConstant(desc); 191 buf.append(");\n"); 192 text.add(buf.toString()); 193 } 194 195 public void visitMethodInsn( 196 final int opcode, 197 final String owner, 198 final String name, 199 final String desc) 200 { 201 buf.setLength(0); 202 buf.append("mv.visitMethodInsn(").append(OPCODES[opcode]).append(", "); 203 appendConstant(owner); 204 buf.append(", "); 205 appendConstant(name); 206 buf.append(", "); 207 appendConstant(desc); 208 buf.append(");\n"); 209 text.add(buf.toString()); 210 } 211 212 public void visitJumpInsn(final int opcode, final Label label) { 213 buf.setLength(0); 214 declareLabel(label); 215 buf.append("mv.visitJumpInsn(").append(OPCODES[opcode]).append(", "); 216 appendLabel(label); 217 buf.append(");\n"); 218 text.add(buf.toString()); 219 } 220 221 public void visitLabel(final Label label) { 222 buf.setLength(0); 223 declareLabel(label); 224 buf.append("mv.visitLabel("); 225 appendLabel(label); 226 buf.append(");\n"); 227 text.add(buf.toString()); 228 } 229 230 public void visitLdcInsn(final Object cst) { 231 buf.setLength(0); 232 buf.append("mv.visitLdcInsn("); 233 appendConstant(cst); 234 buf.append(");\n"); 235 text.add(buf.toString()); 236 } 237 238 public void visitIincInsn(final int var, final int increment) { 239 buf.setLength(0); 240 buf.append("mv.visitIincInsn(") 241 .append(var) 242 .append(", ") 243 .append(increment) 244 .append(");\n"); 245 text.add(buf.toString()); 246 } 247 248 public void visitTableSwitchInsn( 249 final int min, 250 final int max, 251 final Label dflt, 252 final Label[] labels) 253 { 254 buf.setLength(0); 255 for (int i = 0; i < labels.length; ++i) { 256 declareLabel(labels[i]); 257 } 258 declareLabel(dflt); 259 260 buf.append("mv.visitTableSwitchInsn(") 261 .append(min) 262 .append(", ") 263 .append(max) 264 .append(", "); 265 appendLabel(dflt); 266 buf.append(", new Label[] {"); 267 for (int i = 0; i < labels.length; ++i) { 268 buf.append(i == 0 ? " " : ", "); 269 appendLabel(labels[i]); 270 } 271 buf.append(" });\n"); 272 text.add(buf.toString()); 273 } 274 275 public void visitLookupSwitchInsn( 276 final Label dflt, 277 final int[] keys, 278 final Label[] labels) 279 { 280 buf.setLength(0); 281 for (int i = 0; i < labels.length; ++i) { 282 declareLabel(labels[i]); 283 } 284 declareLabel(dflt); 285 286 buf.append("mv.visitLookupSwitchInsn("); 287 appendLabel(dflt); 288 buf.append(", new int[] {"); 289 for (int i = 0; i < keys.length; ++i) { 290 buf.append(i == 0 ? " " : ", ").append(keys[i]); 291 } 292 buf.append(" }, new Label[] {"); 293 for (int i = 0; i < labels.length; ++i) { 294 buf.append(i == 0 ? " " : ", "); 295 appendLabel(labels[i]); 296 } 297 buf.append(" });\n"); 298 text.add(buf.toString()); 299 } 300 301 public void visitMultiANewArrayInsn(final String desc, final int dims) { 302 buf.setLength(0); 303 buf.append("mv.visitMultiANewArrayInsn("); 304 appendConstant(desc); 305 buf.append(", ").append(dims).append(");\n"); 306 text.add(buf.toString()); 307 } 308 309 public void visitTryCatchBlock( 310 final Label start, 311 final Label end, 312 final Label handler, 313 final String type) 314 { 315 buf.setLength(0); 316 declareLabel(start); 317 declareLabel(end); 318 declareLabel(handler); 319 buf.append("mv.visitTryCatchBlock("); 320 appendLabel(start); 321 buf.append(", "); 322 appendLabel(end); 323 buf.append(", "); 324 appendLabel(handler); 325 buf.append(", "); 326 appendConstant(type); 327 buf.append(");\n"); 328 text.add(buf.toString()); 329 } 330 331 public void visitLocalVariable( 332 final String name, 333 final String desc, 334 final String signature, 335 final Label start, 336 final Label end, 337 final int index) 338 { 339 buf.setLength(0); 340 buf.append("mv.visitLocalVariable("); 341 appendConstant(name); 342 buf.append(", "); 343 appendConstant(desc); 344 buf.append(", "); 345 appendConstant(signature); 346 buf.append(", "); 347 appendLabel(start); 348 buf.append(", "); 349 appendLabel(end); 350 buf.append(", ").append(index).append(");\n"); 351 text.add(buf.toString()); 352 } 353 354 public void visitLineNumber(final int line, final Label start) { 355 buf.setLength(0); 356 buf.append("mv.visitLineNumber(").append(line).append(", "); 357 appendLabel(start); 358 buf.append(");\n"); 359 text.add(buf.toString()); 360 } 361 362 public void visitMaxs(final int maxStack, final int maxLocals) { 363 buf.setLength(0); 364 buf.append("mv.visitMaxs(") 365 .append(maxStack) 366 .append(", ") 367 .append(maxLocals) 368 .append(");\n"); 369 text.add(buf.toString()); 370 } 371 372 private void declareFrameTypes(final int n, final Object[] o) { 373 for (int i = 0; i < n; ++i) { 374 if (o[i] instanceof Label) { 375 declareLabel((Label) o[i]); 376 } 377 } 378 } 379 380 private void appendFrameTypes(final int n, final Object[] o) { 381 for (int i = 0; i < n; ++i) { 382 if (i > 0) { 383 buf.append(", "); 384 } 385 if (o[i] instanceof String) { 386 appendConstant(o[i]); 387 } else if (o[i] instanceof Integer) { 388 switch (((Integer) o[i]).intValue()) { 389 case 0: 390 buf.append("Opcodes.TOP"); 391 break; 392 case 1: 393 buf.append("Opcodes.INTEGER"); 394 break; 395 case 2: 396 buf.append("Opcodes.FLOAT"); 397 break; 398 case 3: 399 buf.append("Opcodes.DOUBLE"); 400 break; 401 case 4: 402 buf.append("Opcodes.LONG"); 403 break; 404 case 5: 405 buf.append("Opcodes.NULL"); 406 break; 407 case 6: 408 buf.append("Opcodes.UNINITIALIZED_THIS"); 409 break; 410 } 411 } else { 412 appendLabel((Label) o[i]); 413 } 414 } 415 } 416 417 /** 418 * Appends a declaration of the given label to {@link #buf buf}. This 419 * declaration is of the form "Label lXXX = new Label();". Does nothing if 420 * the given label has already been declared. 421 * 422 * @param l a label. 423 */ 424 private void declareLabel(final Label l) { 425 String name = (String) labelNames.get(l); 426 if (name == null) { 427 name = "l" + labelNames.size(); 428 labelNames.put(l, name); 429 buf.append("Label ").append(name).append(" = new Label();\n"); 430 } 431 } 432 433 /** 434 * Appends the name of the given label to {@link #buf buf}. The given label 435 * <i>must</i> already have a name. One way to ensure this is to always 436 * call {@link #declareLabel declared} before calling this method. 437 * 438 * @param l a label. 439 */ 440 private void appendLabel(final Label l) { 441 buf.append((String) labelNames.get(l)); 442 } 443} 444