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