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