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