annotate src/clojure/asm/commons/AdviceAdapter.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 /***
rlm@10 2 * ASM: a very small and fast Java bytecode manipulation framework
rlm@10 3 * Copyright (c) 2000-2005 INRIA, France Telecom
rlm@10 4 * All rights reserved.
rlm@10 5 *
rlm@10 6 * Redistribution and use in source and binary forms, with or without
rlm@10 7 * modification, are permitted provided that the following conditions
rlm@10 8 * are met:
rlm@10 9 * 1. Redistributions of source code must retain the above copyright
rlm@10 10 * notice, this list of conditions and the following disclaimer.
rlm@10 11 * 2. Redistributions in binary form must reproduce the above copyright
rlm@10 12 * notice, this list of conditions and the following disclaimer in the
rlm@10 13 * documentation and/or other materials provided with the distribution.
rlm@10 14 * 3. Neither the name of the copyright holders nor the names of its
rlm@10 15 * contributors may be used to endorse or promote products derived from
rlm@10 16 * this software without specific prior written permission.
rlm@10 17 *
rlm@10 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
rlm@10 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
rlm@10 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
rlm@10 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
rlm@10 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
rlm@10 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
rlm@10 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
rlm@10 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
rlm@10 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
rlm@10 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
rlm@10 28 * THE POSSIBILITY OF SUCH DAMAGE.
rlm@10 29 */
rlm@10 30 package clojure.asm.commons;
rlm@10 31
rlm@10 32 import java.util.ArrayList;
rlm@10 33 import java.util.HashMap;
rlm@10 34
rlm@10 35 import clojure.asm.Label;
rlm@10 36 import clojure.asm.MethodVisitor;
rlm@10 37 import clojure.asm.Opcodes;
rlm@10 38 import clojure.asm.Type;
rlm@10 39
rlm@10 40 /**
rlm@10 41 * A {@link clojure.asm.MethodAdapter} to insert before, after and around
rlm@10 42 * advices in methods and constructors. <p> The behavior for constructors is
rlm@10 43 * like this: <ol>
rlm@10 44 * <p/>
rlm@10 45 * <li>as long as the INVOKESPECIAL for the object initialization has not been
rlm@10 46 * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
rlm@10 47 * <p/>
rlm@10 48 * <li>when this one is reached, it is only added in the ctor code visitor and
rlm@10 49 * a JP invoke is added</li>
rlm@10 50 * <p/>
rlm@10 51 * <li>after that, only the other code visitor receives the instructions</li>
rlm@10 52 * <p/>
rlm@10 53 * </ol>
rlm@10 54 *
rlm@10 55 * @author Eugene Kuleshov
rlm@10 56 * @author Eric Bruneton
rlm@10 57 */
rlm@10 58 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes{
rlm@10 59 private static final Object THIS = new Object();
rlm@10 60 private static final Object OTHER = new Object();
rlm@10 61
rlm@10 62 protected int methodAccess;
rlm@10 63 protected String methodDesc;
rlm@10 64
rlm@10 65 private boolean constructor;
rlm@10 66 private boolean superInitialized;
rlm@10 67 private ArrayList stackFrame;
rlm@10 68 private HashMap branches;
rlm@10 69
rlm@10 70 /**
rlm@10 71 * Creates a new {@link AdviceAdapter}.
rlm@10 72 *
rlm@10 73 * @param mv the method visitor to which this adapter delegates calls.
rlm@10 74 * @param access the method's access flags (see {@link Opcodes}).
rlm@10 75 * @param name the method's name.
rlm@10 76 * @param desc the method's descriptor (see {@link Type Type}).
rlm@10 77 */
rlm@10 78 public AdviceAdapter(
rlm@10 79 final MethodVisitor mv,
rlm@10 80 final int access,
rlm@10 81 final String name,
rlm@10 82 final String desc){
rlm@10 83 super(mv, access, name, desc);
rlm@10 84 methodAccess = access;
rlm@10 85 methodDesc = desc;
rlm@10 86
rlm@10 87 constructor = "<init>".equals(name);
rlm@10 88 }
rlm@10 89
rlm@10 90 public void visitCode(){
rlm@10 91 mv.visitCode();
rlm@10 92 if(!constructor)
rlm@10 93 {
rlm@10 94 superInitialized = true;
rlm@10 95 onMethodEnter();
rlm@10 96 }
rlm@10 97 else
rlm@10 98 {
rlm@10 99 stackFrame = new ArrayList();
rlm@10 100 branches = new HashMap();
rlm@10 101 }
rlm@10 102 }
rlm@10 103
rlm@10 104 public void visitLabel(final Label label){
rlm@10 105 mv.visitLabel(label);
rlm@10 106
rlm@10 107 if(constructor && branches != null)
rlm@10 108 {
rlm@10 109 ArrayList frame = (ArrayList) branches.get(label);
rlm@10 110 if(frame != null)
rlm@10 111 {
rlm@10 112 stackFrame = frame;
rlm@10 113 branches.remove(label);
rlm@10 114 }
rlm@10 115 }
rlm@10 116 }
rlm@10 117
rlm@10 118 public void visitInsn(final int opcode){
rlm@10 119 if(constructor)
rlm@10 120 {
rlm@10 121 switch(opcode)
rlm@10 122 {
rlm@10 123 case RETURN: // empty stack
rlm@10 124 onMethodExit(opcode);
rlm@10 125 break;
rlm@10 126
rlm@10 127 case IRETURN: // 1 before n/a after
rlm@10 128 case FRETURN: // 1 before n/a after
rlm@10 129 case ARETURN: // 1 before n/a after
rlm@10 130 case ATHROW: // 1 before n/a after
rlm@10 131 popValue();
rlm@10 132 popValue();
rlm@10 133 onMethodExit(opcode);
rlm@10 134 break;
rlm@10 135
rlm@10 136 case LRETURN: // 2 before n/a after
rlm@10 137 case DRETURN: // 2 before n/a after
rlm@10 138 popValue();
rlm@10 139 popValue();
rlm@10 140 onMethodExit(opcode);
rlm@10 141 break;
rlm@10 142
rlm@10 143 case NOP:
rlm@10 144 case LALOAD: // remove 2 add 2
rlm@10 145 case DALOAD: // remove 2 add 2
rlm@10 146 case LNEG:
rlm@10 147 case DNEG:
rlm@10 148 case FNEG:
rlm@10 149 case INEG:
rlm@10 150 case L2D:
rlm@10 151 case D2L:
rlm@10 152 case F2I:
rlm@10 153 case I2B:
rlm@10 154 case I2C:
rlm@10 155 case I2S:
rlm@10 156 case I2F:
rlm@10 157 case Opcodes.ARRAYLENGTH:
rlm@10 158 break;
rlm@10 159
rlm@10 160 case ACONST_NULL:
rlm@10 161 case ICONST_M1:
rlm@10 162 case ICONST_0:
rlm@10 163 case ICONST_1:
rlm@10 164 case ICONST_2:
rlm@10 165 case ICONST_3:
rlm@10 166 case ICONST_4:
rlm@10 167 case ICONST_5:
rlm@10 168 case FCONST_0:
rlm@10 169 case FCONST_1:
rlm@10 170 case FCONST_2:
rlm@10 171 case F2L: // 1 before 2 after
rlm@10 172 case F2D:
rlm@10 173 case I2L:
rlm@10 174 case I2D:
rlm@10 175 pushValue(OTHER);
rlm@10 176 break;
rlm@10 177
rlm@10 178 case LCONST_0:
rlm@10 179 case LCONST_1:
rlm@10 180 case DCONST_0:
rlm@10 181 case DCONST_1:
rlm@10 182 pushValue(OTHER);
rlm@10 183 pushValue(OTHER);
rlm@10 184 break;
rlm@10 185
rlm@10 186 case IALOAD: // remove 2 add 1
rlm@10 187 case FALOAD: // remove 2 add 1
rlm@10 188 case AALOAD: // remove 2 add 1
rlm@10 189 case BALOAD: // remove 2 add 1
rlm@10 190 case CALOAD: // remove 2 add 1
rlm@10 191 case SALOAD: // remove 2 add 1
rlm@10 192 case POP:
rlm@10 193 case IADD:
rlm@10 194 case FADD:
rlm@10 195 case ISUB:
rlm@10 196 case LSHL: // 3 before 2 after
rlm@10 197 case LSHR: // 3 before 2 after
rlm@10 198 case LUSHR: // 3 before 2 after
rlm@10 199 case L2I: // 2 before 1 after
rlm@10 200 case L2F: // 2 before 1 after
rlm@10 201 case D2I: // 2 before 1 after
rlm@10 202 case D2F: // 2 before 1 after
rlm@10 203 case FSUB:
rlm@10 204 case FMUL:
rlm@10 205 case FDIV:
rlm@10 206 case FREM:
rlm@10 207 case FCMPL: // 2 before 1 after
rlm@10 208 case FCMPG: // 2 before 1 after
rlm@10 209 case IMUL:
rlm@10 210 case IDIV:
rlm@10 211 case IREM:
rlm@10 212 case ISHL:
rlm@10 213 case ISHR:
rlm@10 214 case IUSHR:
rlm@10 215 case IAND:
rlm@10 216 case IOR:
rlm@10 217 case IXOR:
rlm@10 218 case MONITORENTER:
rlm@10 219 case MONITOREXIT:
rlm@10 220 popValue();
rlm@10 221 break;
rlm@10 222
rlm@10 223 case POP2:
rlm@10 224 case LSUB:
rlm@10 225 case LMUL:
rlm@10 226 case LDIV:
rlm@10 227 case LREM:
rlm@10 228 case LADD:
rlm@10 229 case LAND:
rlm@10 230 case LOR:
rlm@10 231 case LXOR:
rlm@10 232 case DADD:
rlm@10 233 case DMUL:
rlm@10 234 case DSUB:
rlm@10 235 case DDIV:
rlm@10 236 case DREM:
rlm@10 237 popValue();
rlm@10 238 popValue();
rlm@10 239 break;
rlm@10 240
rlm@10 241 case IASTORE:
rlm@10 242 case FASTORE:
rlm@10 243 case AASTORE:
rlm@10 244 case BASTORE:
rlm@10 245 case CASTORE:
rlm@10 246 case SASTORE:
rlm@10 247 case LCMP: // 4 before 1 after
rlm@10 248 case DCMPL:
rlm@10 249 case DCMPG:
rlm@10 250 popValue();
rlm@10 251 popValue();
rlm@10 252 popValue();
rlm@10 253 break;
rlm@10 254
rlm@10 255 case LASTORE:
rlm@10 256 case DASTORE:
rlm@10 257 popValue();
rlm@10 258 popValue();
rlm@10 259 popValue();
rlm@10 260 popValue();
rlm@10 261 break;
rlm@10 262
rlm@10 263 case DUP:
rlm@10 264 pushValue(peekValue());
rlm@10 265 break;
rlm@10 266
rlm@10 267 case DUP_X1:
rlm@10 268 // TODO optimize this
rlm@10 269 {
rlm@10 270 Object o1 = popValue();
rlm@10 271 Object o2 = popValue();
rlm@10 272 pushValue(o1);
rlm@10 273 pushValue(o2);
rlm@10 274 pushValue(o1);
rlm@10 275 }
rlm@10 276 break;
rlm@10 277
rlm@10 278 case DUP_X2:
rlm@10 279 // TODO optimize this
rlm@10 280 {
rlm@10 281 Object o1 = popValue();
rlm@10 282 Object o2 = popValue();
rlm@10 283 Object o3 = popValue();
rlm@10 284 pushValue(o1);
rlm@10 285 pushValue(o3);
rlm@10 286 pushValue(o2);
rlm@10 287 pushValue(o1);
rlm@10 288 }
rlm@10 289 break;
rlm@10 290
rlm@10 291 case DUP2:
rlm@10 292 // TODO optimize this
rlm@10 293 {
rlm@10 294 Object o1 = popValue();
rlm@10 295 Object o2 = popValue();
rlm@10 296 pushValue(o2);
rlm@10 297 pushValue(o1);
rlm@10 298 pushValue(o2);
rlm@10 299 pushValue(o1);
rlm@10 300 }
rlm@10 301 break;
rlm@10 302
rlm@10 303 case DUP2_X1:
rlm@10 304 // TODO optimize this
rlm@10 305 {
rlm@10 306 Object o1 = popValue();
rlm@10 307 Object o2 = popValue();
rlm@10 308 Object o3 = popValue();
rlm@10 309 pushValue(o2);
rlm@10 310 pushValue(o1);
rlm@10 311 pushValue(o3);
rlm@10 312 pushValue(o2);
rlm@10 313 pushValue(o1);
rlm@10 314 }
rlm@10 315 break;
rlm@10 316
rlm@10 317 case DUP2_X2:
rlm@10 318 // TODO optimize this
rlm@10 319 {
rlm@10 320 Object o1 = popValue();
rlm@10 321 Object o2 = popValue();
rlm@10 322 Object o3 = popValue();
rlm@10 323 Object o4 = popValue();
rlm@10 324 pushValue(o2);
rlm@10 325 pushValue(o1);
rlm@10 326 pushValue(o4);
rlm@10 327 pushValue(o3);
rlm@10 328 pushValue(o2);
rlm@10 329 pushValue(o1);
rlm@10 330 }
rlm@10 331 break;
rlm@10 332
rlm@10 333 case SWAP:
rlm@10 334 {
rlm@10 335 Object o1 = popValue();
rlm@10 336 Object o2 = popValue();
rlm@10 337 pushValue(o1);
rlm@10 338 pushValue(o2);
rlm@10 339 }
rlm@10 340 break;
rlm@10 341 }
rlm@10 342 }
rlm@10 343 else
rlm@10 344 {
rlm@10 345 switch(opcode)
rlm@10 346 {
rlm@10 347 case RETURN:
rlm@10 348 case IRETURN:
rlm@10 349 case FRETURN:
rlm@10 350 case ARETURN:
rlm@10 351 case LRETURN:
rlm@10 352 case DRETURN:
rlm@10 353 case ATHROW:
rlm@10 354 onMethodExit(opcode);
rlm@10 355 break;
rlm@10 356 }
rlm@10 357 }
rlm@10 358 mv.visitInsn(opcode);
rlm@10 359 }
rlm@10 360
rlm@10 361 public void visitVarInsn(final int opcode, final int var){
rlm@10 362 super.visitVarInsn(opcode, var);
rlm@10 363
rlm@10 364 if(constructor)
rlm@10 365 {
rlm@10 366 switch(opcode)
rlm@10 367 {
rlm@10 368 case ILOAD:
rlm@10 369 case FLOAD:
rlm@10 370 pushValue(OTHER);
rlm@10 371 break;
rlm@10 372 case LLOAD:
rlm@10 373 case DLOAD:
rlm@10 374 pushValue(OTHER);
rlm@10 375 pushValue(OTHER);
rlm@10 376 break;
rlm@10 377 case ALOAD:
rlm@10 378 pushValue(var == 0 ? THIS : OTHER);
rlm@10 379 break;
rlm@10 380 case ASTORE:
rlm@10 381 case ISTORE:
rlm@10 382 case FSTORE:
rlm@10 383 popValue();
rlm@10 384 break;
rlm@10 385 case LSTORE:
rlm@10 386 case DSTORE:
rlm@10 387 popValue();
rlm@10 388 popValue();
rlm@10 389 break;
rlm@10 390 }
rlm@10 391 }
rlm@10 392 }
rlm@10 393
rlm@10 394 public void visitFieldInsn(
rlm@10 395 final int opcode,
rlm@10 396 final String owner,
rlm@10 397 final String name,
rlm@10 398 final String desc){
rlm@10 399 mv.visitFieldInsn(opcode, owner, name, desc);
rlm@10 400
rlm@10 401 if(constructor)
rlm@10 402 {
rlm@10 403 char c = desc.charAt(0);
rlm@10 404 boolean longOrDouble = c == 'J' || c == 'D';
rlm@10 405 switch(opcode)
rlm@10 406 {
rlm@10 407 case GETSTATIC:
rlm@10 408 pushValue(OTHER);
rlm@10 409 if(longOrDouble)
rlm@10 410 {
rlm@10 411 pushValue(OTHER);
rlm@10 412 }
rlm@10 413 break;
rlm@10 414 case PUTSTATIC:
rlm@10 415 popValue();
rlm@10 416 if(longOrDouble)
rlm@10 417 {
rlm@10 418 popValue();
rlm@10 419 }
rlm@10 420 break;
rlm@10 421 case PUTFIELD:
rlm@10 422 popValue();
rlm@10 423 if(longOrDouble)
rlm@10 424 {
rlm@10 425 popValue();
rlm@10 426 popValue();
rlm@10 427 }
rlm@10 428 break;
rlm@10 429 // case GETFIELD:
rlm@10 430 default:
rlm@10 431 if(longOrDouble)
rlm@10 432 {
rlm@10 433 pushValue(OTHER);
rlm@10 434 }
rlm@10 435 }
rlm@10 436 }
rlm@10 437 }
rlm@10 438
rlm@10 439 public void visitIntInsn(final int opcode, final int operand){
rlm@10 440 mv.visitIntInsn(opcode, operand);
rlm@10 441
rlm@10 442 if(constructor && opcode != NEWARRAY)
rlm@10 443 {
rlm@10 444 pushValue(OTHER);
rlm@10 445 }
rlm@10 446 }
rlm@10 447
rlm@10 448 public void visitLdcInsn(final Object cst){
rlm@10 449 mv.visitLdcInsn(cst);
rlm@10 450
rlm@10 451 if(constructor)
rlm@10 452 {
rlm@10 453 pushValue(OTHER);
rlm@10 454 if(cst instanceof Double || cst instanceof Long)
rlm@10 455 {
rlm@10 456 pushValue(OTHER);
rlm@10 457 }
rlm@10 458 }
rlm@10 459 }
rlm@10 460
rlm@10 461 public void visitMultiANewArrayInsn(final String desc, final int dims){
rlm@10 462 mv.visitMultiANewArrayInsn(desc, dims);
rlm@10 463
rlm@10 464 if(constructor)
rlm@10 465 {
rlm@10 466 for(int i = 0; i < dims; i++)
rlm@10 467 {
rlm@10 468 popValue();
rlm@10 469 }
rlm@10 470 pushValue(OTHER);
rlm@10 471 }
rlm@10 472 }
rlm@10 473
rlm@10 474 public void visitTypeInsn(final int opcode, final String name){
rlm@10 475 mv.visitTypeInsn(opcode, name);
rlm@10 476
rlm@10 477 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
rlm@10 478 if(constructor && opcode == NEW)
rlm@10 479 {
rlm@10 480 pushValue(OTHER);
rlm@10 481 }
rlm@10 482 }
rlm@10 483
rlm@10 484 public void visitMethodInsn(
rlm@10 485 final int opcode,
rlm@10 486 final String owner,
rlm@10 487 final String name,
rlm@10 488 final String desc){
rlm@10 489 mv.visitMethodInsn(opcode, owner, name, desc);
rlm@10 490
rlm@10 491 if(constructor)
rlm@10 492 {
rlm@10 493 Type[] types = Type.getArgumentTypes(desc);
rlm@10 494 for(int i = 0; i < types.length; i++)
rlm@10 495 {
rlm@10 496 popValue();
rlm@10 497 if(types[i].getSize() == 2)
rlm@10 498 {
rlm@10 499 popValue();
rlm@10 500 }
rlm@10 501 }
rlm@10 502 switch(opcode)
rlm@10 503 {
rlm@10 504 // case INVOKESTATIC:
rlm@10 505 // break;
rlm@10 506
rlm@10 507 case INVOKEINTERFACE:
rlm@10 508 case INVOKEVIRTUAL:
rlm@10 509 popValue(); // objectref
rlm@10 510 break;
rlm@10 511
rlm@10 512 case INVOKESPECIAL:
rlm@10 513 Object type = popValue(); // objectref
rlm@10 514 if(type == THIS && !superInitialized)
rlm@10 515 {
rlm@10 516 onMethodEnter();
rlm@10 517 superInitialized = true;
rlm@10 518 // once super has been initialized it is no longer
rlm@10 519 // necessary to keep track of stack state
rlm@10 520 constructor = false;
rlm@10 521 }
rlm@10 522 break;
rlm@10 523 }
rlm@10 524
rlm@10 525 Type returnType = Type.getReturnType(desc);
rlm@10 526 if(returnType != Type.VOID_TYPE)
rlm@10 527 {
rlm@10 528 pushValue(OTHER);
rlm@10 529 if(returnType.getSize() == 2)
rlm@10 530 {
rlm@10 531 pushValue(OTHER);
rlm@10 532 }
rlm@10 533 }
rlm@10 534 }
rlm@10 535 }
rlm@10 536
rlm@10 537 public void visitJumpInsn(final int opcode, final Label label){
rlm@10 538 mv.visitJumpInsn(opcode, label);
rlm@10 539
rlm@10 540 if(constructor)
rlm@10 541 {
rlm@10 542 switch(opcode)
rlm@10 543 {
rlm@10 544 case IFEQ:
rlm@10 545 case IFNE:
rlm@10 546 case IFLT:
rlm@10 547 case IFGE:
rlm@10 548 case IFGT:
rlm@10 549 case IFLE:
rlm@10 550 case IFNULL:
rlm@10 551 case IFNONNULL:
rlm@10 552 popValue();
rlm@10 553 break;
rlm@10 554
rlm@10 555 case IF_ICMPEQ:
rlm@10 556 case IF_ICMPNE:
rlm@10 557 case IF_ICMPLT:
rlm@10 558 case IF_ICMPGE:
rlm@10 559 case IF_ICMPGT:
rlm@10 560 case IF_ICMPLE:
rlm@10 561 case IF_ACMPEQ:
rlm@10 562 case IF_ACMPNE:
rlm@10 563 popValue();
rlm@10 564 popValue();
rlm@10 565 break;
rlm@10 566
rlm@10 567 case JSR:
rlm@10 568 pushValue(OTHER);
rlm@10 569 break;
rlm@10 570 }
rlm@10 571 addBranch(label);
rlm@10 572 }
rlm@10 573 }
rlm@10 574
rlm@10 575 public void visitLookupSwitchInsn(
rlm@10 576 final Label dflt,
rlm@10 577 final int[] keys,
rlm@10 578 final Label[] labels){
rlm@10 579 mv.visitLookupSwitchInsn(dflt, keys, labels);
rlm@10 580
rlm@10 581 if(constructor)
rlm@10 582 {
rlm@10 583 popValue();
rlm@10 584 addBranches(dflt, labels);
rlm@10 585 }
rlm@10 586 }
rlm@10 587
rlm@10 588 public void visitTableSwitchInsn(
rlm@10 589 final int min,
rlm@10 590 final int max,
rlm@10 591 final Label dflt,
rlm@10 592 final Label[] labels){
rlm@10 593 mv.visitTableSwitchInsn(min, max, dflt, labels);
rlm@10 594
rlm@10 595 if(constructor)
rlm@10 596 {
rlm@10 597 popValue();
rlm@10 598 addBranches(dflt, labels);
rlm@10 599 }
rlm@10 600 }
rlm@10 601
rlm@10 602 private void addBranches(final Label dflt, final Label[] labels){
rlm@10 603 addBranch(dflt);
rlm@10 604 for(int i = 0; i < labels.length; i++)
rlm@10 605 {
rlm@10 606 addBranch(labels[i]);
rlm@10 607 }
rlm@10 608 }
rlm@10 609
rlm@10 610 private void addBranch(final Label label){
rlm@10 611 if(branches.containsKey(label))
rlm@10 612 {
rlm@10 613 return;
rlm@10 614 }
rlm@10 615 ArrayList frame = new ArrayList();
rlm@10 616 frame.addAll(stackFrame);
rlm@10 617 branches.put(label, frame);
rlm@10 618 }
rlm@10 619
rlm@10 620 private Object popValue(){
rlm@10 621 return stackFrame.remove(stackFrame.size() - 1);
rlm@10 622 }
rlm@10 623
rlm@10 624 private Object peekValue(){
rlm@10 625 return stackFrame.get(stackFrame.size() - 1);
rlm@10 626 }
rlm@10 627
rlm@10 628 private void pushValue(final Object o){
rlm@10 629 stackFrame.add(o);
rlm@10 630 }
rlm@10 631
rlm@10 632 /**
rlm@10 633 * Called at the beginning of the method or after super class class call in
rlm@10 634 * the constructor. <br><br>
rlm@10 635 * <p/>
rlm@10 636 * <i>Custom code can use or change all the local variables, but should not
rlm@10 637 * change state of the stack.</i>
rlm@10 638 */
rlm@10 639 protected abstract void onMethodEnter();
rlm@10 640
rlm@10 641 /**
rlm@10 642 * Called before explicit exit from the method using either return or throw.
rlm@10 643 * Top element on the stack contains the return value or exception instance.
rlm@10 644 * For example:
rlm@10 645 * <p/>
rlm@10 646 * <pre>
rlm@10 647 * public void onMethodExit(int opcode) {
rlm@10 648 * if(opcode==RETURN) {
rlm@10 649 * visitInsn(ACONST_NULL);
rlm@10 650 * } else if(opcode==ARETURN || opcode==ATHROW) {
rlm@10 651 * dup();
rlm@10 652 * } else {
rlm@10 653 * if(opcode==LRETURN || opcode==DRETURN) {
rlm@10 654 * dup2();
rlm@10 655 * } else {
rlm@10 656 * dup();
rlm@10 657 * }
rlm@10 658 * box(Type.getReturnType(this.methodDesc));
rlm@10 659 * }
rlm@10 660 * visitIntInsn(SIPUSH, opcode);
rlm@10 661 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
rlm@10 662 * }
rlm@10 663 * <p/>
rlm@10 664 * // an actual call back method
rlm@10 665 * public static void onExit(int opcode, Object param) {
rlm@10 666 * ...
rlm@10 667 * </pre>
rlm@10 668 * <p/>
rlm@10 669 * <br><br>
rlm@10 670 * <p/>
rlm@10 671 * <i>Custom code can use or change all the local variables, but should not
rlm@10 672 * change state of the stack.</i>
rlm@10 673 *
rlm@10 674 * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN,
rlm@10 675 * DRETURN or ATHROW
rlm@10 676 */
rlm@10 677 protected abstract void onMethodExit(int opcode);
rlm@10 678
rlm@10 679 // TODO onException, onMethodCall
rlm@10 680
rlm@10 681 }