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

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