001/*** 002 * ASM: a very small and fast Java bytecode manipulation framework 003 * Copyright (c) 2000-2011 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 */ 030package io.ebean.enhance.asm.commons; 031 032import io.ebean.enhance.asm.ClassReader; 033import io.ebean.enhance.asm.Handle; 034import io.ebean.enhance.asm.Label; 035import io.ebean.enhance.asm.MethodVisitor; 036import io.ebean.enhance.asm.Opcodes; 037import io.ebean.enhance.asm.Type; 038 039import java.util.ArrayList; 040import java.util.HashMap; 041import java.util.List; 042import java.util.Map; 043 044/** 045 * A {@link MethodVisitor} that keeps track of stack map frame changes between 046 * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This 047 * adapter must be used with the 048 * {@link ClassReader#EXPAND_FRAMES} option. Each 049 * visit<i>X</i> instruction delegates to the next visitor in the chain, if any, 050 * and then simulates the effect of this instruction on the stack map frame, 051 * represented by {@link #locals} and {@link #stack}. The next visitor in the 052 * chain can get the state of the stack map frame <i>before</i> each instruction 053 * by reading the value of these fields in its visit<i>X</i> methods (this 054 * requires a reference to the AnalyzerAdapter that is before it in the chain). 055 * If this adapter is used with a class that does not contain stack map table 056 * attributes (i.e., pre Java 6 classes) then this adapter may not be able to 057 * compute the stack map frame for each instruction. In this case no exception 058 * is thrown but the {@link #locals} and {@link #stack} fields will be null for 059 * these instructions. 060 * 061 * @author Eric Bruneton 062 */ 063public class AnalyzerAdapter extends MethodVisitor { 064 065 /** 066 * <code>List</code> of the local variable slots for current execution 067 * frame. Primitive types are represented by {@link Opcodes#TOP}, 068 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, 069 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or 070 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by 071 * two elements, the second one being TOP). Reference types are represented 072 * by String objects (representing internal names), and uninitialized types 073 * by Label objects (this label designates the NEW instruction that created 074 * this uninitialized value). This field is <tt>null</tt> for unreachable 075 * instructions. 076 */ 077 public List<Object> locals; 078 079 /** 080 * <code>List</code> of the operand stack slots for current execution frame. 081 * Primitive types are represented by {@link Opcodes#TOP}, 082 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, 083 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or 084 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by 085 * two elements, the second one being TOP). Reference types are represented 086 * by String objects (representing internal names), and uninitialized types 087 * by Label objects (this label designates the NEW instruction that created 088 * this uninitialized value). This field is <tt>null</tt> for unreachable 089 * instructions. 090 */ 091 public List<Object> stack; 092 093 /** 094 * The labels that designate the next instruction to be visited. May be 095 * <tt>null</tt>. 096 */ 097 private List<Label> labels; 098 099 /** 100 * Information about uninitialized types in the current execution frame. 101 * This map associates internal names to Label objects. Each label 102 * designates a NEW instruction that created the currently uninitialized 103 * types, and the associated internal name represents the NEW operand, i.e. 104 * the final, initialized type value. 105 */ 106 public Map<Object, Object> uninitializedTypes; 107 108 /** 109 * The maximum stack size of this method. 110 */ 111 private int maxStack; 112 113 /** 114 * The maximum number of local variables of this method. 115 */ 116 private int maxLocals; 117 118 /** 119 * The owner's class name. 120 */ 121 private String owner; 122 123 /** 124 * Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this 125 * constructor</i>. Instead, they must use the 126 * {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)} 127 * version. 128 * 129 * @param owner 130 * the owner's class name. 131 * @param access 132 * the method's access flags (see {@link Opcodes}). 133 * @param name 134 * the method's name. 135 * @param desc 136 * the method's descriptor (see {@link Type Type}). 137 * @param mv 138 * the method visitor to which this adapter delegates calls. May 139 * be <tt>null</tt>. 140 * @throws IllegalStateException 141 * If a subclass calls this constructor. 142 */ 143 public AnalyzerAdapter(final String owner, final int access, 144 final String name, final String desc, final MethodVisitor mv) { 145 this(Opcodes.ASM6, owner, access, name, desc, mv); 146 if (getClass() != AnalyzerAdapter.class) { 147 throw new IllegalStateException(); 148 } 149 } 150 151 /** 152 * Creates a new {@link AnalyzerAdapter}. 153 * 154 * @param api 155 * the ASM API version implemented by this visitor. Must be one 156 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 157 * @param owner 158 * the owner's class name. 159 * @param access 160 * the method's access flags (see {@link Opcodes}). 161 * @param name 162 * the method's name. 163 * @param desc 164 * the method's descriptor (see {@link Type Type}). 165 * @param mv 166 * the method visitor to which this adapter delegates calls. May 167 * be <tt>null</tt>. 168 */ 169 protected AnalyzerAdapter(final int api, final String owner, 170 final int access, final String name, final String desc, 171 final MethodVisitor mv) { 172 super(api, mv); 173 this.owner = owner; 174 locals = new ArrayList<Object>(); 175 stack = new ArrayList<Object>(); 176 uninitializedTypes = new HashMap<Object, Object>(); 177 178 if ((access & Opcodes.ACC_STATIC) == 0) { 179 if ("<init>".equals(name)) { 180 locals.add(Opcodes.UNINITIALIZED_THIS); 181 } else { 182 locals.add(owner); 183 } 184 } 185 Type[] types = Type.getArgumentTypes(desc); 186 for (int i = 0; i < types.length; ++i) { 187 Type type = types[i]; 188 switch (type.getSort()) { 189 case Type.BOOLEAN: 190 case Type.CHAR: 191 case Type.BYTE: 192 case Type.SHORT: 193 case Type.INT: 194 locals.add(Opcodes.INTEGER); 195 break; 196 case Type.FLOAT: 197 locals.add(Opcodes.FLOAT); 198 break; 199 case Type.LONG: 200 locals.add(Opcodes.LONG); 201 locals.add(Opcodes.TOP); 202 break; 203 case Type.DOUBLE: 204 locals.add(Opcodes.DOUBLE); 205 locals.add(Opcodes.TOP); 206 break; 207 case Type.ARRAY: 208 locals.add(types[i].getDescriptor()); 209 break; 210 // case Type.OBJECT: 211 default: 212 locals.add(types[i].getInternalName()); 213 } 214 } 215 maxLocals = locals.size(); 216 } 217 218 @Override 219 public void visitFrame(final int type, final int nLocal, 220 final Object[] local, final int nStack, final Object[] stack) { 221 if (type != Opcodes.F_NEW) { // uncompressed frame 222 throw new IllegalStateException( 223 "ClassReader.accept() should be called with EXPAND_FRAMES flag"); 224 } 225 226 if (mv != null) { 227 mv.visitFrame(type, nLocal, local, nStack, stack); 228 } 229 230 if (this.locals != null) { 231 this.locals.clear(); 232 this.stack.clear(); 233 } else { 234 this.locals = new ArrayList<Object>(); 235 this.stack = new ArrayList<Object>(); 236 } 237 visitFrameTypes(nLocal, local, this.locals); 238 visitFrameTypes(nStack, stack, this.stack); 239 maxStack = Math.max(maxStack, this.stack.size()); 240 } 241 242 private static void visitFrameTypes(final int n, final Object[] types, 243 final List<Object> result) { 244 for (int i = 0; i < n; ++i) { 245 Object type = types[i]; 246 result.add(type); 247 if (type == Opcodes.LONG || type == Opcodes.DOUBLE) { 248 result.add(Opcodes.TOP); 249 } 250 } 251 } 252 253 @Override 254 public void visitInsn(final int opcode) { 255 if (mv != null) { 256 mv.visitInsn(opcode); 257 } 258 execute(opcode, 0, null); 259 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) 260 || opcode == Opcodes.ATHROW) { 261 this.locals = null; 262 this.stack = null; 263 } 264 } 265 266 @Override 267 public void visitIntInsn(final int opcode, final int operand) { 268 if (mv != null) { 269 mv.visitIntInsn(opcode, operand); 270 } 271 execute(opcode, operand, null); 272 } 273 274 @Override 275 public void visitVarInsn(final int opcode, final int var) { 276 if (mv != null) { 277 mv.visitVarInsn(opcode, var); 278 } 279 execute(opcode, var, null); 280 } 281 282 @Override 283 public void visitTypeInsn(final int opcode, final String type) { 284 if (opcode == Opcodes.NEW) { 285 if (labels == null) { 286 Label l = new Label(); 287 labels = new ArrayList<Label>(3); 288 labels.add(l); 289 if (mv != null) { 290 mv.visitLabel(l); 291 } 292 } 293 for (int i = 0; i < labels.size(); ++i) { 294 uninitializedTypes.put(labels.get(i), type); 295 } 296 } 297 if (mv != null) { 298 mv.visitTypeInsn(opcode, type); 299 } 300 execute(opcode, 0, type); 301 } 302 303 @Override 304 public void visitFieldInsn(final int opcode, final String owner, 305 final String name, final String desc) { 306 if (mv != null) { 307 mv.visitFieldInsn(opcode, owner, name, desc); 308 } 309 execute(opcode, 0, desc); 310 } 311 312 @Deprecated 313 @Override 314 public void visitMethodInsn(final int opcode, final String owner, 315 final String name, final String desc) { 316 if (api >= Opcodes.ASM5) { 317 super.visitMethodInsn(opcode, owner, name, desc); 318 return; 319 } 320 doVisitMethodInsn(opcode, owner, name, desc, 321 opcode == Opcodes.INVOKEINTERFACE); 322 } 323 324 @Override 325 public void visitMethodInsn(final int opcode, final String owner, 326 final String name, final String desc, final boolean itf) { 327 if (api < Opcodes.ASM5) { 328 super.visitMethodInsn(opcode, owner, name, desc, itf); 329 return; 330 } 331 doVisitMethodInsn(opcode, owner, name, desc, itf); 332 } 333 334 private void doVisitMethodInsn(int opcode, final String owner, 335 final String name, final String desc, final boolean itf) { 336 if (mv != null) { 337 mv.visitMethodInsn(opcode, owner, name, desc, itf); 338 } 339 if (this.locals == null) { 340 labels = null; 341 return; 342 } 343 pop(desc); 344 if (opcode != Opcodes.INVOKESTATIC) { 345 Object t = pop(); 346 if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') { 347 Object u; 348 if (t == Opcodes.UNINITIALIZED_THIS) { 349 u = this.owner; 350 } else { 351 u = uninitializedTypes.get(t); 352 } 353 for (int i = 0; i < locals.size(); ++i) { 354 if (locals.get(i) == t) { 355 locals.set(i, u); 356 } 357 } 358 for (int i = 0; i < stack.size(); ++i) { 359 if (stack.get(i) == t) { 360 stack.set(i, u); 361 } 362 } 363 } 364 } 365 pushDesc(desc); 366 labels = null; 367 } 368 369 @Override 370 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 371 Object... bsmArgs) { 372 if (mv != null) { 373 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); 374 } 375 if (this.locals == null) { 376 labels = null; 377 return; 378 } 379 pop(desc); 380 pushDesc(desc); 381 labels = null; 382 } 383 384 @Override 385 public void visitJumpInsn(final int opcode, final Label label) { 386 if (mv != null) { 387 mv.visitJumpInsn(opcode, label); 388 } 389 execute(opcode, 0, null); 390 if (opcode == Opcodes.GOTO) { 391 this.locals = null; 392 this.stack = null; 393 } 394 } 395 396 @Override 397 public void visitLabel(final Label label) { 398 if (mv != null) { 399 mv.visitLabel(label); 400 } 401 if (labels == null) { 402 labels = new ArrayList<Label>(3); 403 } 404 labels.add(label); 405 } 406 407 @Override 408 public void visitLdcInsn(final Object cst) { 409 if (mv != null) { 410 mv.visitLdcInsn(cst); 411 } 412 if (this.locals == null) { 413 labels = null; 414 return; 415 } 416 if (cst instanceof Integer) { 417 push(Opcodes.INTEGER); 418 } else if (cst instanceof Long) { 419 push(Opcodes.LONG); 420 push(Opcodes.TOP); 421 } else if (cst instanceof Float) { 422 push(Opcodes.FLOAT); 423 } else if (cst instanceof Double) { 424 push(Opcodes.DOUBLE); 425 push(Opcodes.TOP); 426 } else if (cst instanceof String) { 427 push("java/lang/String"); 428 } else if (cst instanceof Type) { 429 int sort = ((Type) cst).getSort(); 430 if (sort == Type.OBJECT || sort == Type.ARRAY) { 431 push("java/lang/Class"); 432 } else if (sort == Type.METHOD) { 433 push("java/lang/invoke/MethodType"); 434 } else { 435 throw new IllegalArgumentException(); 436 } 437 } else if (cst instanceof Handle) { 438 push("java/lang/invoke/MethodHandle"); 439 } else { 440 throw new IllegalArgumentException(); 441 } 442 labels = null; 443 } 444 445 @Override 446 public void visitIincInsn(final int var, final int increment) { 447 if (mv != null) { 448 mv.visitIincInsn(var, increment); 449 } 450 execute(Opcodes.IINC, var, null); 451 } 452 453 @Override 454 public void visitTableSwitchInsn(final int min, final int max, 455 final Label dflt, final Label... labels) { 456 if (mv != null) { 457 mv.visitTableSwitchInsn(min, max, dflt, labels); 458 } 459 execute(Opcodes.TABLESWITCH, 0, null); 460 this.locals = null; 461 this.stack = null; 462 } 463 464 @Override 465 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 466 final Label[] labels) { 467 if (mv != null) { 468 mv.visitLookupSwitchInsn(dflt, keys, labels); 469 } 470 execute(Opcodes.LOOKUPSWITCH, 0, null); 471 this.locals = null; 472 this.stack = null; 473 } 474 475 @Override 476 public void visitMultiANewArrayInsn(final String desc, final int dims) { 477 if (mv != null) { 478 mv.visitMultiANewArrayInsn(desc, dims); 479 } 480 execute(Opcodes.MULTIANEWARRAY, dims, desc); 481 } 482 483 @Override 484 public void visitMaxs(final int maxStack, final int maxLocals) { 485 if (mv != null) { 486 this.maxStack = Math.max(this.maxStack, maxStack); 487 this.maxLocals = Math.max(this.maxLocals, maxLocals); 488 mv.visitMaxs(this.maxStack, this.maxLocals); 489 } 490 } 491 492 // ------------------------------------------------------------------------ 493 494 private Object get(final int local) { 495 maxLocals = Math.max(maxLocals, local + 1); 496 return local < locals.size() ? locals.get(local) : Opcodes.TOP; 497 } 498 499 private void set(final int local, final Object type) { 500 maxLocals = Math.max(maxLocals, local + 1); 501 while (local >= locals.size()) { 502 locals.add(Opcodes.TOP); 503 } 504 locals.set(local, type); 505 } 506 507 private void push(final Object type) { 508 stack.add(type); 509 maxStack = Math.max(maxStack, stack.size()); 510 } 511 512 private void pushDesc(final String desc) { 513 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; 514 switch (desc.charAt(index)) { 515 case 'V': 516 return; 517 case 'Z': 518 case 'C': 519 case 'B': 520 case 'S': 521 case 'I': 522 push(Opcodes.INTEGER); 523 return; 524 case 'F': 525 push(Opcodes.FLOAT); 526 return; 527 case 'J': 528 push(Opcodes.LONG); 529 push(Opcodes.TOP); 530 return; 531 case 'D': 532 push(Opcodes.DOUBLE); 533 push(Opcodes.TOP); 534 return; 535 case '[': 536 if (index == 0) { 537 push(desc); 538 } else { 539 push(desc.substring(index, desc.length())); 540 } 541 break; 542 // case 'L': 543 default: 544 if (index == 0) { 545 push(desc.substring(1, desc.length() - 1)); 546 } else { 547 push(desc.substring(index + 1, desc.length() - 1)); 548 } 549 } 550 } 551 552 private Object pop() { 553 return stack.remove(stack.size() - 1); 554 } 555 556 private void pop(final int n) { 557 int size = stack.size(); 558 int end = size - n; 559 for (int i = size - 1; i >= end; --i) { 560 stack.remove(i); 561 } 562 } 563 564 private void pop(final String desc) { 565 char c = desc.charAt(0); 566 if (c == '(') { 567 int n = 0; 568 Type[] types = Type.getArgumentTypes(desc); 569 for (int i = 0; i < types.length; ++i) { 570 n += types[i].getSize(); 571 } 572 pop(n); 573 } else if (c == 'J' || c == 'D') { 574 pop(2); 575 } else { 576 pop(1); 577 } 578 } 579 580 private void execute(final int opcode, final int iarg, final String sarg) { 581 if (this.locals == null) { 582 labels = null; 583 return; 584 } 585 Object t1, t2, t3, t4; 586 switch (opcode) { 587 case Opcodes.NOP: 588 case Opcodes.INEG: 589 case Opcodes.LNEG: 590 case Opcodes.FNEG: 591 case Opcodes.DNEG: 592 case Opcodes.I2B: 593 case Opcodes.I2C: 594 case Opcodes.I2S: 595 case Opcodes.GOTO: 596 case Opcodes.RETURN: 597 break; 598 case Opcodes.ACONST_NULL: 599 push(Opcodes.NULL); 600 break; 601 case Opcodes.ICONST_M1: 602 case Opcodes.ICONST_0: 603 case Opcodes.ICONST_1: 604 case Opcodes.ICONST_2: 605 case Opcodes.ICONST_3: 606 case Opcodes.ICONST_4: 607 case Opcodes.ICONST_5: 608 case Opcodes.BIPUSH: 609 case Opcodes.SIPUSH: 610 push(Opcodes.INTEGER); 611 break; 612 case Opcodes.LCONST_0: 613 case Opcodes.LCONST_1: 614 push(Opcodes.LONG); 615 push(Opcodes.TOP); 616 break; 617 case Opcodes.FCONST_0: 618 case Opcodes.FCONST_1: 619 case Opcodes.FCONST_2: 620 push(Opcodes.FLOAT); 621 break; 622 case Opcodes.DCONST_0: 623 case Opcodes.DCONST_1: 624 push(Opcodes.DOUBLE); 625 push(Opcodes.TOP); 626 break; 627 case Opcodes.ILOAD: 628 case Opcodes.FLOAD: 629 case Opcodes.ALOAD: 630 push(get(iarg)); 631 break; 632 case Opcodes.LLOAD: 633 case Opcodes.DLOAD: 634 push(get(iarg)); 635 push(Opcodes.TOP); 636 break; 637 case Opcodes.IALOAD: 638 case Opcodes.BALOAD: 639 case Opcodes.CALOAD: 640 case Opcodes.SALOAD: 641 pop(2); 642 push(Opcodes.INTEGER); 643 break; 644 case Opcodes.LALOAD: 645 case Opcodes.D2L: 646 pop(2); 647 push(Opcodes.LONG); 648 push(Opcodes.TOP); 649 break; 650 case Opcodes.FALOAD: 651 pop(2); 652 push(Opcodes.FLOAT); 653 break; 654 case Opcodes.DALOAD: 655 case Opcodes.L2D: 656 pop(2); 657 push(Opcodes.DOUBLE); 658 push(Opcodes.TOP); 659 break; 660 case Opcodes.AALOAD: 661 pop(1); 662 t1 = pop(); 663 if (t1 instanceof String) { 664 pushDesc(((String) t1).substring(1)); 665 } else if (t1 == Opcodes.NULL) { 666 push(t1); 667 } else { 668 push("java/lang/Object"); 669 } 670 break; 671 case Opcodes.ISTORE: 672 case Opcodes.FSTORE: 673 case Opcodes.ASTORE: 674 t1 = pop(); 675 set(iarg, t1); 676 if (iarg > 0) { 677 t2 = get(iarg - 1); 678 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { 679 set(iarg - 1, Opcodes.TOP); 680 } 681 } 682 break; 683 case Opcodes.LSTORE: 684 case Opcodes.DSTORE: 685 pop(1); 686 t1 = pop(); 687 set(iarg, t1); 688 set(iarg + 1, Opcodes.TOP); 689 if (iarg > 0) { 690 t2 = get(iarg - 1); 691 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) { 692 set(iarg - 1, Opcodes.TOP); 693 } 694 } 695 break; 696 case Opcodes.IASTORE: 697 case Opcodes.BASTORE: 698 case Opcodes.CASTORE: 699 case Opcodes.SASTORE: 700 case Opcodes.FASTORE: 701 case Opcodes.AASTORE: 702 pop(3); 703 break; 704 case Opcodes.LASTORE: 705 case Opcodes.DASTORE: 706 pop(4); 707 break; 708 case Opcodes.POP: 709 case Opcodes.IFEQ: 710 case Opcodes.IFNE: 711 case Opcodes.IFLT: 712 case Opcodes.IFGE: 713 case Opcodes.IFGT: 714 case Opcodes.IFLE: 715 case Opcodes.IRETURN: 716 case Opcodes.FRETURN: 717 case Opcodes.ARETURN: 718 case Opcodes.TABLESWITCH: 719 case Opcodes.LOOKUPSWITCH: 720 case Opcodes.ATHROW: 721 case Opcodes.MONITORENTER: 722 case Opcodes.MONITOREXIT: 723 case Opcodes.IFNULL: 724 case Opcodes.IFNONNULL: 725 pop(1); 726 break; 727 case Opcodes.POP2: 728 case Opcodes.IF_ICMPEQ: 729 case Opcodes.IF_ICMPNE: 730 case Opcodes.IF_ICMPLT: 731 case Opcodes.IF_ICMPGE: 732 case Opcodes.IF_ICMPGT: 733 case Opcodes.IF_ICMPLE: 734 case Opcodes.IF_ACMPEQ: 735 case Opcodes.IF_ACMPNE: 736 case Opcodes.LRETURN: 737 case Opcodes.DRETURN: 738 pop(2); 739 break; 740 case Opcodes.DUP: 741 t1 = pop(); 742 push(t1); 743 push(t1); 744 break; 745 case Opcodes.DUP_X1: 746 t1 = pop(); 747 t2 = pop(); 748 push(t1); 749 push(t2); 750 push(t1); 751 break; 752 case Opcodes.DUP_X2: 753 t1 = pop(); 754 t2 = pop(); 755 t3 = pop(); 756 push(t1); 757 push(t3); 758 push(t2); 759 push(t1); 760 break; 761 case Opcodes.DUP2: 762 t1 = pop(); 763 t2 = pop(); 764 push(t2); 765 push(t1); 766 push(t2); 767 push(t1); 768 break; 769 case Opcodes.DUP2_X1: 770 t1 = pop(); 771 t2 = pop(); 772 t3 = pop(); 773 push(t2); 774 push(t1); 775 push(t3); 776 push(t2); 777 push(t1); 778 break; 779 case Opcodes.DUP2_X2: 780 t1 = pop(); 781 t2 = pop(); 782 t3 = pop(); 783 t4 = pop(); 784 push(t2); 785 push(t1); 786 push(t4); 787 push(t3); 788 push(t2); 789 push(t1); 790 break; 791 case Opcodes.SWAP: 792 t1 = pop(); 793 t2 = pop(); 794 push(t1); 795 push(t2); 796 break; 797 case Opcodes.IADD: 798 case Opcodes.ISUB: 799 case Opcodes.IMUL: 800 case Opcodes.IDIV: 801 case Opcodes.IREM: 802 case Opcodes.IAND: 803 case Opcodes.IOR: 804 case Opcodes.IXOR: 805 case Opcodes.ISHL: 806 case Opcodes.ISHR: 807 case Opcodes.IUSHR: 808 case Opcodes.L2I: 809 case Opcodes.D2I: 810 case Opcodes.FCMPL: 811 case Opcodes.FCMPG: 812 pop(2); 813 push(Opcodes.INTEGER); 814 break; 815 case Opcodes.LADD: 816 case Opcodes.LSUB: 817 case Opcodes.LMUL: 818 case Opcodes.LDIV: 819 case Opcodes.LREM: 820 case Opcodes.LAND: 821 case Opcodes.LOR: 822 case Opcodes.LXOR: 823 pop(4); 824 push(Opcodes.LONG); 825 push(Opcodes.TOP); 826 break; 827 case Opcodes.FADD: 828 case Opcodes.FSUB: 829 case Opcodes.FMUL: 830 case Opcodes.FDIV: 831 case Opcodes.FREM: 832 case Opcodes.L2F: 833 case Opcodes.D2F: 834 pop(2); 835 push(Opcodes.FLOAT); 836 break; 837 case Opcodes.DADD: 838 case Opcodes.DSUB: 839 case Opcodes.DMUL: 840 case Opcodes.DDIV: 841 case Opcodes.DREM: 842 pop(4); 843 push(Opcodes.DOUBLE); 844 push(Opcodes.TOP); 845 break; 846 case Opcodes.LSHL: 847 case Opcodes.LSHR: 848 case Opcodes.LUSHR: 849 pop(3); 850 push(Opcodes.LONG); 851 push(Opcodes.TOP); 852 break; 853 case Opcodes.IINC: 854 set(iarg, Opcodes.INTEGER); 855 break; 856 case Opcodes.I2L: 857 case Opcodes.F2L: 858 pop(1); 859 push(Opcodes.LONG); 860 push(Opcodes.TOP); 861 break; 862 case Opcodes.I2F: 863 pop(1); 864 push(Opcodes.FLOAT); 865 break; 866 case Opcodes.I2D: 867 case Opcodes.F2D: 868 pop(1); 869 push(Opcodes.DOUBLE); 870 push(Opcodes.TOP); 871 break; 872 case Opcodes.F2I: 873 case Opcodes.ARRAYLENGTH: 874 case Opcodes.INSTANCEOF: 875 pop(1); 876 push(Opcodes.INTEGER); 877 break; 878 case Opcodes.LCMP: 879 case Opcodes.DCMPL: 880 case Opcodes.DCMPG: 881 pop(4); 882 push(Opcodes.INTEGER); 883 break; 884 case Opcodes.JSR: 885 case Opcodes.RET: 886 throw new RuntimeException("JSR/RET are not supported"); 887 case Opcodes.GETSTATIC: 888 pushDesc(sarg); 889 break; 890 case Opcodes.PUTSTATIC: 891 pop(sarg); 892 break; 893 case Opcodes.GETFIELD: 894 pop(1); 895 pushDesc(sarg); 896 break; 897 case Opcodes.PUTFIELD: 898 pop(sarg); 899 pop(); 900 break; 901 case Opcodes.NEW: 902 push(labels.get(0)); 903 break; 904 case Opcodes.NEWARRAY: 905 pop(); 906 switch (iarg) { 907 case Opcodes.T_BOOLEAN: 908 pushDesc("[Z"); 909 break; 910 case Opcodes.T_CHAR: 911 pushDesc("[C"); 912 break; 913 case Opcodes.T_BYTE: 914 pushDesc("[B"); 915 break; 916 case Opcodes.T_SHORT: 917 pushDesc("[S"); 918 break; 919 case Opcodes.T_INT: 920 pushDesc("[I"); 921 break; 922 case Opcodes.T_FLOAT: 923 pushDesc("[F"); 924 break; 925 case Opcodes.T_DOUBLE: 926 pushDesc("[D"); 927 break; 928 // case Opcodes.T_LONG: 929 default: 930 pushDesc("[J"); 931 break; 932 } 933 break; 934 case Opcodes.ANEWARRAY: 935 pop(); 936 pushDesc("[" + Type.getObjectType(sarg)); 937 break; 938 case Opcodes.CHECKCAST: 939 pop(); 940 pushDesc(Type.getObjectType(sarg).getDescriptor()); 941 break; 942 // case Opcodes.MULTIANEWARRAY: 943 default: 944 pop(iarg); 945 pushDesc(sarg); 946 break; 947 } 948 labels = null; 949 } 950}