1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.bytecode.stackmap; 17 18 import javassist.bytecode.ByteArray; 19 import javassist.bytecode.Opcode; 20 import javassist.bytecode.ConstPool; 21 import javassist.bytecode.Descriptor; 22 import javassist.bytecode.BadBytecode; 23 import javassist.ClassPool; 24 25 /* 26 * A class for performing abstract interpretation. 27 * See also MapMaker class. 28 */ 29 30 public abstract class Tracer implements TypeTag { 31 protected ClassPool classPool; 32 protected ConstPool cpool; 33 protected String returnType; 34 35 protected int stackTop; 36 protected TypeData[] stackTypes; 37 protected TypeData[] localsTypes; 38 39 public Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals, 40 String retType) { 41 classPool = classes; 42 cpool = cp; 43 returnType = retType; 44 stackTop = 0; 45 stackTypes = new TypeData[maxStack]; 46 localsTypes = new TypeData[maxLocals]; 47 } 48 49 public Tracer(Tracer t, boolean copyStack) { 50 classPool = t.classPool; 51 cpool = t.cpool; 52 returnType = t.returnType; 53 54 stackTop = t.stackTop; 55 int size = t.stackTypes.length; 56 stackTypes = new TypeData[size]; 57 if (copyStack) 58 copyFrom(t.stackTop, t.stackTypes, stackTypes); 59 60 int size2 = t.localsTypes.length; 61 localsTypes = new TypeData[size2]; 62 copyFrom(size2, t.localsTypes, localsTypes); 63 } 64 65 protected static int copyFrom(int n, TypeData[] srcTypes, TypeData[] destTypes) { 66 int k = -1; 67 for (int i = 0; i < n; i++) { 68 TypeData t = srcTypes[i]; 69 destTypes[i] = t == TOP ? TOP : t.getSelf(); 70 if (t != TOP) 71 if (t.is2WordType()) 72 k = i + 1; 73 else 74 k = i; 75 } 76 77 return k + 1; 78 } 79 80 /** 81 * Does abstract interpretation on the given bytecode instruction. 82 * It records whether or not a local variable (i.e. register) is accessed. 83 * If the instruction requires that a local variable or 84 * a stack element has a more specific type, this method updates the 85 * type of it. 86 * 87 * @param pos the position of the instruction. 88 * @return the size of the instruction at POS. 89 */ 90 protected int doOpcode(int pos, byte[] code) throws BadBytecode { 91 try { 92 int op = code[pos] & 0xff; 93 if (op < 96) 94 if (op < 54) 95 return doOpcode0_53(pos, code, op); 96 else 97 return doOpcode54_95(pos, code, op); 98 else 99 if (op < 148) 100 return doOpcode96_147(pos, code, op); 101 else 102 return doOpcode148_201(pos, code, op); 103 } 104 catch (ArrayIndexOutOfBoundsException e) { 105 throw new BadBytecode("inconsistent stack height " + e.getMessage()); 106 } 107 } 108 109 protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {} 110 protected void visitGoto(int pos, byte[] code, int offset) throws BadBytecode {} 111 protected void visitReturn(int pos, byte[] code) throws BadBytecode {} 112 protected void visitThrow(int pos, byte[] code) throws BadBytecode {} 113 114 /** 115 * @param pos the position of TABLESWITCH 116 * @param code bytecode 117 * @param n the number of case labels 118 * @param offsetPos the position of the branch-target table. 119 * @param defaultOffset the offset to the default branch target. 120 */ 121 protected void visitTableSwitch(int pos, byte[] code, int n, 122 int offsetPos, int defaultOffset) throws BadBytecode {} 123 124 /** 125 * @param pos the position of LOOKUPSWITCH 126 * @param code bytecode 127 * @param n the number of case labels 128 * @param offsetPos the position of the table of pairs of a value and a branch target. 129 * @param defaultOffset the offset to the default branch target. 130 */ 131 protected void visitLookupSwitch(int pos, byte[] code, int n, 132 int pairsPos, int defaultOffset) throws BadBytecode {} 133 134 /** 135 * Invoked when the visited instruction is jsr. 136 * Java6 or later does not allow using RET. 137 */ 138 protected void visitJSR(int pos, byte[] code) throws BadBytecode { 139 /* Since JSR pushes a return address onto the operand stack, 140 * the stack map at the entry point of a subroutine is 141 * stackTypes resulting after executing the following code: 142 * 143 * stackTypes[stackTop++] = TOP; 144 */ 145 } 146 147 /** 148 * Invoked when the visited instruction is ret or wide ret. 149 * Java6 or later does not allow using RET. 150 */ 151 protected void visitRET(int pos, byte[] code) throws BadBytecode {} 152 153 private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode { 154 int reg; 155 TypeData[] stackTypes = this.stackTypes; 156 switch (op) { 157 case Opcode.NOP : 158 break; 159 case Opcode.ACONST_NULL : 160 stackTypes[stackTop++] = new TypeData.NullType(); 161 break; 162 case Opcode.ICONST_M1 : 163 case Opcode.ICONST_0 : 164 case Opcode.ICONST_1 : 165 case Opcode.ICONST_2 : 166 case Opcode.ICONST_3 : 167 case Opcode.ICONST_4 : 168 case Opcode.ICONST_5 : 169 stackTypes[stackTop++] = INTEGER; 170 break; 171 case Opcode.LCONST_0 : 172 case Opcode.LCONST_1 : 173 stackTypes[stackTop++] = LONG; 174 stackTypes[stackTop++] = TOP; 175 break; 176 case Opcode.FCONST_0 : 177 case Opcode.FCONST_1 : 178 case Opcode.FCONST_2 : 179 stackTypes[stackTop++] = FLOAT; 180 break; 181 case Opcode.DCONST_0 : 182 case Opcode.DCONST_1 : 183 stackTypes[stackTop++] = DOUBLE; 184 stackTypes[stackTop++] = TOP; 185 break; 186 case Opcode.BIPUSH : 187 case Opcode.SIPUSH : 188 stackTypes[stackTop++] = INTEGER; 189 return op == Opcode.SIPUSH ? 3 : 2; 190 case Opcode.LDC : 191 doLDC(code[pos + 1] & 0xff); 192 return 2; 193 case Opcode.LDC_W : 194 case Opcode.LDC2_W : 195 doLDC(ByteArray.readU16bit(code, pos + 1)); 196 return 3; 197 case Opcode.ILOAD : 198 return doXLOAD(INTEGER, code, pos); 199 case Opcode.LLOAD : 200 return doXLOAD(LONG, code, pos); 201 case Opcode.FLOAD : 202 return doXLOAD(FLOAT, code, pos); 203 case Opcode.DLOAD : 204 return doXLOAD(DOUBLE, code, pos); 205 case Opcode.ALOAD : 206 return doALOAD(code[pos + 1] & 0xff); 207 case Opcode.ILOAD_0 : 208 case Opcode.ILOAD_1 : 209 case Opcode.ILOAD_2 : 210 case Opcode.ILOAD_3 : 211 stackTypes[stackTop++] = INTEGER; 212 break; 213 case Opcode.LLOAD_0 : 214 case Opcode.LLOAD_1 : 215 case Opcode.LLOAD_2 : 216 case Opcode.LLOAD_3 : 217 stackTypes[stackTop++] = LONG; 218 stackTypes[stackTop++] = TOP; 219 break; 220 case Opcode.FLOAD_0 : 221 case Opcode.FLOAD_1 : 222 case Opcode.FLOAD_2 : 223 case Opcode.FLOAD_3 : 224 stackTypes[stackTop++] = FLOAT; 225 break; 226 case Opcode.DLOAD_0 : 227 case Opcode.DLOAD_1 : 228 case Opcode.DLOAD_2 : 229 case Opcode.DLOAD_3 : 230 stackTypes[stackTop++] = DOUBLE; 231 stackTypes[stackTop++] = TOP; 232 break; 233 case Opcode.ALOAD_0 : 234 case Opcode.ALOAD_1 : 235 case Opcode.ALOAD_2 : 236 case Opcode.ALOAD_3 : 237 reg = op - Opcode.ALOAD_0; 238 stackTypes[stackTop++] = localsTypes[reg]; 239 break; 240 case Opcode.IALOAD : 241 stackTypes[--stackTop - 1] = INTEGER; 242 break; 243 case Opcode.LALOAD : 244 stackTypes[stackTop - 2] = LONG; 245 stackTypes[stackTop - 1] = TOP; 246 break; 247 case Opcode.FALOAD : 248 stackTypes[--stackTop - 1] = FLOAT; 249 break; 250 case Opcode.DALOAD : 251 stackTypes[stackTop - 2] = DOUBLE; 252 stackTypes[stackTop - 1] = TOP; 253 break; 254 case Opcode.AALOAD : { 255 int s = --stackTop - 1; 256 TypeData data = stackTypes[s]; 257 if (data == null || !data.isObjectType()) 258 throw new BadBytecode("bad AALOAD"); 259 else 260 stackTypes[s] = new TypeData.ArrayElement(data); 261 262 break; } 263 case Opcode.BALOAD : 264 case Opcode.CALOAD : 265 case Opcode.SALOAD : 266 stackTypes[--stackTop - 1] = INTEGER; 267 break; 268 default : 269 throw new RuntimeException("fatal"); 270 } 271 272 return 1; 273 } 274 275 private void doLDC(int index) { 276 TypeData[] stackTypes = this.stackTypes; 277 int tag = cpool.getTag(index); 278 if (tag == ConstPool.CONST_String) 279 stackTypes[stackTop++] = new TypeData.ClassName("java.lang.String"); 280 else if (tag == ConstPool.CONST_Integer) 281 stackTypes[stackTop++] = INTEGER; 282 else if (tag == ConstPool.CONST_Float) 283 stackTypes[stackTop++] = FLOAT; 284 else if (tag == ConstPool.CONST_Long) { 285 stackTypes[stackTop++] = LONG; 286 stackTypes[stackTop++] = TOP; 287 } 288 else if (tag == ConstPool.CONST_Double) { 289 stackTypes[stackTop++] = DOUBLE; 290 stackTypes[stackTop++] = TOP; 291 } 292 else if (tag == ConstPool.CONST_Class) 293 stackTypes[stackTop++] = new TypeData.ClassName("java.lang.Class"); 294 else 295 throw new RuntimeException("bad LDC: " + tag); 296 } 297 298 private int doXLOAD(TypeData type, byte[] code, int pos) { 299 int localVar = code[pos + 1] & 0xff; 300 return doXLOAD(localVar, type); 301 } 302 303 private int doXLOAD(int localVar, TypeData type) { 304 stackTypes[stackTop++] = type; 305 if (type.is2WordType()) 306 stackTypes[stackTop++] = TOP; 307 308 return 2; 309 } 310 311 private int doALOAD(int localVar) { // int localVar, TypeData type) { 312 stackTypes[stackTop++] = localsTypes[localVar]; 313 return 2; 314 } 315 316 private int doOpcode54_95(int pos, byte[] code, int op) throws BadBytecode { 317 TypeData[] localsTypes = this.localsTypes; 318 TypeData[] stackTypes = this.stackTypes; 319 switch (op) { 320 case Opcode.ISTORE : 321 return doXSTORE(pos, code, INTEGER); 322 case Opcode.LSTORE : 323 return doXSTORE(pos, code, LONG); 324 case Opcode.FSTORE : 325 return doXSTORE(pos, code, FLOAT); 326 case Opcode.DSTORE : 327 return doXSTORE(pos, code, DOUBLE); 328 case Opcode.ASTORE : 329 return doASTORE(code[pos + 1] & 0xff); 330 case Opcode.ISTORE_0 : 331 case Opcode.ISTORE_1 : 332 case Opcode.ISTORE_2 : 333 case Opcode.ISTORE_3 : 334 { int var = op - Opcode.ISTORE_0; 335 localsTypes[var] = INTEGER; 336 stackTop--; } 337 break; 338 case Opcode.LSTORE_0 : 339 case Opcode.LSTORE_1 : 340 case Opcode.LSTORE_2 : 341 case Opcode.LSTORE_3 : 342 { int var = op - Opcode.LSTORE_0; 343 localsTypes[var] = LONG; 344 localsTypes[var + 1] = TOP; 345 stackTop -= 2; } 346 break; 347 case Opcode.FSTORE_0 : 348 case Opcode.FSTORE_1 : 349 case Opcode.FSTORE_2 : 350 case Opcode.FSTORE_3 : 351 { int var = op - Opcode.FSTORE_0; 352 localsTypes[var] = FLOAT; 353 stackTop--; } 354 break; 355 case Opcode.DSTORE_0 : 356 case Opcode.DSTORE_1 : 357 case Opcode.DSTORE_2 : 358 case Opcode.DSTORE_3 : 359 { int var = op - Opcode.DSTORE_0; 360 localsTypes[var] = DOUBLE; 361 localsTypes[var + 1] = TOP; 362 stackTop -= 2; } 363 break; 364 case Opcode.ASTORE_0 : 365 case Opcode.ASTORE_1 : 366 case Opcode.ASTORE_2 : 367 case Opcode.ASTORE_3 : 368 { int var = op - Opcode.ASTORE_0; 369 doASTORE(var); 370 break; } 371 case Opcode.IASTORE : 372 case Opcode.LASTORE : 373 case Opcode.FASTORE : 374 case Opcode.DASTORE : 375 stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3; 376 break; 377 case Opcode.AASTORE : 378 TypeData.setType(stackTypes[stackTop - 1], 379 TypeData.ArrayElement.getElementType(stackTypes[stackTop - 3].getName()), 380 classPool); 381 stackTop -= 3; 382 break; 383 case Opcode.BASTORE : 384 case Opcode.CASTORE : 385 case Opcode.SASTORE : 386 stackTop -= 3; 387 break; 388 case Opcode.POP : 389 stackTop--; 390 break; 391 case Opcode.POP2 : 392 stackTop -= 2; 393 break; 394 case Opcode.DUP : { 395 int sp = stackTop; 396 stackTypes[sp] = stackTypes[sp - 1]; 397 stackTop = sp + 1; 398 break; } 399 case Opcode.DUP_X1 : 400 case Opcode.DUP_X2 : { 401 int len = op - Opcode.DUP_X1 + 2; 402 doDUP_XX(1, len); 403 int sp = stackTop; 404 stackTypes[sp - len] = stackTypes[sp]; 405 stackTop = sp + 1; 406 break; } 407 case Opcode.DUP2 : 408 doDUP_XX(2, 2); 409 stackTop += 2; 410 break; 411 case Opcode.DUP2_X1 : 412 case Opcode.DUP2_X2 : { 413 int len = op - Opcode.DUP2_X1 + 3; 414 doDUP_XX(2, len); 415 int sp = stackTop; 416 stackTypes[sp - len] = stackTypes[sp]; 417 stackTypes[sp - len + 1] = stackTypes[sp + 1]; 418 stackTop = sp + 2; 419 break; } 420 case Opcode.SWAP : { 421 int sp = stackTop - 1; 422 TypeData t = stackTypes[sp]; 423 stackTypes[sp] = stackTypes[sp - 1]; 424 stackTypes[sp - 1] = t; 425 break; } 426 default : 427 throw new RuntimeException("fatal"); 428 } 429 430 return 1; 431 } 432 433 private int doXSTORE(int pos, byte[] code, TypeData type) { 434 int index = code[pos + 1] & 0xff; 435 return doXSTORE(index, type); 436 } 437 438 private int doXSTORE(int index, TypeData type) { 439 stackTop--; 440 localsTypes[index] = type; 441 if (type.is2WordType()) { 442 stackTop--; 443 localsTypes[index + 1] = TOP; 444 } 445 446 return 2; 447 } 448 449 private int doASTORE(int index) { 450 stackTop--; 451 // implicit upcast might be done. 452 localsTypes[index] = stackTypes[stackTop].copy(); 453 return 2; 454 } 455 456 private void doDUP_XX(int delta, int len) { 457 TypeData types[] = stackTypes; 458 int sp = stackTop - 1; 459 int end = sp - len; 460 while (sp > end) { 461 types[sp + delta] = types[sp]; 462 sp--; 463 } 464 } 465 466 private int doOpcode96_147(int pos, byte[] code, int op) { 467 if (op <= Opcode.LXOR) { // IADD...LXOR 468 stackTop += Opcode.STACK_GROW[op]; 469 return 1; 470 } 471 472 switch (op) { 473 case Opcode.IINC : 474 // this does not call writeLocal(). 475 return 3; 476 case Opcode.I2L : 477 stackTypes[stackTop] = LONG; 478 stackTypes[stackTop - 1] = TOP; 479 stackTop++; 480 break; 481 case Opcode.I2F : 482 stackTypes[stackTop - 1] = FLOAT; 483 break; 484 case Opcode.I2D : 485 stackTypes[stackTop] = DOUBLE; 486 stackTypes[stackTop - 1] = TOP; 487 stackTop++; 488 break; 489 case Opcode.L2I : 490 stackTypes[--stackTop - 1] = INTEGER; 491 break; 492 case Opcode.L2F : 493 stackTypes[--stackTop - 1] = FLOAT; 494 break; 495 case Opcode.L2D : 496 stackTypes[stackTop - 1] = DOUBLE; 497 break; 498 case Opcode.F2I : 499 stackTypes[stackTop - 1] = INTEGER; 500 break; 501 case Opcode.F2L : 502 stackTypes[stackTop - 1] = TOP; 503 stackTypes[stackTop++] = LONG; 504 break; 505 case Opcode.F2D : 506 stackTypes[stackTop - 1] = TOP; 507 stackTypes[stackTop++] = DOUBLE; 508 break; 509 case Opcode.D2I : 510 stackTypes[--stackTop - 1] = INTEGER; 511 break; 512 case Opcode.D2L : 513 stackTypes[stackTop - 1] = LONG; 514 break; 515 case Opcode.D2F : 516 stackTypes[--stackTop - 1] = FLOAT; 517 break; 518 case Opcode.I2B : 519 case Opcode.I2C : 520 case Opcode.I2S : 521 break; 522 default : 523 throw new RuntimeException("fatal"); 524 } 525 526 return 1; 527 } 528 529 private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode { 530 switch (op) { 531 case Opcode.LCMP : 532 stackTypes[stackTop - 4] = INTEGER; 533 stackTop -= 3; 534 break; 535 case Opcode.FCMPL : 536 case Opcode.FCMPG : 537 stackTypes[--stackTop - 1] = INTEGER; 538 break; 539 case Opcode.DCMPL : 540 case Opcode.DCMPG : 541 stackTypes[stackTop - 4] = INTEGER; 542 stackTop -= 3; 543 break; 544 case Opcode.IFEQ : 545 case Opcode.IFNE : 546 case Opcode.IFLT : 547 case Opcode.IFGE : 548 case Opcode.IFGT : 549 case Opcode.IFLE : 550 stackTop--; // branch 551 visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1)); 552 return 3; 553 case Opcode.IF_ICMPEQ : 554 case Opcode.IF_ICMPNE : 555 case Opcode.IF_ICMPLT : 556 case Opcode.IF_ICMPGE : 557 case Opcode.IF_ICMPGT : 558 case Opcode.IF_ICMPLE : 559 case Opcode.IF_ACMPEQ : 560 case Opcode.IF_ACMPNE : 561 stackTop -= 2; // branch 562 visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1)); 563 return 3; 564 case Opcode.GOTO : 565 visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1)); 566 return 3; // branch 567 case Opcode.JSR : 568 visitJSR(pos, code); 569 return 3; // branch 570 case Opcode.RET : 571 visitRET(pos, code); 572 return 2; 573 case Opcode.TABLESWITCH : { 574 stackTop--; // branch 575 int pos2 = (pos & ~3) + 8; 576 int low = ByteArray.read32bit(code, pos2); 577 int high = ByteArray.read32bit(code, pos2 + 4); 578 int n = high - low + 1; 579 visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4)); 580 return n * 4 + 16 - (pos & 3); } 581 case Opcode.LOOKUPSWITCH : { 582 stackTop--; // branch 583 int pos2 = (pos & ~3) + 8; 584 int n = ByteArray.read32bit(code, pos2); 585 visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4)); 586 return n * 8 + 12 - (pos & 3); } 587 case Opcode.IRETURN : 588 stackTop--; 589 visitReturn(pos, code); 590 break; 591 case Opcode.LRETURN : 592 stackTop -= 2; 593 visitReturn(pos, code); 594 break; 595 case Opcode.FRETURN : 596 stackTop--; 597 visitReturn(pos, code); 598 break; 599 case Opcode.DRETURN : 600 stackTop -= 2; 601 visitReturn(pos, code); 602 break; 603 case Opcode.ARETURN : 604 TypeData.setType(stackTypes[--stackTop], returnType, classPool); 605 visitReturn(pos, code); 606 break; 607 case Opcode.RETURN : 608 visitReturn(pos, code); 609 break; 610 case Opcode.GETSTATIC : 611 return doGetField(pos, code, false); 612 case Opcode.PUTSTATIC : 613 return doPutField(pos, code, false); 614 case Opcode.GETFIELD : 615 return doGetField(pos, code, true); 616 case Opcode.PUTFIELD : 617 return doPutField(pos, code, true); 618 case Opcode.INVOKEVIRTUAL : 619 case Opcode.INVOKESPECIAL : 620 return doInvokeMethod(pos, code, true); 621 case Opcode.INVOKESTATIC : 622 return doInvokeMethod(pos, code, false); 623 case Opcode.INVOKEINTERFACE : 624 return doInvokeIntfMethod(pos, code); 625 case 186 : 626 throw new RuntimeException("bad opcode 186"); 627 case Opcode.NEW : { 628 int i = ByteArray.readU16bit(code, pos + 1); 629 stackTypes[stackTop++] 630 = new TypeData.UninitData(pos, cpool.getClassInfo(i)); 631 return 3; } 632 case Opcode.NEWARRAY : 633 return doNEWARRAY(pos, code); 634 case Opcode.ANEWARRAY : { 635 int i = ByteArray.readU16bit(code, pos + 1); 636 String type = cpool.getClassInfo(i).replace('.', '/'); 637 if (type.charAt(0) == '[') 638 type = "[" + type; 639 else 640 type = "[L" + type + ";"; 641 642 stackTypes[stackTop - 1] 643 = new TypeData.ClassName(type); 644 return 3; } 645 case Opcode.ARRAYLENGTH : 646 TypeData.setType(stackTypes[stackTop - 1], "[Ljava.lang.Object;", classPool); 647 stackTypes[stackTop - 1] = INTEGER; 648 break; 649 case Opcode.ATHROW : 650 TypeData.setType(stackTypes[--stackTop], "java.lang.Throwable", classPool); 651 visitThrow(pos, code); 652 break; 653 case Opcode.CHECKCAST : { 654 // TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool); 655 int i = ByteArray.readU16bit(code, pos + 1); 656 stackTypes[stackTop - 1] = new TypeData.ClassName(cpool.getClassInfo(i)); 657 return 3; } 658 case Opcode.INSTANCEOF : 659 // TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool); 660 stackTypes[stackTop - 1] = INTEGER; 661 return 3; 662 case Opcode.MONITORENTER : 663 case Opcode.MONITOREXIT : 664 stackTop--; 665 // TypeData.setType(stackTypes[stackTop], "java.lang.Object", classPool); 666 break; 667 case Opcode.WIDE : 668 return doWIDE(pos, code); 669 case Opcode.MULTIANEWARRAY : 670 return doMultiANewArray(pos, code); 671 case Opcode.IFNULL : 672 case Opcode.IFNONNULL : 673 stackTop--; // branch 674 visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1)); 675 return 3; 676 case Opcode.GOTO_W : 677 visitGoto(pos, code, ByteArray.read32bit(code, pos + 1)); 678 return 5; // branch 679 case Opcode.JSR_W : 680 visitJSR(pos, code); 681 return 5; 682 } 683 return 1; 684 } 685 686 private int doWIDE(int pos, byte[] code) throws BadBytecode { 687 int op = code[pos + 1] & 0xff; 688 switch (op) { 689 case Opcode.ILOAD : 690 doWIDE_XLOAD(pos, code, INTEGER); 691 break; 692 case Opcode.LLOAD : 693 doWIDE_XLOAD(pos, code, LONG); 694 break; 695 case Opcode.FLOAD : 696 doWIDE_XLOAD(pos, code, FLOAT); 697 break; 698 case Opcode.DLOAD : 699 doWIDE_XLOAD(pos, code, DOUBLE); 700 break; 701 case Opcode.ALOAD : { 702 int index = ByteArray.readU16bit(code, pos + 2); 703 doALOAD(index); 704 break; } 705 case Opcode.ISTORE : 706 doWIDE_STORE(pos, code, INTEGER); 707 break; 708 case Opcode.LSTORE : 709 doWIDE_STORE(pos, code, LONG); 710 break; 711 case Opcode.FSTORE : 712 doWIDE_STORE(pos, code, FLOAT); 713 break; 714 case Opcode.DSTORE : 715 doWIDE_STORE(pos, code, DOUBLE); 716 break; 717 case Opcode.ASTORE : { 718 int index = ByteArray.readU16bit(code, pos + 2); 719 doASTORE(index); 720 break; } 721 case Opcode.IINC : 722 // this does not call writeLocal(). 723 return 6; 724 case Opcode.RET : 725 visitRET(pos, code); 726 break; 727 default : 728 throw new RuntimeException("bad WIDE instruction: " + op); 729 } 730 731 return 4; 732 } 733 734 private void doWIDE_XLOAD(int pos, byte[] code, TypeData type) { 735 int index = ByteArray.readU16bit(code, pos + 2); 736 doXLOAD(index, type); 737 } 738 739 private void doWIDE_STORE(int pos, byte[] code, TypeData type) { 740 int index = ByteArray.readU16bit(code, pos + 2); 741 doXSTORE(index, type); 742 } 743 744 private int doPutField(int pos, byte[] code, boolean notStatic) throws BadBytecode { 745 int index = ByteArray.readU16bit(code, pos + 1); 746 String desc = cpool.getFieldrefType(index); 747 stackTop -= Descriptor.dataSize(desc); 748 char c = desc.charAt(0); 749 if (c == 'L') 750 TypeData.setType(stackTypes[stackTop], getFieldClassName(desc, 0), classPool); 751 else if (c == '[') 752 TypeData.setType(stackTypes[stackTop], desc, classPool); 753 754 setFieldTarget(notStatic, index); 755 return 3; 756 } 757 758 private int doGetField(int pos, byte[] code, boolean notStatic) throws BadBytecode { 759 int index = ByteArray.readU16bit(code, pos + 1); 760 setFieldTarget(notStatic, index); 761 String desc = cpool.getFieldrefType(index); 762 pushMemberType(desc); 763 return 3; 764 } 765 766 private void setFieldTarget(boolean notStatic, int index) throws BadBytecode { 767 if (notStatic) { 768 String className = cpool.getFieldrefClassName(index); 769 TypeData.setType(stackTypes[--stackTop], className, classPool); 770 } 771 } 772 773 private int doNEWARRAY(int pos, byte[] code) { 774 int s = stackTop - 1; 775 String type; 776 switch (code[pos + 1] & 0xff) { 777 case Opcode.T_BOOLEAN : 778 type = "[Z"; 779 break; 780 case Opcode.T_CHAR : 781 type = "[C"; 782 break; 783 case Opcode.T_FLOAT : 784 type = "[F"; 785 break; 786 case Opcode.T_DOUBLE : 787 type = "[D"; 788 break; 789 case Opcode.T_BYTE : 790 type = "[B"; 791 break; 792 case Opcode.T_SHORT : 793 type = "[S"; 794 break; 795 case Opcode.T_INT : 796 type = "[I"; 797 break; 798 case Opcode.T_LONG : 799 type = "[J"; 800 break; 801 default : 802 throw new RuntimeException("bad newarray"); 803 } 804 805 stackTypes[s] = new TypeData.ClassName(type); 806 return 2; 807 } 808 809 private int doMultiANewArray(int pos, byte[] code) { 810 int i = ByteArray.readU16bit(code, pos + 1); 811 int dim = code[pos + 3] & 0xff; 812 stackTop -= dim - 1; 813 814 String type = cpool.getClassInfo(i).replace('.', '/'); 815 stackTypes[stackTop - 1] = new TypeData.ClassName(type); 816 return 4; 817 } 818 819 private int doInvokeMethod(int pos, byte[] code, boolean notStatic) throws BadBytecode { 820 int i = ByteArray.readU16bit(code, pos + 1); 821 String desc = cpool.getMethodrefType(i); 822 checkParamTypes(desc, 1); 823 if (notStatic) { 824 String className = cpool.getMethodrefClassName(i); 825 TypeData.setType(stackTypes[--stackTop], className, classPool); 826 } 827 828 pushMemberType(desc); 829 return 3; 830 } 831 832 private int doInvokeIntfMethod(int pos, byte[] code) throws BadBytecode { 833 int i = ByteArray.readU16bit(code, pos + 1); 834 String desc = cpool.getInterfaceMethodrefType(i); 835 checkParamTypes(desc, 1); 836 String className = cpool.getInterfaceMethodrefClassName(i); 837 TypeData.setType(stackTypes[--stackTop], className, classPool); 838 pushMemberType(desc); 839 return 5; 840 } 841 842 private void pushMemberType(String descriptor) { 843 int top = 0; 844 if (descriptor.charAt(0) == '(') { 845 top = descriptor.indexOf(')') + 1; 846 if (top < 1) 847 throw new IndexOutOfBoundsException("bad descriptor: " 848 + descriptor); 849 } 850 851 TypeData[] types = stackTypes; 852 int index = stackTop; 853 switch (descriptor.charAt(top)) { 854 case '[' : 855 types[index] = new TypeData.ClassName(descriptor.substring(top)); 856 break; 857 case 'L' : 858 types[index] = new TypeData.ClassName(getFieldClassName(descriptor, top)); 859 break; 860 case 'J' : 861 types[index] = LONG; 862 types[index + 1] = TOP; 863 stackTop += 2; 864 return; 865 case 'F' : 866 types[index] = FLOAT; 867 break; 868 case 'D' : 869 types[index] = DOUBLE; 870 types[index + 1] = TOP; 871 stackTop += 2; 872 return; 873 case 'V' : 874 return; 875 default : // C, B, S, I, Z 876 types[index] = INTEGER; 877 break; 878 } 879 880 stackTop++; 881 } 882 883 private static String getFieldClassName(String desc, int index) { 884 return desc.substring(index + 1, desc.length() - 1).replace('/', '.'); 885 } 886 887 private void checkParamTypes(String desc, int i) throws BadBytecode { 888 char c = desc.charAt(i); 889 if (c == ')') 890 return; 891 892 int k = i; 893 boolean array = false; 894 while (c == '[') { 895 array = true; 896 c = desc.charAt(++k); 897 } 898 899 if (c == 'L') { 900 k = desc.indexOf(';', k) + 1; 901 if (k <= 0) 902 throw new IndexOutOfBoundsException("bad descriptor"); 903 } 904 else 905 k++; 906 907 checkParamTypes(desc, k); 908 if (!array && (c == 'J' || c == 'D')) 909 stackTop -= 2; 910 else 911 stackTop--; 912 913 if (array) 914 TypeData.setType(stackTypes[stackTop], 915 desc.substring(i, k), classPool); 916 else if (c == 'L') 917 TypeData.setType(stackTypes[stackTop], 918 desc.substring(i + 1, k - 1).replace('/', '.'), classPool); 919 } 920 } 921