1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.commons; 29 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 import org.objectweb.asm.ConstantDynamic; 35 import org.objectweb.asm.Handle; 36 import org.objectweb.asm.Label; 37 import org.objectweb.asm.MethodVisitor; 38 import org.objectweb.asm.Opcodes; 39 import org.objectweb.asm.Type; 40 41 /** 42 * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link 43 * #visitFrame(int, int, Object[], int, Object[])} calls. This adapter must be used with the {@link 44 * org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>X</i> instruction delegates to 45 * the next visitor in the chain, if any, and then simulates the effect of this instruction on the 46 * stack map frame, represented by {@link #locals} and {@link #stack}. The next visitor in the chain 47 * can get the state of the stack map frame <i>before</i> each instruction by reading the value of 48 * these fields in its visit<i>X</i> methods (this requires a reference to the AnalyzerAdapter that 49 * is before it in the chain). If this adapter is used with a class that does not contain stack map 50 * table attributes (i.e., pre Java 6 classes) then this adapter may not be able to compute the 51 * stack map frame for each instruction. In this case no exception is thrown but the {@link #locals} 52 * and {@link #stack} fields will be null for these instructions. 53 * 54 * @author Eric Bruneton 55 */ 56 public class AnalyzerAdapter extends MethodVisitor { 57 58 /** 59 * The local variable slots for the current execution frame. Primitive types are represented by 60 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, 61 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and 62 * double are represented by two elements, the second one being TOP). Reference types are 63 * represented by String objects (representing internal names, see {@link 64 * Type#getInternalName()}), and uninitialized types by Label objects (this label designates the 65 * NEW instruction that created this uninitialized value). This field is {@literal null} for 66 * unreachable instructions. 67 */ 68 public List<Object> locals; 69 70 /** 71 * The operand stack slots for the current execution frame. Primitive types are represented by 72 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, 73 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and 74 * double are represented by two elements, the second one being TOP). Reference types are 75 * represented by String objects (representing internal names, see {@link 76 * Type#getInternalName()}), and uninitialized types by Label objects (this label designates the 77 * NEW instruction that created this uninitialized value). This field is {@literal null} for 78 * unreachable instructions. 79 */ 80 public List<Object> stack; 81 82 /** The labels that designate the next instruction to be visited. May be {@literal null}. */ 83 private List<Label> labels; 84 85 /** 86 * The uninitialized types in the current execution frame. This map associates internal names to 87 * Label objects (see {@link Type#getInternalName()}). Each label designates a NEW instruction 88 * that created the currently uninitialized types, and the associated internal name represents the 89 * NEW operand, i.e. the final, initialized type value. 90 */ 91 public Map<Object, Object> uninitializedTypes; 92 93 /** The maximum stack size of this method. */ 94 private int maxStack; 95 96 /** The maximum number of local variables of this method. */ 97 private int maxLocals; 98 99 /** 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 */ AnalyzerAdapter( final String owner, final int access, final String name, final String descriptor, final MethodVisitor methodVisitor)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(/* latest api = */ Opcodes.ASM9, 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 the {@code 131 * ASM}<i>x</i> values in {@link Opcodes}. 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 */ AnalyzerAdapter( final int api, final String owner, final int access, final String name, final String descriptor, final MethodVisitor methodVisitor)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 visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)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 visitFrameTypes( final int numTypes, final Object[] frameTypes, final List<Object> result)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 visitInsn(final int opcode)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 visitIntInsn(final int opcode, final int operand)241 public void visitIntInsn(final int opcode, final int operand) { 242 super.visitIntInsn(opcode, operand); 243 execute(opcode, operand, null); 244 } 245 246 @Override visitVarInsn(final int opcode, final int varIndex)247 public void visitVarInsn(final int opcode, final int varIndex) { 248 super.visitVarInsn(opcode, varIndex); 249 boolean isLongOrDouble = 250 opcode == Opcodes.LLOAD 251 || opcode == Opcodes.DLOAD 252 || opcode == Opcodes.LSTORE 253 || opcode == Opcodes.DSTORE; 254 maxLocals = Math.max(maxLocals, varIndex + (isLongOrDouble ? 2 : 1)); 255 execute(opcode, varIndex, null); 256 } 257 258 @Override visitTypeInsn(final int opcode, final String type)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 visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)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 visitMethodInsn( final int opcodeAndSource, final String owner, final String name, final String descriptor, final boolean isInterface)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 visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)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 visitJumpInsn(final int opcode, final Label label)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 visitLabel(final Label label)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 visitLdcInsn(final Object value)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 visitIincInsn(final int varIndex, final int increment)403 public void visitIincInsn(final int varIndex, final int increment) { 404 super.visitIincInsn(varIndex, increment); 405 maxLocals = Math.max(maxLocals, varIndex + 1); 406 execute(Opcodes.IINC, varIndex, null); 407 } 408 409 @Override visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)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 visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)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 visitMultiANewArrayInsn(final String descriptor, final int numDimensions)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 visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)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 visitMaxs(final int maxStack, final int maxLocals)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 get(final int local)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 set(final int local, final Object type)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 push(final Object type)471 private void push(final Object type) { 472 stack.add(type); 473 maxStack = Math.max(maxStack, stack.size()); 474 } 475 pushDescriptor(final String fieldOrMethodDescriptor)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 pop()513 private Object pop() { 514 return stack.remove(stack.size() - 1); 515 } 516 pop(final int numSlots)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 pop(final String descriptor)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 execute(final int opcode, final int intArg, final String stringArg)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 } 911