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 30KB

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