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

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