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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955
  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. if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
  1217. || srcType == VOID || type == VOID)
  1218. throw new CompileError(msg);
  1219. if (type == CLASS) {
  1220. if (!isRefType(srcType))
  1221. throw new CompileError(msg);
  1222. return toJvmArrayName(name, dim);
  1223. }
  1224. else
  1225. if (dim > 0)
  1226. return toJvmTypeName(type, dim);
  1227. else
  1228. return null; // built-in type
  1229. }
  1230. void atNumCastExpr(int srcType, int destType)
  1231. throws CompileError
  1232. {
  1233. if (srcType == destType)
  1234. return;
  1235. int op, op2;
  1236. int stype = typePrecedence(srcType);
  1237. int dtype = typePrecedence(destType);
  1238. if (0 <= stype && stype < 3)
  1239. op = castOp[stype * 4 + dtype];
  1240. else
  1241. op = NOP;
  1242. if (destType == DOUBLE)
  1243. op2 = I2D;
  1244. else if (destType == FLOAT)
  1245. op2 = I2F;
  1246. else if (destType == LONG)
  1247. op2 = I2L;
  1248. else if (destType == SHORT)
  1249. op2 = I2S;
  1250. else if (destType == CHAR)
  1251. op2 = I2C;
  1252. else if (destType == BYTE)
  1253. op2 = I2B;
  1254. else
  1255. op2 = NOP;
  1256. if (op != NOP)
  1257. bytecode.addOpcode(op);
  1258. if (op == NOP || op == L2I || op == F2I || op == D2I)
  1259. if (op2 != NOP)
  1260. bytecode.addOpcode(op2);
  1261. }
  1262. public void atExpr(Expr expr) throws CompileError {
  1263. // array access, member access,
  1264. // (unary) +, (unary) -, ++, --, !, ~
  1265. int token = expr.getOperator();
  1266. ASTree oprand = expr.oprand1();
  1267. if (token == '.') {
  1268. String member = ((Symbol)expr.oprand2()).get();
  1269. if (member.equals("class"))
  1270. atClassObject(expr); // .class
  1271. else
  1272. atFieldRead(expr);
  1273. }
  1274. else if (token == MEMBER) { // field read
  1275. /* MEMBER ('#') is an extension by Javassist.
  1276. * The compiler internally uses # for compiling .class
  1277. * expressions such as "int.class".
  1278. */
  1279. atFieldRead(expr);
  1280. }
  1281. else if (token == ARRAY)
  1282. atArrayRead(oprand, expr.oprand2());
  1283. else if (token == PLUSPLUS || token == MINUSMINUS)
  1284. atPlusPlus(token, oprand, expr, true);
  1285. else if (token == '!') {
  1286. if (!booleanExpr(false, expr)) {
  1287. bytecode.addIndex(7);
  1288. bytecode.addIconst(1);
  1289. bytecode.addOpcode(Opcode.GOTO);
  1290. bytecode.addIndex(4);
  1291. }
  1292. bytecode.addIconst(0);
  1293. }
  1294. else if (token == CALL) // method call
  1295. fatal();
  1296. else {
  1297. expr.oprand1().accept(this);
  1298. int type = typePrecedence(exprType);
  1299. if (arrayDim > 0)
  1300. badType(expr);
  1301. if (token == '-') {
  1302. if (type == P_DOUBLE)
  1303. bytecode.addOpcode(DNEG);
  1304. else if (type == P_FLOAT)
  1305. bytecode.addOpcode(FNEG);
  1306. else if (type == P_LONG)
  1307. bytecode.addOpcode(LNEG);
  1308. else if (type == P_INT) {
  1309. bytecode.addOpcode(INEG);
  1310. exprType = INT; // type may be BYTE, ...
  1311. }
  1312. else
  1313. badType(expr);
  1314. }
  1315. else if (token == '~') {
  1316. if (type == P_INT) {
  1317. bytecode.addIconst(-1);
  1318. bytecode.addOpcode(IXOR);
  1319. exprType = INT; // type may be BYTE. ...
  1320. }
  1321. else if (type == P_LONG) {
  1322. bytecode.addLconst(-1);
  1323. bytecode.addOpcode(LXOR);
  1324. }
  1325. else
  1326. badType(expr);
  1327. }
  1328. else if (token == '+') {
  1329. if (type == P_OTHER)
  1330. badType(expr);
  1331. // do nothing. ignore.
  1332. }
  1333. else
  1334. fatal();
  1335. }
  1336. }
  1337. protected static void badType(Expr expr) throws CompileError {
  1338. throw new CompileError("invalid type for " + expr.getName());
  1339. }
  1340. public abstract void atCallExpr(CallExpr expr) throws CompileError;
  1341. protected abstract void atFieldRead(ASTree expr) throws CompileError;
  1342. public void atClassObject(Expr expr) throws CompileError {
  1343. ASTree op1 = expr.oprand1();
  1344. if (!(op1 instanceof Symbol))
  1345. throw new CompileError("fatal error: badly parsed .class expr");
  1346. String cname = ((Symbol)op1).get();
  1347. if (cname.startsWith("[")) {
  1348. int i = cname.indexOf("[L");
  1349. if (i >= 0) {
  1350. String name = cname.substring(i + 2, cname.length() - 1);
  1351. String name2 = resolveClassName(name);
  1352. if (!name.equals(name2)) {
  1353. /* For example, to obtain String[].class,
  1354. * "[Ljava.lang.String;" (not "[Ljava/lang/String"!)
  1355. * must be passed to Class.forName().
  1356. */
  1357. name2 = MemberResolver.jvmToJavaName(name2);
  1358. StringBuffer sbuf = new StringBuffer();
  1359. while (i-- >= 0)
  1360. sbuf.append('[');
  1361. sbuf.append('L').append(name2).append(';');
  1362. cname = sbuf.toString();
  1363. }
  1364. }
  1365. }
  1366. else {
  1367. cname = resolveClassName(MemberResolver.javaToJvmName(cname));
  1368. cname = MemberResolver.jvmToJavaName(cname);
  1369. }
  1370. atClassObject2(cname);
  1371. exprType = CLASS;
  1372. arrayDim = 0;
  1373. className = "java/lang/Class";
  1374. }
  1375. /* MemberCodeGen overrides this method.
  1376. */
  1377. protected void atClassObject2(String cname) throws CompileError {
  1378. int start = bytecode.currentPc();
  1379. bytecode.addLdc(cname);
  1380. bytecode.addInvokestatic("java.lang.Class", "forName",
  1381. "(Ljava/lang/String;)Ljava/lang/Class;");
  1382. int end = bytecode.currentPc();
  1383. bytecode.addOpcode(Opcode.GOTO);
  1384. int pc = bytecode.currentPc();
  1385. bytecode.addIndex(0); // correct later
  1386. bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
  1387. "java.lang.ClassNotFoundException");
  1388. /* -- the following code is for inlining a call to DotClass.fail().
  1389. int var = getMaxLocals();
  1390. incMaxLocals(1);
  1391. bytecode.growStack(1);
  1392. bytecode.addAstore(var);
  1393. bytecode.addNew("java.lang.NoClassDefFoundError");
  1394. bytecode.addOpcode(DUP);
  1395. bytecode.addAload(var);
  1396. bytecode.addInvokevirtual("java.lang.ClassNotFoundException",
  1397. "getMessage", "()Ljava/lang/String;");
  1398. bytecode.addInvokespecial("java.lang.NoClassDefFoundError", "<init>",
  1399. "(Ljava/lang/String;)V");
  1400. */
  1401. bytecode.growStack(1);
  1402. bytecode.addInvokestatic("javassist.runtime.DotClass", "fail",
  1403. "(Ljava/lang/ClassNotFoundException;)"
  1404. + "Ljava/lang/NoClassDefFoundError;");
  1405. bytecode.addOpcode(ATHROW);
  1406. bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
  1407. }
  1408. public void atArrayRead(ASTree array, ASTree index)
  1409. throws CompileError
  1410. {
  1411. arrayAccess(array, index);
  1412. bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
  1413. }
  1414. protected void arrayAccess(ASTree array, ASTree index)
  1415. throws CompileError
  1416. {
  1417. array.accept(this);
  1418. int type = exprType;
  1419. int dim = arrayDim;
  1420. if (dim == 0)
  1421. throw new CompileError("bad array access");
  1422. String cname = className;
  1423. index.accept(this);
  1424. if (typePrecedence(exprType) != P_INT || arrayDim > 0)
  1425. throw new CompileError("bad array index");
  1426. exprType = type;
  1427. arrayDim = dim - 1;
  1428. className = cname;
  1429. }
  1430. protected static int getArrayReadOp(int type, int dim) {
  1431. if (dim > 0)
  1432. return AALOAD;
  1433. switch (type) {
  1434. case DOUBLE :
  1435. return DALOAD;
  1436. case FLOAT :
  1437. return FALOAD;
  1438. case LONG :
  1439. return LALOAD;
  1440. case INT :
  1441. return IALOAD;
  1442. case SHORT :
  1443. return SALOAD;
  1444. case CHAR :
  1445. return CALOAD;
  1446. case BYTE :
  1447. case BOOLEAN :
  1448. return BALOAD;
  1449. default :
  1450. return AALOAD;
  1451. }
  1452. }
  1453. protected static int getArrayWriteOp(int type, int dim) {
  1454. if (dim > 0)
  1455. return AASTORE;
  1456. switch (type) {
  1457. case DOUBLE :
  1458. return DASTORE;
  1459. case FLOAT :
  1460. return FASTORE;
  1461. case LONG :
  1462. return LASTORE;
  1463. case INT :
  1464. return IASTORE;
  1465. case SHORT :
  1466. return SASTORE;
  1467. case CHAR :
  1468. return CASTORE;
  1469. case BYTE :
  1470. case BOOLEAN :
  1471. return BASTORE;
  1472. default :
  1473. return AASTORE;
  1474. }
  1475. }
  1476. private void atPlusPlus(int token, ASTree oprand, Expr expr,
  1477. boolean doDup) throws CompileError
  1478. {
  1479. boolean isPost = oprand == null; // ++i or i++?
  1480. if (isPost)
  1481. oprand = expr.oprand2();
  1482. if (oprand instanceof Variable) {
  1483. Declarator d = ((Variable)oprand).getDeclarator();
  1484. int t = exprType = d.getType();
  1485. arrayDim = d.getArrayDim();
  1486. int var = getLocalVar(d);
  1487. if (arrayDim > 0)
  1488. badType(expr);
  1489. if (t == DOUBLE) {
  1490. bytecode.addDload(var);
  1491. if (doDup && isPost)
  1492. bytecode.addOpcode(DUP2);
  1493. bytecode.addDconst(1.0);
  1494. bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
  1495. if (doDup && !isPost)
  1496. bytecode.addOpcode(DUP2);
  1497. bytecode.addDstore(var);
  1498. }
  1499. else if (t == LONG) {
  1500. bytecode.addLload(var);
  1501. if (doDup && isPost)
  1502. bytecode.addOpcode(DUP2);
  1503. bytecode.addLconst((long)1);
  1504. bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
  1505. if (doDup && !isPost)
  1506. bytecode.addOpcode(DUP2);
  1507. bytecode.addLstore(var);
  1508. }
  1509. else if (t == FLOAT) {
  1510. bytecode.addFload(var);
  1511. if (doDup && isPost)
  1512. bytecode.addOpcode(DUP);
  1513. bytecode.addFconst(1.0f);
  1514. bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
  1515. if (doDup && !isPost)
  1516. bytecode.addOpcode(DUP);
  1517. bytecode.addFstore(var);
  1518. }
  1519. else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
  1520. if (doDup && isPost)
  1521. bytecode.addIload(var);
  1522. int delta = token == PLUSPLUS ? 1 : -1;
  1523. if (var > 0xff) {
  1524. bytecode.addOpcode(WIDE);
  1525. bytecode.addOpcode(IINC);
  1526. bytecode.addIndex(var);
  1527. bytecode.addIndex(delta);
  1528. }
  1529. else {
  1530. bytecode.addOpcode(IINC);
  1531. bytecode.add(var);
  1532. bytecode.add(delta);
  1533. }
  1534. if (doDup && !isPost)
  1535. bytecode.addIload(var);
  1536. }
  1537. else
  1538. badType(expr);
  1539. }
  1540. else {
  1541. if (oprand instanceof Expr) {
  1542. Expr e = (Expr)oprand;
  1543. if (e.getOperator() == ARRAY) {
  1544. atArrayPlusPlus(token, isPost, e, doDup);
  1545. return;
  1546. }
  1547. }
  1548. atFieldPlusPlus(token, isPost, oprand, expr, doDup);
  1549. }
  1550. }
  1551. public void atArrayPlusPlus(int token, boolean isPost,
  1552. Expr expr, boolean doDup) throws CompileError
  1553. {
  1554. arrayAccess(expr.oprand1(), expr.oprand2());
  1555. int t = exprType;
  1556. int dim = arrayDim;
  1557. if (dim > 0)
  1558. badType(expr);
  1559. bytecode.addOpcode(DUP2);
  1560. bytecode.addOpcode(getArrayReadOp(t, arrayDim));
  1561. int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2;
  1562. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  1563. bytecode.addOpcode(getArrayWriteOp(t, dim));
  1564. }
  1565. protected void atPlusPlusCore(int dup_code, boolean doDup,
  1566. int token, boolean isPost,
  1567. Expr expr) throws CompileError
  1568. {
  1569. int t = exprType;
  1570. if (doDup && isPost)
  1571. bytecode.addOpcode(dup_code);
  1572. if (t == INT || t == BYTE || t == CHAR || t == SHORT) {
  1573. bytecode.addIconst(1);
  1574. bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB);
  1575. exprType = INT;
  1576. }
  1577. else if (t == LONG) {
  1578. bytecode.addLconst((long)1);
  1579. bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
  1580. }
  1581. else if (t == FLOAT) {
  1582. bytecode.addFconst(1.0f);
  1583. bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
  1584. }
  1585. else if (t == DOUBLE) {
  1586. bytecode.addDconst(1.0);
  1587. bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
  1588. }
  1589. else
  1590. badType(expr);
  1591. if (doDup && !isPost)
  1592. bytecode.addOpcode(dup_code);
  1593. }
  1594. protected abstract void atFieldPlusPlus(int token, boolean isPost,
  1595. ASTree oprand, Expr expr, boolean doDup) throws CompileError;
  1596. public abstract void atMember(Member n) throws CompileError;
  1597. public void atVariable(Variable v) throws CompileError {
  1598. Declarator d = v.getDeclarator();
  1599. exprType = d.getType();
  1600. arrayDim = d.getArrayDim();
  1601. className = d.getClassName();
  1602. int var = getLocalVar(d);
  1603. if (arrayDim > 0)
  1604. bytecode.addAload(var);
  1605. else
  1606. switch (exprType) {
  1607. case CLASS :
  1608. bytecode.addAload(var);
  1609. break;
  1610. case LONG :
  1611. bytecode.addLload(var);
  1612. break;
  1613. case FLOAT :
  1614. bytecode.addFload(var);
  1615. break;
  1616. case DOUBLE :
  1617. bytecode.addDload(var);
  1618. break;
  1619. default : // BOOLEAN, BYTE, CHAR, SHORT, INT
  1620. bytecode.addIload(var);
  1621. break;
  1622. }
  1623. }
  1624. public void atKeyword(Keyword k) throws CompileError {
  1625. arrayDim = 0;
  1626. int token = k.get();
  1627. switch (token) {
  1628. case TRUE :
  1629. bytecode.addIconst(1);
  1630. exprType = BOOLEAN;
  1631. break;
  1632. case FALSE :
  1633. bytecode.addIconst(0);
  1634. exprType = BOOLEAN;
  1635. break;
  1636. case NULL :
  1637. bytecode.addOpcode(ACONST_NULL);
  1638. exprType = NULL;
  1639. break;
  1640. case THIS :
  1641. case SUPER :
  1642. if (inStaticMethod)
  1643. throw new CompileError("not-available: "
  1644. + (token == THIS ? "this" : "super"));
  1645. bytecode.addAload(0);
  1646. exprType = CLASS;
  1647. if (token == THIS)
  1648. className = getThisName();
  1649. else
  1650. className = getSuperName();
  1651. break;
  1652. default :
  1653. fatal();
  1654. }
  1655. }
  1656. public void atStringL(StringL s) throws CompileError {
  1657. exprType = CLASS;
  1658. arrayDim = 0;
  1659. className = jvmJavaLangString;
  1660. bytecode.addLdc(s.get());
  1661. }
  1662. public void atIntConst(IntConst i) throws CompileError {
  1663. arrayDim = 0;
  1664. long value = i.get();
  1665. int type = i.getType();
  1666. if (type == IntConstant || type == CharConstant) {
  1667. exprType = (type == IntConstant ? INT : CHAR);
  1668. bytecode.addIconst((int)value);
  1669. }
  1670. else {
  1671. exprType = LONG;
  1672. bytecode.addLconst(value);
  1673. }
  1674. }
  1675. public void atDoubleConst(DoubleConst d) throws CompileError {
  1676. arrayDim = 0;
  1677. if (d.getType() == DoubleConstant) {
  1678. exprType = DOUBLE;
  1679. bytecode.addDconst(d.get());
  1680. }
  1681. else {
  1682. exprType = FLOAT;
  1683. bytecode.addFconst((float)d.get());
  1684. }
  1685. }
  1686. }