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