You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Tracer.java 31KB

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