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.

CodeGen.java 60KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956
  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.compiler;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import javassist.compiler.ast.*;
  20. import javassist.bytecode.*;
  21. /* The code generator is implemeted by three files:
  22. * CodeGen.java, MemberCodeGen.java, and JvstCodeGen.
  23. * I just wanted to split a big file into three smaller ones.
  24. */
  25. public abstract class CodeGen extends Visitor implements Opcode, TokenId {
  26. static final String javaLangObject = "java.lang.Object";
  27. static final String jvmJavaLangObject = "java/lang/Object";
  28. static final String javaLangString = "java.lang.String";
  29. static final String jvmJavaLangString = "java/lang/String";
  30. protected Bytecode bytecode;
  31. private int tempVar;
  32. TypeChecker typeChecker;
  33. /**
  34. * true if the last visited node is a return statement.
  35. */
  36. protected boolean hasReturned;
  37. /**
  38. * Must be true if compilation is for a static method.
  39. */
  40. public boolean inStaticMethod;
  41. protected ArrayList breakList, continueList;
  42. /**
  43. * doit() in ReturnHook is called from atReturn().
  44. */
  45. protected static abstract class ReturnHook {
  46. ReturnHook next;
  47. /**
  48. * Returns true if the generated code ends with return,
  49. * throw, or goto.
  50. */
  51. protected abstract boolean doit(Bytecode b, int opcode);
  52. protected ReturnHook(CodeGen gen) {
  53. next = gen.returnHooks;
  54. gen.returnHooks = this;
  55. }
  56. protected void remove(CodeGen gen) {
  57. gen.returnHooks = next;
  58. }
  59. }
  60. protected ReturnHook returnHooks;
  61. /* The following fields are used by atXXX() methods
  62. * for returning the type of the compiled expression.
  63. */
  64. protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
  65. protected int arrayDim;
  66. protected String className; // JVM-internal representation
  67. public CodeGen(Bytecode b) {
  68. bytecode = b;
  69. tempVar = -1;
  70. typeChecker = null;
  71. hasReturned = false;
  72. inStaticMethod = false;
  73. breakList = null;
  74. continueList = null;
  75. returnHooks = null;
  76. }
  77. public void setTypeChecker(TypeChecker checker) {
  78. typeChecker = checker;
  79. }
  80. protected static void fatal() throws CompileError {
  81. throw new CompileError("fatal");
  82. }
  83. public static boolean is2word(int type, int dim) {
  84. return dim == 0 && (type == DOUBLE || type == LONG);
  85. }
  86. public int getMaxLocals() { return bytecode.getMaxLocals(); }
  87. public void setMaxLocals(int n) {
  88. bytecode.setMaxLocals(n);
  89. }
  90. protected void incMaxLocals(int size) {
  91. bytecode.incMaxLocals(size);
  92. }
  93. /**
  94. * Returns a local variable that single or double words can be
  95. * stored in.
  96. */
  97. protected int getTempVar() {
  98. if (tempVar < 0) {
  99. tempVar = getMaxLocals();
  100. incMaxLocals(2);
  101. }
  102. return tempVar;
  103. }
  104. protected int getLocalVar(Declarator d) {
  105. int v = d.getLocalVar();
  106. if (v < 0) {
  107. v = getMaxLocals(); // delayed variable allocation.
  108. d.setLocalVar(v);
  109. incMaxLocals(1);
  110. }
  111. return v;
  112. }
  113. /**
  114. * Returns the JVM-internal representation of this class name.
  115. */
  116. protected abstract String getThisName();
  117. /**
  118. * Returns the JVM-internal representation of this super class name.
  119. */
  120. protected abstract String getSuperName() throws CompileError;
  121. /* Converts a class name into a JVM-internal representation.
  122. *
  123. * It may also expand a simple class name to java.lang.*.
  124. * For example, this converts Object into java/lang/Object.
  125. */
  126. protected abstract String resolveClassName(ASTList name)
  127. throws CompileError;
  128. /* Expands a simple class name to java.lang.*.
  129. * For example, this converts Object into java/lang/Object.
  130. */
  131. protected abstract String resolveClassName(String jvmClassName)
  132. throws CompileError;
  133. /**
  134. * @param name the JVM-internal representation.
  135. * name is not exapnded to java.lang.*.
  136. */
  137. protected static String toJvmArrayName(String name, int dim) {
  138. if (name == null)
  139. return null;
  140. if (dim == 0)
  141. return name;
  142. else {
  143. StringBuffer sbuf = new StringBuffer();
  144. int d = dim;
  145. while (d-- > 0)
  146. sbuf.append('[');
  147. sbuf.append('L');
  148. sbuf.append(name);
  149. sbuf.append(';');
  150. return sbuf.toString();
  151. }
  152. }
  153. protected static String toJvmTypeName(int type, int dim) {
  154. char c = 'I';
  155. switch(type) {
  156. case BOOLEAN :
  157. c = 'Z';
  158. break;
  159. case BYTE :
  160. c = 'B';
  161. break;
  162. case CHAR :
  163. c = 'C';
  164. break;
  165. case SHORT :
  166. c = 'S';
  167. break;
  168. case INT :
  169. c = 'I';
  170. break;
  171. case LONG :
  172. c = 'J';
  173. break;
  174. case FLOAT :
  175. c = 'F';
  176. break;
  177. case DOUBLE :
  178. c = 'D';
  179. break;
  180. case VOID :
  181. c = 'V';
  182. break;
  183. }
  184. StringBuffer sbuf = new StringBuffer();
  185. while (dim-- > 0)
  186. sbuf.append('[');
  187. sbuf.append(c);
  188. return sbuf.toString();
  189. }
  190. public void compileExpr(ASTree expr) throws CompileError {
  191. doTypeCheck(expr);
  192. expr.accept(this);
  193. }
  194. public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
  195. throws CompileError
  196. {
  197. doTypeCheck(expr);
  198. return booleanExpr(branchIf, expr);
  199. }
  200. public void doTypeCheck(ASTree expr) throws CompileError {
  201. if (typeChecker != null)
  202. expr.accept(typeChecker);
  203. }
  204. public void atASTList(ASTList n) throws CompileError { fatal(); }
  205. public void atPair(Pair n) throws CompileError { fatal(); }
  206. public void atSymbol(Symbol n) throws CompileError { fatal(); }
  207. public void atFieldDecl(FieldDecl field) throws CompileError {
  208. field.getInit().accept(this);
  209. }
  210. public void atMethodDecl(MethodDecl method) throws CompileError {
  211. ASTList mods = method.getModifiers();
  212. setMaxLocals(1);
  213. while (mods != null) {
  214. Keyword k = (Keyword)mods.head();
  215. mods = mods.tail();
  216. if (k.get() == STATIC) {
  217. setMaxLocals(0);
  218. inStaticMethod = true;
  219. }
  220. }
  221. ASTList params = method.getParams();
  222. while (params != null) {
  223. atDeclarator((Declarator)params.head());
  224. params = params.tail();
  225. }
  226. Stmnt s = method.getBody();
  227. atMethodBody(s, method.isConstructor(),
  228. method.getReturn().getType() == VOID);
  229. }
  230. /**
  231. * @param isCons true if super() must be called.
  232. * false if the method is a class initializer.
  233. */
  234. public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid)
  235. throws CompileError
  236. {
  237. if (s == null)
  238. return;
  239. if (isCons && needsSuperCall(s))
  240. insertDefaultSuperCall();
  241. hasReturned = false;
  242. s.accept(this);
  243. if (!hasReturned)
  244. if (isVoid) {
  245. bytecode.addOpcode(Opcode.RETURN);
  246. hasReturned = true;
  247. }
  248. else
  249. throw new CompileError("no return statement");
  250. }
  251. private boolean needsSuperCall(Stmnt body) throws CompileError {
  252. if (body.getOperator() == BLOCK)
  253. body = (Stmnt)body.head();
  254. if (body != null && body.getOperator() == EXPR) {
  255. ASTree expr = body.head();
  256. if (expr != null && expr instanceof Expr
  257. && ((Expr)expr).getOperator() == CALL) {
  258. ASTree target = ((Expr)expr).head();
  259. if (target instanceof Keyword) {
  260. int token = ((Keyword)target).get();
  261. return token != THIS && token != SUPER;
  262. }
  263. }
  264. }
  265. return true;
  266. }
  267. protected abstract void insertDefaultSuperCall() throws CompileError;
  268. public void atStmnt(Stmnt st) throws CompileError {
  269. if (st == null)
  270. return; // empty
  271. int op = st.getOperator();
  272. if (op == EXPR) {
  273. ASTree expr = st.getLeft();
  274. doTypeCheck(expr);
  275. if (expr instanceof AssignExpr)
  276. atAssignExpr((AssignExpr)expr, false);
  277. else if (isPlusPlusExpr(expr)) {
  278. Expr e = (Expr)expr;
  279. atPlusPlus(e.getOperator(), e.oprand1(), e, false);
  280. }
  281. else {
  282. expr.accept(this);
  283. if (is2word(exprType, arrayDim))
  284. bytecode.addOpcode(POP2);
  285. else if (exprType != VOID)
  286. bytecode.addOpcode(POP);
  287. }
  288. }
  289. else if (op == DECL || op == BLOCK) {
  290. ASTList list = st;
  291. while (list != null) {
  292. ASTree h = list.head();
  293. list = list.tail();
  294. if (h != null)
  295. h.accept(this);
  296. }
  297. }
  298. else if (op == IF)
  299. atIfStmnt(st);
  300. else if (op == WHILE || op == DO)
  301. atWhileStmnt(st, op == WHILE);
  302. else if (op == FOR)
  303. atForStmnt(st);
  304. else if (op == BREAK || op == CONTINUE)
  305. atBreakStmnt(st, op == BREAK);
  306. else if (op == TokenId.RETURN)
  307. atReturnStmnt(st);
  308. else if (op == THROW)
  309. atThrowStmnt(st);
  310. else if (op == TRY)
  311. atTryStmnt(st);
  312. else if (op == SWITCH)
  313. atSwitchStmnt(st);
  314. else if (op == SYNCHRONIZED)
  315. atSyncStmnt(st);
  316. else {
  317. // LABEL, SWITCH label stament might be null?.
  318. hasReturned = false;
  319. throw new CompileError(
  320. "sorry, not supported statement: TokenId " + op);
  321. }
  322. }
  323. private void atIfStmnt(Stmnt st) throws CompileError {
  324. ASTree expr = st.head();
  325. Stmnt thenp = (Stmnt)st.tail().head();
  326. Stmnt elsep = (Stmnt)st.tail().tail().head();
  327. if (compileBooleanExpr(false, expr)) {
  328. hasReturned = false;
  329. if (elsep != null)
  330. elsep.accept(this);
  331. return;
  332. }
  333. int pc = bytecode.currentPc();
  334. int pc2 = 0;
  335. bytecode.addIndex(0); // correct later
  336. hasReturned = false;
  337. if (thenp != null)
  338. thenp.accept(this);
  339. boolean thenHasReturned = hasReturned;
  340. hasReturned = false;
  341. if (elsep != null && !thenHasReturned) {
  342. bytecode.addOpcode(Opcode.GOTO);
  343. pc2 = bytecode.currentPc();
  344. bytecode.addIndex(0);
  345. }
  346. bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
  347. if (elsep != null) {
  348. elsep.accept(this);
  349. if (!thenHasReturned)
  350. bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
  351. hasReturned = thenHasReturned && hasReturned;
  352. }
  353. }
  354. private void atWhileStmnt(Stmnt st, boolean notDo) throws CompileError {
  355. ArrayList prevBreakList = breakList;
  356. ArrayList prevContList = continueList;
  357. breakList = new ArrayList();
  358. continueList = new ArrayList();
  359. ASTree expr = st.head();
  360. Stmnt body = (Stmnt)st.tail();
  361. int pc = 0;
  362. if (notDo) {
  363. bytecode.addOpcode(Opcode.GOTO);
  364. pc = bytecode.currentPc();
  365. bytecode.addIndex(0);
  366. }
  367. int pc2 = bytecode.currentPc();
  368. if (body != null)
  369. body.accept(this);
  370. int pc3 = bytecode.currentPc();
  371. if (notDo)
  372. bytecode.write16bit(pc, pc3 - pc + 1);
  373. boolean alwaysBranch = compileBooleanExpr(true, expr);
  374. if (alwaysBranch) {
  375. bytecode.addOpcode(Opcode.GOTO);
  376. alwaysBranch = breakList.size() == 0;
  377. }
  378. bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
  379. patchGoto(breakList, bytecode.currentPc());
  380. patchGoto(continueList, pc3);
  381. continueList = prevContList;
  382. breakList = prevBreakList;
  383. hasReturned = alwaysBranch;
  384. }
  385. protected void patchGoto(ArrayList list, int targetPc) {
  386. int n = list.size();
  387. for (int i = 0; i < n; ++i) {
  388. int pc = ((Integer)list.get(i)).intValue();
  389. bytecode.write16bit(pc, targetPc - pc + 1);
  390. }
  391. }
  392. private void atForStmnt(Stmnt st) throws CompileError {
  393. ArrayList prevBreakList = breakList;
  394. ArrayList prevContList = continueList;
  395. breakList = new ArrayList();
  396. continueList = new ArrayList();
  397. Stmnt init = (Stmnt)st.head();
  398. ASTList p = st.tail();
  399. ASTree expr = p.head();
  400. p = p.tail();
  401. Stmnt update = (Stmnt)p.head();
  402. Stmnt body = (Stmnt)p.tail();
  403. if (init != null)
  404. init.accept(this);
  405. int pc = bytecode.currentPc();
  406. int pc2 = 0;
  407. if (expr != null) {
  408. if (compileBooleanExpr(false, expr)) {
  409. // in case of "for (...; false; ...)"
  410. continueList = prevContList;
  411. breakList = prevBreakList;
  412. hasReturned = false;
  413. return;
  414. }
  415. pc2 = bytecode.currentPc();
  416. bytecode.addIndex(0);
  417. }
  418. if (body != null)
  419. body.accept(this);
  420. int pc3 = bytecode.currentPc();
  421. if (update != null)
  422. update.accept(this);
  423. bytecode.addOpcode(Opcode.GOTO);
  424. bytecode.addIndex(pc - bytecode.currentPc() + 1);
  425. int pc4 = bytecode.currentPc();
  426. if (expr != null)
  427. bytecode.write16bit(pc2, pc4 - pc2 + 1);
  428. patchGoto(breakList, pc4);
  429. patchGoto(continueList, pc3);
  430. continueList = prevContList;
  431. breakList = prevBreakList;
  432. hasReturned = false;
  433. }
  434. private void atSwitchStmnt(Stmnt st) throws CompileError {
  435. compileExpr(st.head());
  436. ArrayList prevBreakList = breakList;
  437. breakList = new ArrayList();
  438. int opcodePc = bytecode.currentPc();
  439. bytecode.addOpcode(LOOKUPSWITCH);
  440. int npads = 3 - (opcodePc & 3);
  441. while (npads-- > 0)
  442. bytecode.add(0);
  443. Stmnt body = (Stmnt)st.tail();
  444. int npairs = 0;
  445. for (ASTList list = body; list != null; list = list.tail())
  446. if (((Stmnt)list.head()).getOperator() == CASE)
  447. ++npairs;
  448. // opcodePc2 is the position at which the default jump offset is.
  449. int opcodePc2 = bytecode.currentPc();
  450. bytecode.addGap(4);
  451. bytecode.add32bit(npairs);
  452. bytecode.addGap(npairs * 8);
  453. long[] pairs = new long[npairs];
  454. int ipairs = 0;
  455. int defaultPc = -1;
  456. for (ASTList list = body; list != null; list = list.tail()) {
  457. Stmnt label = (Stmnt)list.head();
  458. int op = label.getOperator();
  459. if (op == DEFAULT)
  460. defaultPc = bytecode.currentPc();
  461. else if (op != CASE)
  462. fatal();
  463. else {
  464. pairs[ipairs++]
  465. = ((long)computeLabel(label.head()) << 32) +
  466. ((long)(bytecode.currentPc() - opcodePc) & 0xffffffff);
  467. }
  468. hasReturned = false;
  469. ((Stmnt)label.tail()).accept(this);
  470. }
  471. Arrays.sort(pairs);
  472. int pc = opcodePc2 + 8;
  473. for (int i = 0; i < npairs; ++i) {
  474. bytecode.write32bit(pc, (int)(pairs[i] >>> 32));
  475. bytecode.write32bit(pc + 4, (int)pairs[i]);
  476. pc += 8;
  477. }
  478. if (defaultPc < 0 || breakList.size() > 0)
  479. hasReturned = false;
  480. int endPc = bytecode.currentPc();
  481. if (defaultPc < 0)
  482. defaultPc = endPc;
  483. bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
  484. patchGoto(breakList, endPc);
  485. breakList = prevBreakList;
  486. }
  487. private int computeLabel(ASTree expr) throws CompileError {
  488. doTypeCheck(expr);
  489. expr = TypeChecker.stripPlusExpr(expr);
  490. if (expr instanceof IntConst)
  491. return (int)((IntConst)expr).get();
  492. else
  493. throw new CompileError("bad case label");
  494. }
  495. private void atBreakStmnt(Stmnt st, boolean notCont)
  496. throws CompileError
  497. {
  498. if (st.head() != null)
  499. throw new CompileError(
  500. "sorry, not support labeled break or continue");
  501. bytecode.addOpcode(Opcode.GOTO);
  502. Integer pc = new Integer(bytecode.currentPc());
  503. bytecode.addIndex(0);
  504. if (notCont)
  505. breakList.add(pc);
  506. else
  507. continueList.add(pc);
  508. }
  509. protected void atReturnStmnt(Stmnt st) throws CompileError {
  510. atReturnStmnt2(st.getLeft());
  511. }
  512. protected final void atReturnStmnt2(ASTree result) throws CompileError {
  513. int op;
  514. if (result == null)
  515. op = Opcode.RETURN;
  516. else {
  517. compileExpr(result);
  518. if (arrayDim > 0)
  519. op = ARETURN;
  520. else {
  521. int type = exprType;
  522. if (type == DOUBLE)
  523. op = DRETURN;
  524. else if (type == FLOAT)
  525. op = FRETURN;
  526. else if (type == LONG)
  527. op = LRETURN;
  528. else if (isRefType(type))
  529. op = ARETURN;
  530. else
  531. op = IRETURN;
  532. }
  533. }
  534. for (ReturnHook har = returnHooks; har != null; har = har.next)
  535. if (har.doit(bytecode, op)) {
  536. hasReturned = true;
  537. return;
  538. }
  539. bytecode.addOpcode(op);
  540. hasReturned = true;
  541. }
  542. private void atThrowStmnt(Stmnt st) throws CompileError {
  543. ASTree e = st.getLeft();
  544. compileExpr(e);
  545. if (exprType != CLASS || arrayDim > 0)
  546. throw new CompileError("bad throw statement");
  547. bytecode.addOpcode(ATHROW);
  548. hasReturned = true;
  549. }
  550. /* overridden in MemberCodeGen
  551. */
  552. protected void atTryStmnt(Stmnt st) throws CompileError {
  553. hasReturned = false;
  554. }
  555. private void atSyncStmnt(Stmnt st) throws CompileError {
  556. int nbreaks = getListSize(breakList);
  557. int ncontinues = getListSize(continueList);
  558. compileExpr(st.head());
  559. if (exprType != CLASS && arrayDim == 0)
  560. throw new CompileError("bad type expr for synchronized block");
  561. Bytecode bc = bytecode;
  562. final int var = bc.getMaxLocals();
  563. bc.incMaxLocals(1);
  564. bc.addOpcode(DUP);
  565. bc.addAstore(var);
  566. bc.addOpcode(MONITORENTER);
  567. ReturnHook rh = new ReturnHook(this) {
  568. protected boolean doit(Bytecode b, int opcode) {
  569. b.addAload(var);
  570. b.addOpcode(MONITOREXIT);
  571. return false;
  572. }
  573. };
  574. int pc = bc.currentPc();
  575. Stmnt body = (Stmnt)st.tail();
  576. if (body != null)
  577. body.accept(this);
  578. int pc2 = bc.currentPc();
  579. int pc3 = 0;
  580. if (!hasReturned) {
  581. rh.doit(bc, 0); // the 2nd arg is ignored.
  582. bc.addOpcode(Opcode.GOTO);
  583. pc3 = bc.currentPc();
  584. bc.addIndex(0);
  585. }
  586. if (pc < pc2) { // if the body is not empty
  587. int pc4 = bc.currentPc();
  588. rh.doit(bc, 0); // the 2nd arg is ignored.
  589. bc.addOpcode(ATHROW);
  590. bc.addExceptionHandler(pc, pc2, pc4, 0);
  591. }
  592. if (!hasReturned)
  593. bc.write16bit(pc3, bc.currentPc() - pc3 + 1);
  594. rh.remove(this);
  595. if (getListSize(breakList) != nbreaks
  596. || getListSize(continueList) != ncontinues)
  597. throw new CompileError(
  598. "sorry, cannot break/continue in synchronized block");
  599. }
  600. private static int getListSize(ArrayList list) {
  601. return list == null ? 0 : list.size();
  602. }
  603. private static boolean isPlusPlusExpr(ASTree expr) {
  604. if (expr instanceof Expr) {
  605. int op = ((Expr)expr).getOperator();
  606. return op == PLUSPLUS || op == MINUSMINUS;
  607. }
  608. return false;
  609. }
  610. public void atDeclarator(Declarator d) throws CompileError {
  611. d.setLocalVar(getMaxLocals());
  612. d.setClassName(resolveClassName(d.getClassName()));
  613. int size;
  614. if (is2word(d.getType(), d.getArrayDim()))
  615. size = 2;
  616. else
  617. size = 1;
  618. incMaxLocals(size);
  619. /* NOTE: Array initializers has not been supported.
  620. */
  621. ASTree init = d.getInitializer();
  622. if (init != null) {
  623. doTypeCheck(init);
  624. atVariableAssign(null, '=', null, d, init, false);
  625. }
  626. }
  627. public abstract void atNewExpr(NewExpr n) throws CompileError;
  628. public abstract void atArrayInit(ArrayInit init) throws CompileError;
  629. public void atAssignExpr(AssignExpr expr) throws CompileError {
  630. atAssignExpr(expr, true);
  631. }
  632. protected void atAssignExpr(AssignExpr expr, boolean doDup)
  633. throws CompileError
  634. {
  635. // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
  636. int op = expr.getOperator();
  637. ASTree left = expr.oprand1();
  638. ASTree right = expr.oprand2();
  639. if (left instanceof Variable)
  640. atVariableAssign(expr, op, (Variable)left,
  641. ((Variable)left).getDeclarator(),
  642. right, doDup);
  643. else {
  644. if (left instanceof Expr) {
  645. Expr e = (Expr)left;
  646. if (e.getOperator() == ARRAY) {
  647. atArrayAssign(expr, op, (Expr)left, right, doDup);
  648. return;
  649. }
  650. }
  651. atFieldAssign(expr, op, left, right, doDup);
  652. }
  653. }
  654. protected static void badAssign(Expr expr) throws CompileError {
  655. String msg;
  656. if (expr == null)
  657. msg = "incompatible type for assignment";
  658. else
  659. msg = "incompatible type for " + expr.getName();
  660. throw new CompileError(msg);
  661. }
  662. /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
  663. *
  664. * expr and var can be null.
  665. */
  666. private void atVariableAssign(Expr expr, int op, Variable var,
  667. Declarator d, ASTree right,
  668. boolean doDup) throws CompileError
  669. {
  670. int varType = d.getType();
  671. int varArray = d.getArrayDim();
  672. String varClass = d.getClassName();
  673. int varNo = getLocalVar(d);
  674. if (op != '=')
  675. atVariable(var);
  676. // expr is null if the caller is atDeclarator().
  677. if (expr == null && right instanceof ArrayInit)
  678. atArrayVariableAssign((ArrayInit)right, varType, varArray, varClass);
  679. else
  680. atAssignCore(expr, op, right, varType, varArray, varClass);
  681. if (doDup)
  682. if (is2word(varType, varArray))
  683. bytecode.addOpcode(DUP2);
  684. else
  685. bytecode.addOpcode(DUP);
  686. if (varArray > 0)
  687. bytecode.addAstore(varNo);
  688. else if (varType == DOUBLE)
  689. bytecode.addDstore(varNo);
  690. else if (varType == FLOAT)
  691. bytecode.addFstore(varNo);
  692. else if (varType == LONG)
  693. bytecode.addLstore(varNo);
  694. else if (isRefType(varType))
  695. bytecode.addAstore(varNo);
  696. else
  697. bytecode.addIstore(varNo);
  698. exprType = varType;
  699. arrayDim = varArray;
  700. className = varClass;
  701. }
  702. protected abstract void atArrayVariableAssign(ArrayInit init,
  703. int varType, int varArray, String varClass) throws CompileError;
  704. private void atArrayAssign(Expr expr, int op, Expr array,
  705. ASTree right, boolean doDup) throws CompileError
  706. {
  707. arrayAccess(array.oprand1(), array.oprand2());
  708. if (op != '=') {
  709. bytecode.addOpcode(DUP2);
  710. bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
  711. }
  712. int aType = exprType;
  713. int aDim = arrayDim;
  714. String cname = className;
  715. atAssignCore(expr, op, right, aType, aDim, cname);
  716. if (doDup)
  717. if (is2word(aType, aDim))
  718. bytecode.addOpcode(DUP2_X2);
  719. else
  720. bytecode.addOpcode(DUP_X2);
  721. bytecode.addOpcode(getArrayWriteOp(aType, aDim));
  722. exprType = aType;
  723. arrayDim = aDim;
  724. className = cname;
  725. }
  726. protected abstract void atFieldAssign(Expr expr, int op, ASTree left,
  727. ASTree right, boolean doDup) throws CompileError;
  728. protected void atAssignCore(Expr expr, int op, ASTree right,
  729. int type, int dim, String cname)
  730. throws CompileError
  731. {
  732. if (op == PLUS_E && dim == 0 && type == CLASS)
  733. atStringPlusEq(expr, type, dim, cname, right);
  734. else {
  735. right.accept(this);
  736. if (invalidDim(exprType, arrayDim, className, type, dim, cname,
  737. false) || (op != '=' && dim > 0))
  738. badAssign(expr);
  739. if (op != '=') {
  740. int token = assignOps[op - MOD_E];
  741. int k = lookupBinOp(token);
  742. if (k < 0)
  743. fatal();
  744. atArithBinExpr(expr, token, k, type);
  745. }
  746. }
  747. if (op != '=' || (dim == 0 && !isRefType(type)))
  748. atNumCastExpr(exprType, type);
  749. // type check should be done here.
  750. }
  751. private void atStringPlusEq(Expr expr, int type, int dim, String cname,
  752. ASTree right)
  753. throws CompileError
  754. {
  755. if (!jvmJavaLangString.equals(cname))
  756. badAssign(expr);
  757. convToString(type, dim); // the value might be null.
  758. right.accept(this);
  759. convToString(exprType, arrayDim);
  760. bytecode.addInvokevirtual(javaLangString, "concat",
  761. "(Ljava/lang/String;)Ljava/lang/String;");
  762. exprType = CLASS;
  763. arrayDim = 0;
  764. className = jvmJavaLangString;
  765. }
  766. private boolean invalidDim(int srcType, int srcDim, String srcClass,
  767. int destType, int destDim, String destClass,
  768. boolean isCast)
  769. {
  770. if (srcDim != destDim)
  771. if (srcType == NULL)
  772. return false;
  773. else if (destDim == 0 && destType == CLASS
  774. && jvmJavaLangObject.equals(destClass))
  775. return false;
  776. else if (isCast && srcDim == 0 && srcType == CLASS
  777. && jvmJavaLangObject.equals(srcClass))
  778. return false;
  779. else
  780. return true;
  781. return false;
  782. }
  783. public void atCondExpr(CondExpr expr) throws CompileError {
  784. if (booleanExpr(false, expr.condExpr()))
  785. expr.elseExpr().accept(this);
  786. else {
  787. int pc = bytecode.currentPc();
  788. bytecode.addIndex(0); // correct later
  789. expr.thenExpr().accept(this);
  790. int dim1 = arrayDim;
  791. bytecode.addOpcode(Opcode.GOTO);
  792. int pc2 = bytecode.currentPc();
  793. bytecode.addIndex(0);
  794. bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
  795. expr.elseExpr().accept(this);
  796. if (dim1 != arrayDim)
  797. throw new CompileError("type mismatch in ?:");
  798. bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
  799. }
  800. }
  801. static final int[] binOp = {
  802. '+', DADD, FADD, LADD, IADD,
  803. '-', DSUB, FSUB, LSUB, ISUB,
  804. '*', DMUL, FMUL, LMUL, IMUL,
  805. '/', DDIV, FDIV, LDIV, IDIV,
  806. '%', DREM, FREM, LREM, IREM,
  807. '|', NOP, NOP, LOR, IOR,
  808. '^', NOP, NOP, LXOR, IXOR,
  809. '&', NOP, NOP, LAND, IAND,
  810. LSHIFT, NOP, NOP, LSHL, ISHL,
  811. RSHIFT, NOP, NOP, LSHR, ISHR,
  812. ARSHIFT, NOP, NOP, LUSHR, IUSHR };
  813. static int lookupBinOp(int token) {
  814. int[] code = binOp;
  815. int s = code.length;
  816. for (int k = 0; k < s; k = k + 5)
  817. if (code[k] == token)
  818. return k;
  819. return -1;
  820. }
  821. public void atBinExpr(BinExpr expr) throws CompileError {
  822. int token = expr.getOperator();
  823. /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
  824. */
  825. int k = lookupBinOp(token);
  826. if (k >= 0) {
  827. expr.oprand1().accept(this);
  828. ASTree right = expr.oprand2();
  829. if (right == null)
  830. return; // see TypeChecker.atBinExpr().
  831. int type1 = exprType;
  832. int dim1 = arrayDim;
  833. String cname1 = className;
  834. right.accept(this);
  835. if (dim1 != arrayDim)
  836. throw new CompileError("incompatible array types");
  837. if (token == '+' && dim1 == 0
  838. && (type1 == CLASS || exprType == CLASS))
  839. atStringConcatExpr(expr, type1, dim1, cname1);
  840. else
  841. atArithBinExpr(expr, token, k, type1);
  842. }
  843. else {
  844. /* equation: &&, ||, ==, !=, <=, >=, <, >
  845. */
  846. if (!booleanExpr(true, expr)) {
  847. bytecode.addIndex(7);
  848. bytecode.addIconst(0); // false
  849. bytecode.addOpcode(Opcode.GOTO);
  850. bytecode.addIndex(4);
  851. }
  852. bytecode.addIconst(1); // true
  853. }
  854. }
  855. /* arrayDim values of the two oprands must be equal.
  856. * If an oprand type is not a numeric type, this method
  857. * throws an exception.
  858. */
  859. private void atArithBinExpr(Expr expr, int token,
  860. int index, int type1) throws CompileError
  861. {
  862. if (arrayDim != 0)
  863. badTypes(expr);
  864. int type2 = exprType;
  865. if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
  866. if (type2 == INT || type2 == SHORT
  867. || type2 == CHAR || type2 == BYTE)
  868. exprType = type1;
  869. else
  870. badTypes(expr);
  871. else
  872. convertOprandTypes(type1, type2, expr);
  873. int p = typePrecedence(exprType);
  874. if (p >= 0) {
  875. int op = binOp[index + p + 1];
  876. if (op != NOP) {
  877. if (p == P_INT && exprType != BOOLEAN)
  878. exprType = INT; // type1 may be BYTE, ...
  879. bytecode.addOpcode(op);
  880. return;
  881. }
  882. }
  883. badTypes(expr);
  884. }
  885. private void atStringConcatExpr(Expr expr, int type1, int dim1,
  886. String cname1) throws CompileError
  887. {
  888. int type2 = exprType;
  889. int dim2 = arrayDim;
  890. boolean type2Is2 = is2word(type2, dim2);
  891. boolean type2IsString
  892. = (type2 == CLASS && jvmJavaLangString.equals(className));
  893. if (type2Is2)
  894. convToString(type2, dim2);
  895. if (is2word(type1, dim1)) {
  896. bytecode.addOpcode(DUP_X2);
  897. bytecode.addOpcode(POP);
  898. }
  899. else
  900. bytecode.addOpcode(SWAP);
  901. // even if type1 is String, the left operand might be null.
  902. convToString(type1, dim1);
  903. bytecode.addOpcode(SWAP);
  904. if (!type2Is2 && !type2IsString)
  905. convToString(type2, dim2);
  906. bytecode.addInvokevirtual(javaLangString, "concat",
  907. "(Ljava/lang/String;)Ljava/lang/String;");
  908. exprType = CLASS;
  909. arrayDim = 0;
  910. className = jvmJavaLangString;
  911. }
  912. private void convToString(int type, int dim) throws CompileError {
  913. final String method = "valueOf";
  914. if (isRefType(type) || dim > 0)
  915. bytecode.addInvokestatic(javaLangString, method,
  916. "(Ljava/lang/Object;)Ljava/lang/String;");
  917. else if (type == DOUBLE)
  918. bytecode.addInvokestatic(javaLangString, method,
  919. "(D)Ljava/lang/String;");
  920. else if (type == FLOAT)
  921. bytecode.addInvokestatic(javaLangString, method,
  922. "(F)Ljava/lang/String;");
  923. else if (type == LONG)
  924. bytecode.addInvokestatic(javaLangString, method,
  925. "(J)Ljava/lang/String;");
  926. else if (type == BOOLEAN)
  927. bytecode.addInvokestatic(javaLangString, method,
  928. "(Z)Ljava/lang/String;");
  929. else if (type == CHAR)
  930. bytecode.addInvokestatic(javaLangString, method,
  931. "(C)Ljava/lang/String;");
  932. else if (type == VOID)
  933. throw new CompileError("void type expression");
  934. else /* INT, BYTE, SHORT */
  935. bytecode.addInvokestatic(javaLangString, method,
  936. "(I)Ljava/lang/String;");
  937. }
  938. /* Produces the opcode to branch if the condition is true.
  939. * The oprand (branch offset) is not produced.
  940. *
  941. * @return true if the compiled code is GOTO (always branch).
  942. * GOTO is not produced.
  943. */
  944. private boolean booleanExpr(boolean branchIf, ASTree expr)
  945. throws CompileError
  946. {
  947. boolean isAndAnd;
  948. int op = getCompOperator(expr);
  949. if (op == EQ) { // ==, !=, ...
  950. BinExpr bexpr = (BinExpr)expr;
  951. int type1 = compileOprands(bexpr);
  952. // here, arrayDim might represent the array dim. of the left oprand
  953. // if the right oprand is NULL.
  954. compareExpr(branchIf, bexpr.getOperator(), type1, bexpr);
  955. }
  956. else if (op == '!')
  957. return booleanExpr(!branchIf, ((Expr)expr).oprand1());
  958. else if ((isAndAnd = (op == ANDAND)) || op == OROR) {
  959. BinExpr bexpr = (BinExpr)expr;
  960. if (booleanExpr(!isAndAnd, bexpr.oprand1())) {
  961. exprType = BOOLEAN;
  962. arrayDim = 0;
  963. return true;
  964. }
  965. else {
  966. int pc = bytecode.currentPc();
  967. bytecode.addIndex(0); // correct later
  968. if (booleanExpr(isAndAnd, bexpr.oprand2()))
  969. bytecode.addOpcode(Opcode.GOTO);
  970. bytecode.write16bit(pc, bytecode.currentPc() - pc + 3);
  971. if (branchIf != isAndAnd) {
  972. bytecode.addIndex(6); // skip GOTO instruction
  973. bytecode.addOpcode(Opcode.GOTO);
  974. }
  975. }
  976. }
  977. else if (isAlwaysBranch(expr, branchIf)) {
  978. // Opcode.GOTO is not added here. The caller must add it.
  979. exprType = BOOLEAN;
  980. arrayDim = 0;
  981. return true; // always branch
  982. }
  983. else { // others
  984. expr.accept(this);
  985. if (exprType != BOOLEAN || arrayDim != 0)
  986. throw new CompileError("boolean expr is required");
  987. bytecode.addOpcode(branchIf ? IFNE : IFEQ);
  988. }
  989. exprType = BOOLEAN;
  990. arrayDim = 0;
  991. return false;
  992. }
  993. private static boolean isAlwaysBranch(ASTree expr, boolean branchIf) {
  994. if (expr instanceof Keyword) {
  995. int t = ((Keyword)expr).get();
  996. return branchIf ? t == TRUE : t == FALSE;
  997. }
  998. return false;
  999. }
  1000. static int getCompOperator(ASTree expr) throws CompileError {
  1001. if (expr instanceof Expr) {
  1002. Expr bexpr = (Expr)expr;
  1003. int token = bexpr.getOperator();
  1004. if (token == '!')
  1005. return '!';
  1006. else if ((bexpr instanceof BinExpr)
  1007. && token != OROR && token != ANDAND
  1008. && token != '&' && token != '|')
  1009. return EQ; // ==, !=, ...
  1010. else
  1011. return token;
  1012. }
  1013. return ' '; // others
  1014. }
  1015. private int compileOprands(BinExpr expr) throws CompileError {
  1016. expr.oprand1().accept(this);
  1017. int type1 = exprType;
  1018. int dim1 = arrayDim;
  1019. expr.oprand2().accept(this);
  1020. if (dim1 != arrayDim)
  1021. if (type1 != NULL && exprType != NULL)
  1022. throw new CompileError("incompatible array types");
  1023. else if (exprType == NULL)
  1024. arrayDim = dim1;
  1025. if (type1 == NULL)
  1026. return exprType;
  1027. else
  1028. return type1;
  1029. }
  1030. private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
  1031. NEQ, IF_ICMPNE, IF_ICMPEQ,
  1032. LE, IF_ICMPLE, IF_ICMPGT,
  1033. GE, IF_ICMPGE, IF_ICMPLT,
  1034. '<', IF_ICMPLT, IF_ICMPGE,
  1035. '>', IF_ICMPGT, IF_ICMPLE };
  1036. private static final int ifOp2[] = { EQ, IFEQ, IFNE,
  1037. NEQ, IFNE, IFEQ,
  1038. LE, IFLE, IFGT,
  1039. GE, IFGE, IFLT,
  1040. '<', IFLT, IFGE,
  1041. '>', IFGT, IFLE };
  1042. /* Produces the opcode to branch if the condition is true.
  1043. * The oprands are not produced.
  1044. *
  1045. * Parameter expr - compare expression ==, !=, <=, >=, <, >
  1046. */
  1047. private void compareExpr(boolean branchIf,
  1048. int token, int type1, BinExpr expr)
  1049. throws CompileError
  1050. {
  1051. if (arrayDim == 0)
  1052. convertOprandTypes(type1, exprType, expr);
  1053. int p = typePrecedence(exprType);
  1054. if (p == P_OTHER || arrayDim > 0)
  1055. if (token == EQ)
  1056. bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE);
  1057. else if (token == NEQ)
  1058. bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ);
  1059. else
  1060. badTypes(expr);
  1061. else
  1062. if (p == P_INT) {
  1063. int op[] = ifOp;
  1064. for (int i = 0; i < op.length; i += 3)
  1065. if (op[i] == token) {
  1066. bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
  1067. return;
  1068. }
  1069. badTypes(expr);
  1070. }
  1071. else {
  1072. if (p == P_DOUBLE)
  1073. if (token == '<' || token == LE)
  1074. bytecode.addOpcode(DCMPG);
  1075. else
  1076. bytecode.addOpcode(DCMPL);
  1077. else if (p == P_FLOAT)
  1078. if (token == '<' || token == LE)
  1079. bytecode.addOpcode(FCMPG);
  1080. else
  1081. bytecode.addOpcode(FCMPL);
  1082. else if (p == P_LONG)
  1083. bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
  1084. else
  1085. fatal();
  1086. int[] op = ifOp2;
  1087. for (int i = 0; i < op.length; i += 3)
  1088. if (op[i] == token) {
  1089. bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
  1090. return;
  1091. }
  1092. badTypes(expr);
  1093. }
  1094. }
  1095. protected static void badTypes(Expr expr) throws CompileError {
  1096. throw new CompileError("invalid types for " + expr.getName());
  1097. }
  1098. private static final int P_DOUBLE = 0;
  1099. private static final int P_FLOAT = 1;
  1100. private static final int P_LONG = 2;
  1101. private static final int P_INT = 3;
  1102. private static final int P_OTHER = -1;
  1103. protected static boolean isRefType(int type) {
  1104. return type == CLASS || type == NULL;
  1105. }
  1106. private static int typePrecedence(int type) {
  1107. if (type == DOUBLE)
  1108. return P_DOUBLE;
  1109. else if (type == FLOAT)
  1110. return P_FLOAT;
  1111. else if (type == LONG)
  1112. return P_LONG;
  1113. else if (isRefType(type))
  1114. return P_OTHER;
  1115. else if (type == VOID)
  1116. return P_OTHER; // this is wrong, but ...
  1117. else
  1118. return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT
  1119. }
  1120. // used in TypeChecker.
  1121. static boolean isP_INT(int type) {
  1122. return typePrecedence(type) == P_INT;
  1123. }
  1124. // used in TypeChecker.
  1125. static boolean rightIsStrong(int type1, int type2) {
  1126. int type1_p = typePrecedence(type1);
  1127. int type2_p = typePrecedence(type2);
  1128. return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p;
  1129. }
  1130. private static final int[] castOp = {
  1131. /* D F L I */
  1132. /* double */ NOP, D2F, D2L, D2I,
  1133. /* float */ F2D, NOP, F2L, F2I,
  1134. /* long */ L2D, L2F, NOP, L2I,
  1135. /* other */ I2D, I2F, I2L, NOP };
  1136. /* do implicit type conversion.
  1137. * arrayDim values of the two oprands must be zero.
  1138. */
  1139. private void convertOprandTypes(int type1, int type2, Expr expr)
  1140. throws CompileError
  1141. {
  1142. boolean rightStrong;
  1143. int type1_p = typePrecedence(type1);
  1144. int type2_p = typePrecedence(type2);
  1145. if (type2_p < 0 && type1_p < 0) // not primitive types
  1146. return;
  1147. if (type2_p < 0 || type1_p < 0) // either is not a primitive type
  1148. badTypes(expr);
  1149. int op, result_type;
  1150. if (type1_p <= type2_p) {
  1151. rightStrong = false;
  1152. exprType = type1;
  1153. op = castOp[type2_p * 4 + type1_p];
  1154. result_type = type1_p;
  1155. }
  1156. else {
  1157. rightStrong = true;
  1158. op = castOp[type1_p * 4 + type2_p];
  1159. result_type = type2_p;
  1160. }
  1161. if (rightStrong) {
  1162. if (result_type == P_DOUBLE || result_type == P_LONG) {
  1163. if (type1_p == P_DOUBLE || type1_p == P_LONG)
  1164. bytecode.addOpcode(DUP2_X2);
  1165. else
  1166. bytecode.addOpcode(DUP2_X1);
  1167. bytecode.addOpcode(POP2);
  1168. bytecode.addOpcode(op);
  1169. bytecode.addOpcode(DUP2_X2);
  1170. bytecode.addOpcode(POP2);
  1171. }
  1172. else if (result_type == P_FLOAT) {
  1173. if (type1_p == P_LONG) {
  1174. bytecode.addOpcode(DUP_X2);
  1175. bytecode.addOpcode(POP);
  1176. }
  1177. else
  1178. bytecode.addOpcode(SWAP);
  1179. bytecode.addOpcode(op);
  1180. bytecode.addOpcode(SWAP);
  1181. }
  1182. else
  1183. fatal();
  1184. }
  1185. else if (op != NOP)
  1186. bytecode.addOpcode(op);
  1187. }
  1188. public void atCastExpr(CastExpr expr) throws CompileError {
  1189. String cname = resolveClassName(expr.getClassName());
  1190. String toClass = checkCastExpr(expr, cname);
  1191. int srcType = exprType;
  1192. exprType = expr.getType();
  1193. arrayDim = expr.getArrayDim();
  1194. className = cname;
  1195. if (toClass == null)
  1196. atNumCastExpr(srcType, exprType); // built-in type
  1197. else
  1198. bytecode.addCheckcast(toClass);
  1199. }
  1200. public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
  1201. String cname = resolveClassName(expr.getClassName());
  1202. String toClass = checkCastExpr(expr, cname);
  1203. bytecode.addInstanceof(toClass);
  1204. exprType = BOOLEAN;
  1205. arrayDim = 0;
  1206. }
  1207. private String checkCastExpr(CastExpr expr, String name)
  1208. throws CompileError
  1209. {
  1210. final String msg = "invalid cast";
  1211. ASTree oprand = expr.getOprand();
  1212. int dim = expr.getArrayDim();
  1213. int type = expr.getType();
  1214. oprand.accept(this);
  1215. int srcType = exprType;
  1216. int srcDim = arrayDim;
  1217. if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
  1218. || srcType == VOID || type == VOID)
  1219. throw new CompileError(msg);
  1220. if (type == CLASS) {
  1221. if (!isRefType(srcType) && srcDim == 0)
  1222. throw new CompileError(msg);
  1223. return toJvmArrayName(name, dim);
  1224. }
  1225. else
  1226. if (dim > 0)
  1227. return toJvmTypeName(type, dim);
  1228. else
  1229. return null; // built-in type
  1230. }
  1231. void atNumCastExpr(int srcType, int destType)
  1232. throws CompileError
  1233. {
  1234. if (srcType == destType)
  1235. return;
  1236. int op, op2;
  1237. int stype = typePrecedence(srcType);
  1238. int dtype = typePrecedence(destType);
  1239. if (0 <= stype && stype < 3)
  1240. op = castOp[stype * 4 + dtype];
  1241. else
  1242. op = NOP;
  1243. if (destType == DOUBLE)
  1244. op2 = I2D;
  1245. else if (destType == FLOAT)
  1246. op2 = I2F;
  1247. else if (destType == LONG)
  1248. op2 = I2L;
  1249. else if (destType == SHORT)
  1250. op2 = I2S;
  1251. else if (destType == CHAR)
  1252. op2 = I2C;
  1253. else if (destType == BYTE)
  1254. op2 = I2B;
  1255. else
  1256. op2 = NOP;
  1257. if (op != NOP)
  1258. bytecode.addOpcode(op);
  1259. if (op == NOP || op == L2I || op == F2I || op == D2I)
  1260. if (op2 != NOP)
  1261. bytecode.addOpcode(op2);
  1262. }
  1263. public void atExpr(Expr expr) throws CompileError {
  1264. // array access, member access,
  1265. // (unary) +, (unary) -, ++, --, !, ~
  1266. int token = expr.getOperator();
  1267. ASTree oprand = expr.oprand1();
  1268. if (token == '.') {
  1269. String member = ((Symbol)expr.oprand2()).get();
  1270. if (member.equals("class"))
  1271. atClassObject(expr); // .class
  1272. else
  1273. atFieldRead(expr);
  1274. }
  1275. else if (token == MEMBER) { // field read
  1276. /* MEMBER ('#') is an extension by Javassist.
  1277. * The compiler internally uses # for compiling .class
  1278. * expressions such as "int.class".
  1279. */
  1280. atFieldRead(expr);
  1281. }
  1282. else if (token == ARRAY)
  1283. atArrayRead(oprand, expr.oprand2());
  1284. else if (token == PLUSPLUS || token == MINUSMINUS)
  1285. atPlusPlus(token, oprand, expr, true);
  1286. else if (token == '!') {
  1287. if (!booleanExpr(false, expr)) {
  1288. bytecode.addIndex(7);
  1289. bytecode.addIconst(1);
  1290. bytecode.addOpcode(Opcode.GOTO);
  1291. bytecode.addIndex(4);
  1292. }
  1293. bytecode.addIconst(0);
  1294. }
  1295. else if (token == CALL) // method call
  1296. fatal();
  1297. else {
  1298. expr.oprand1().accept(this);
  1299. int type = typePrecedence(exprType);
  1300. if (arrayDim > 0)
  1301. badType(expr);
  1302. if (token == '-') {
  1303. if (type == P_DOUBLE)
  1304. bytecode.addOpcode(DNEG);
  1305. else if (type == P_FLOAT)
  1306. bytecode.addOpcode(FNEG);
  1307. else if (type == P_LONG)
  1308. bytecode.addOpcode(LNEG);
  1309. else if (type == P_INT) {
  1310. bytecode.addOpcode(INEG);
  1311. exprType = INT; // type may be BYTE, ...
  1312. }
  1313. else
  1314. badType(expr);
  1315. }
  1316. else if (token == '~') {
  1317. if (type == P_INT) {
  1318. bytecode.addIconst(-1);
  1319. bytecode.addOpcode(IXOR);
  1320. exprType = INT; // type may be BYTE. ...
  1321. }
  1322. else if (type == P_LONG) {
  1323. bytecode.addLconst(-1);
  1324. bytecode.addOpcode(LXOR);
  1325. }
  1326. else
  1327. badType(expr);
  1328. }
  1329. else if (token == '+') {
  1330. if (type == P_OTHER)
  1331. badType(expr);
  1332. // do nothing. ignore.
  1333. }
  1334. else
  1335. fatal();
  1336. }
  1337. }
  1338. protected static void badType(Expr expr) throws CompileError {
  1339. throw new CompileError("invalid type for " + expr.getName());
  1340. }
  1341. public abstract void atCallExpr(CallExpr expr) throws CompileError;
  1342. protected abstract void atFieldRead(ASTree expr) throws CompileError;
  1343. public void atClassObject(Expr expr) throws CompileError {
  1344. ASTree op1 = expr.oprand1();
  1345. if (!(op1 instanceof Symbol))
  1346. throw new CompileError("fatal error: badly parsed .class expr");
  1347. String cname = ((Symbol)op1).get();
  1348. if (cname.startsWith("[")) {
  1349. int i = cname.indexOf("[L");
  1350. if (i >= 0) {
  1351. String name = cname.substring(i + 2, cname.length() - 1);
  1352. String name2 = resolveClassName(name);
  1353. if (!name.equals(name2)) {
  1354. /* For example, to obtain String[].class,
  1355. * "[Ljava.lang.String;" (not "[Ljava/lang/String"!)
  1356. * must be passed to Class.forName().
  1357. */
  1358. name2 = MemberResolver.jvmToJavaName(name2);
  1359. StringBuffer sbuf = new StringBuffer();
  1360. while (i-- >= 0)
  1361. sbuf.append('[');
  1362. sbuf.append('L').append(name2).append(';');
  1363. cname = sbuf.toString();
  1364. }
  1365. }
  1366. }
  1367. else {
  1368. cname = resolveClassName(MemberResolver.javaToJvmName(cname));
  1369. cname = MemberResolver.jvmToJavaName(cname);
  1370. }
  1371. atClassObject2(cname);
  1372. exprType = CLASS;
  1373. arrayDim = 0;
  1374. className = "java/lang/Class";
  1375. }
  1376. /* MemberCodeGen overrides this method.
  1377. */
  1378. protected void atClassObject2(String cname) throws CompileError {
  1379. int start = bytecode.currentPc();
  1380. bytecode.addLdc(cname);
  1381. bytecode.addInvokestatic("java.lang.Class", "forName",
  1382. "(Ljava/lang/String;)Ljava/lang/Class;");
  1383. int end = bytecode.currentPc();
  1384. bytecode.addOpcode(Opcode.GOTO);
  1385. int pc = bytecode.currentPc();
  1386. bytecode.addIndex(0); // correct later
  1387. bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
  1388. "java.lang.ClassNotFoundException");
  1389. /* -- the following code is for inlining a call to DotClass.fail().
  1390. int var = getMaxLocals();
  1391. incMaxLocals(1);
  1392. bytecode.growStack(1);
  1393. bytecode.addAstore(var);
  1394. bytecode.addNew("java.lang.NoClassDefFoundError");
  1395. bytecode.addOpcode(DUP);
  1396. bytecode.addAload(var);
  1397. bytecode.addInvokevirtual("java.lang.ClassNotFoundException",
  1398. "getMessage", "()Ljava/lang/String;");
  1399. bytecode.addInvokespecial("java.lang.NoClassDefFoundError", "<init>",
  1400. "(Ljava/lang/String;)V");
  1401. */
  1402. bytecode.growStack(1);
  1403. bytecode.addInvokestatic("javassist.runtime.DotClass", "fail",
  1404. "(Ljava/lang/ClassNotFoundException;)"
  1405. + "Ljava/lang/NoClassDefFoundError;");
  1406. bytecode.addOpcode(ATHROW);
  1407. bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
  1408. }
  1409. public void atArrayRead(ASTree array, ASTree index)
  1410. throws CompileError
  1411. {
  1412. arrayAccess(array, index);
  1413. bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
  1414. }
  1415. protected void arrayAccess(ASTree array, ASTree index)
  1416. throws CompileError
  1417. {
  1418. array.accept(this);
  1419. int type = exprType;
  1420. int dim = arrayDim;
  1421. if (dim == 0)
  1422. throw new CompileError("bad array access");
  1423. String cname = className;
  1424. index.accept(this);
  1425. if (typePrecedence(exprType) != P_INT || arrayDim > 0)
  1426. throw new CompileError("bad array index");
  1427. exprType = type;
  1428. arrayDim = dim - 1;
  1429. className = cname;
  1430. }
  1431. protected static int getArrayReadOp(int type, int dim) {
  1432. if (dim > 0)
  1433. return AALOAD;
  1434. switch (type) {
  1435. case DOUBLE :
  1436. return DALOAD;
  1437. case FLOAT :
  1438. return FALOAD;
  1439. case LONG :
  1440. return LALOAD;
  1441. case INT :
  1442. return IALOAD;
  1443. case SHORT :
  1444. return SALOAD;
  1445. case CHAR :
  1446. return CALOAD;
  1447. case BYTE :
  1448. case BOOLEAN :
  1449. return BALOAD;
  1450. default :
  1451. return AALOAD;
  1452. }
  1453. }
  1454. protected static int getArrayWriteOp(int type, int dim) {
  1455. if (dim > 0)
  1456. return AASTORE;
  1457. switch (type) {
  1458. case DOUBLE :
  1459. return DASTORE;
  1460. case FLOAT :
  1461. return FASTORE;
  1462. case LONG :
  1463. return LASTORE;
  1464. case INT :
  1465. return IASTORE;
  1466. case SHORT :
  1467. return SASTORE;
  1468. case CHAR :
  1469. return CASTORE;
  1470. case BYTE :
  1471. case BOOLEAN :
  1472. return BASTORE;
  1473. default :
  1474. return AASTORE;
  1475. }
  1476. }
  1477. private void atPlusPlus(int token, ASTree oprand, Expr expr,
  1478. boolean doDup) throws CompileError
  1479. {
  1480. boolean isPost = oprand == null; // ++i or i++?
  1481. if (isPost)
  1482. oprand = expr.oprand2();
  1483. if (oprand instanceof Variable) {
  1484. Declarator d = ((Variable)oprand).getDeclarator();
  1485. int t = exprType = d.getType();
  1486. arrayDim = d.getArrayDim();
  1487. int var = getLocalVar(d);
  1488. if (arrayDim > 0)
  1489. badType(expr);
  1490. if (t == DOUBLE) {
  1491. bytecode.addDload(var);
  1492. if (doDup && isPost)
  1493. bytecode.addOpcode(DUP2);
  1494. bytecode.addDconst(1.0);
  1495. bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
  1496. if (doDup && !isPost)
  1497. bytecode.addOpcode(DUP2);
  1498. bytecode.addDstore(var);
  1499. }
  1500. else if (t == LONG) {
  1501. bytecode.addLload(var);
  1502. if (doDup && isPost)
  1503. bytecode.addOpcode(DUP2);
  1504. bytecode.addLconst((long)1);
  1505. bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
  1506. if (doDup && !isPost)
  1507. bytecode.addOpcode(DUP2);
  1508. bytecode.addLstore(var);
  1509. }
  1510. else if (t == FLOAT) {
  1511. bytecode.addFload(var);
  1512. if (doDup && isPost)
  1513. bytecode.addOpcode(DUP);
  1514. bytecode.addFconst(1.0f);
  1515. bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
  1516. if (doDup && !isPost)
  1517. bytecode.addOpcode(DUP);
  1518. bytecode.addFstore(var);
  1519. }
  1520. else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
  1521. if (doDup && isPost)
  1522. bytecode.addIload(var);
  1523. int delta = token == PLUSPLUS ? 1 : -1;
  1524. if (var > 0xff) {
  1525. bytecode.addOpcode(WIDE);
  1526. bytecode.addOpcode(IINC);
  1527. bytecode.addIndex(var);
  1528. bytecode.addIndex(delta);
  1529. }
  1530. else {
  1531. bytecode.addOpcode(IINC);
  1532. bytecode.add(var);
  1533. bytecode.add(delta);
  1534. }
  1535. if (doDup && !isPost)
  1536. bytecode.addIload(var);
  1537. }
  1538. else
  1539. badType(expr);
  1540. }
  1541. else {
  1542. if (oprand instanceof Expr) {
  1543. Expr e = (Expr)oprand;
  1544. if (e.getOperator() == ARRAY) {
  1545. atArrayPlusPlus(token, isPost, e, doDup);
  1546. return;
  1547. }
  1548. }
  1549. atFieldPlusPlus(token, isPost, oprand, expr, doDup);
  1550. }
  1551. }
  1552. public void atArrayPlusPlus(int token, boolean isPost,
  1553. Expr expr, boolean doDup) throws CompileError
  1554. {
  1555. arrayAccess(expr.oprand1(), expr.oprand2());
  1556. int t = exprType;
  1557. int dim = arrayDim;
  1558. if (dim > 0)
  1559. badType(expr);
  1560. bytecode.addOpcode(DUP2);
  1561. bytecode.addOpcode(getArrayReadOp(t, arrayDim));
  1562. int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2;
  1563. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  1564. bytecode.addOpcode(getArrayWriteOp(t, dim));
  1565. }
  1566. protected void atPlusPlusCore(int dup_code, boolean doDup,
  1567. int token, boolean isPost,
  1568. Expr expr) throws CompileError
  1569. {
  1570. int t = exprType;
  1571. if (doDup && isPost)
  1572. bytecode.addOpcode(dup_code);
  1573. if (t == INT || t == BYTE || t == CHAR || t == SHORT) {
  1574. bytecode.addIconst(1);
  1575. bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB);
  1576. exprType = INT;
  1577. }
  1578. else if (t == LONG) {
  1579. bytecode.addLconst((long)1);
  1580. bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
  1581. }
  1582. else if (t == FLOAT) {
  1583. bytecode.addFconst(1.0f);
  1584. bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
  1585. }
  1586. else if (t == DOUBLE) {
  1587. bytecode.addDconst(1.0);
  1588. bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
  1589. }
  1590. else
  1591. badType(expr);
  1592. if (doDup && !isPost)
  1593. bytecode.addOpcode(dup_code);
  1594. }
  1595. protected abstract void atFieldPlusPlus(int token, boolean isPost,
  1596. ASTree oprand, Expr expr, boolean doDup) throws CompileError;
  1597. public abstract void atMember(Member n) throws CompileError;
  1598. public void atVariable(Variable v) throws CompileError {
  1599. Declarator d = v.getDeclarator();
  1600. exprType = d.getType();
  1601. arrayDim = d.getArrayDim();
  1602. className = d.getClassName();
  1603. int var = getLocalVar(d);
  1604. if (arrayDim > 0)
  1605. bytecode.addAload(var);
  1606. else
  1607. switch (exprType) {
  1608. case CLASS :
  1609. bytecode.addAload(var);
  1610. break;
  1611. case LONG :
  1612. bytecode.addLload(var);
  1613. break;
  1614. case FLOAT :
  1615. bytecode.addFload(var);
  1616. break;
  1617. case DOUBLE :
  1618. bytecode.addDload(var);
  1619. break;
  1620. default : // BOOLEAN, BYTE, CHAR, SHORT, INT
  1621. bytecode.addIload(var);
  1622. break;
  1623. }
  1624. }
  1625. public void atKeyword(Keyword k) throws CompileError {
  1626. arrayDim = 0;
  1627. int token = k.get();
  1628. switch (token) {
  1629. case TRUE :
  1630. bytecode.addIconst(1);
  1631. exprType = BOOLEAN;
  1632. break;
  1633. case FALSE :
  1634. bytecode.addIconst(0);
  1635. exprType = BOOLEAN;
  1636. break;
  1637. case NULL :
  1638. bytecode.addOpcode(ACONST_NULL);
  1639. exprType = NULL;
  1640. break;
  1641. case THIS :
  1642. case SUPER :
  1643. if (inStaticMethod)
  1644. throw new CompileError("not-available: "
  1645. + (token == THIS ? "this" : "super"));
  1646. bytecode.addAload(0);
  1647. exprType = CLASS;
  1648. if (token == THIS)
  1649. className = getThisName();
  1650. else
  1651. className = getSuperName();
  1652. break;
  1653. default :
  1654. fatal();
  1655. }
  1656. }
  1657. public void atStringL(StringL s) throws CompileError {
  1658. exprType = CLASS;
  1659. arrayDim = 0;
  1660. className = jvmJavaLangString;
  1661. bytecode.addLdc(s.get());
  1662. }
  1663. public void atIntConst(IntConst i) throws CompileError {
  1664. arrayDim = 0;
  1665. long value = i.get();
  1666. int type = i.getType();
  1667. if (type == IntConstant || type == CharConstant) {
  1668. exprType = (type == IntConstant ? INT : CHAR);
  1669. bytecode.addIconst((int)value);
  1670. }
  1671. else {
  1672. exprType = LONG;
  1673. bytecode.addLconst(value);
  1674. }
  1675. }
  1676. public void atDoubleConst(DoubleConst d) throws CompileError {
  1677. arrayDim = 0;
  1678. if (d.getType() == DoubleConstant) {
  1679. exprType = DOUBLE;
  1680. bytecode.addDconst(d.get());
  1681. }
  1682. else {
  1683. exprType = FLOAT;
  1684. bytecode.addFconst((float)d.get());
  1685. }
  1686. }
  1687. }