Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

CodeGen.java 63KB

10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
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. }