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.

MemberCodeGen.java 39KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208
  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.List;
  19. import javassist.ClassPool;
  20. import javassist.CtClass;
  21. import javassist.CtField;
  22. import javassist.CtMethod;
  23. import javassist.Modifier;
  24. import javassist.NotFoundException;
  25. import javassist.bytecode.AccessFlag;
  26. import javassist.bytecode.Bytecode;
  27. import javassist.bytecode.ClassFile;
  28. import javassist.bytecode.ConstPool;
  29. import javassist.bytecode.Descriptor;
  30. import javassist.bytecode.FieldInfo;
  31. import javassist.bytecode.MethodInfo;
  32. import javassist.bytecode.Opcode;
  33. import javassist.compiler.ast.ASTList;
  34. import javassist.compiler.ast.ASTree;
  35. import javassist.compiler.ast.ArrayInit;
  36. import javassist.compiler.ast.CallExpr;
  37. import javassist.compiler.ast.Declarator;
  38. import javassist.compiler.ast.Expr;
  39. import javassist.compiler.ast.Keyword;
  40. import javassist.compiler.ast.Member;
  41. import javassist.compiler.ast.MethodDecl;
  42. import javassist.compiler.ast.NewExpr;
  43. import javassist.compiler.ast.Pair;
  44. import javassist.compiler.ast.Stmnt;
  45. import javassist.compiler.ast.Symbol;
  46. /* Code generator methods depending on javassist.* classes.
  47. */
  48. public class MemberCodeGen extends CodeGen {
  49. protected MemberResolver resolver;
  50. protected CtClass thisClass;
  51. protected MethodInfo thisMethod;
  52. protected boolean resultStatic;
  53. public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
  54. super(b);
  55. resolver = new MemberResolver(cp);
  56. thisClass = cc;
  57. thisMethod = null;
  58. }
  59. /**
  60. * Returns the major version of the class file
  61. * targeted by this compilation.
  62. */
  63. public int getMajorVersion() {
  64. ClassFile cf = thisClass.getClassFile2();
  65. if (cf == null)
  66. return ClassFile.MAJOR_VERSION; // JDK 1.3
  67. return cf.getMajorVersion();
  68. }
  69. /**
  70. * Records the currently compiled method.
  71. */
  72. public void setThisMethod(CtMethod m) {
  73. thisMethod = m.getMethodInfo2();
  74. if (typeChecker != null)
  75. typeChecker.setThisMethod(thisMethod);
  76. }
  77. public CtClass getThisClass() { return thisClass; }
  78. /**
  79. * Returns the JVM-internal representation of this class name.
  80. */
  81. @Override
  82. protected String getThisName() {
  83. return MemberResolver.javaToJvmName(thisClass.getName());
  84. }
  85. /**
  86. * Returns the JVM-internal representation of this super class name.
  87. */
  88. @Override
  89. protected String getSuperName() throws CompileError {
  90. return MemberResolver.javaToJvmName(
  91. MemberResolver.getSuperclass(thisClass).getName());
  92. }
  93. @Override
  94. protected void insertDefaultSuperCall() throws CompileError {
  95. bytecode.addAload(0);
  96. bytecode.addInvokespecial(MemberResolver.getSuperclass(thisClass),
  97. "<init>", "()V");
  98. }
  99. static class JsrHook extends ReturnHook {
  100. List<int[]> jsrList;
  101. CodeGen cgen;
  102. int var;
  103. JsrHook(CodeGen gen) {
  104. super(gen);
  105. jsrList = new ArrayList<int[]>();
  106. cgen = gen;
  107. var = -1;
  108. }
  109. private int getVar(int size) {
  110. if (var < 0) {
  111. var = cgen.getMaxLocals();
  112. cgen.incMaxLocals(size);
  113. }
  114. return var;
  115. }
  116. private void jsrJmp(Bytecode b) {
  117. b.addOpcode(Opcode.GOTO);
  118. jsrList.add(new int[] {b.currentPc(), var});
  119. b.addIndex(0);
  120. }
  121. @Override
  122. protected boolean doit(Bytecode b, int opcode) {
  123. switch (opcode) {
  124. case Opcode.RETURN :
  125. jsrJmp(b);
  126. break;
  127. case ARETURN :
  128. b.addAstore(getVar(1));
  129. jsrJmp(b);
  130. b.addAload(var);
  131. break;
  132. case IRETURN :
  133. b.addIstore(getVar(1));
  134. jsrJmp(b);
  135. b.addIload(var);
  136. break;
  137. case LRETURN :
  138. b.addLstore(getVar(2));
  139. jsrJmp(b);
  140. b.addLload(var);
  141. break;
  142. case DRETURN :
  143. b.addDstore(getVar(2));
  144. jsrJmp(b);
  145. b.addDload(var);
  146. break;
  147. case FRETURN :
  148. b.addFstore(getVar(1));
  149. jsrJmp(b);
  150. b.addFload(var);
  151. break;
  152. default :
  153. throw new RuntimeException("fatal");
  154. }
  155. return false;
  156. }
  157. }
  158. static class JsrHook2 extends ReturnHook {
  159. int var;
  160. int target;
  161. JsrHook2(CodeGen gen, int[] retTarget) {
  162. super(gen);
  163. target = retTarget[0];
  164. var = retTarget[1];
  165. }
  166. @Override
  167. protected boolean doit(Bytecode b, int opcode) {
  168. switch (opcode) {
  169. case Opcode.RETURN :
  170. break;
  171. case ARETURN :
  172. b.addAstore(var);
  173. break;
  174. case IRETURN :
  175. b.addIstore(var);
  176. break;
  177. case LRETURN :
  178. b.addLstore(var);
  179. break;
  180. case DRETURN :
  181. b.addDstore(var);
  182. break;
  183. case FRETURN :
  184. b.addFstore(var);
  185. break;
  186. default :
  187. throw new RuntimeException("fatal");
  188. }
  189. b.addOpcode(Opcode.GOTO);
  190. b.addIndex(target - b.currentPc() + 3);
  191. return true;
  192. }
  193. }
  194. @Override
  195. protected void atTryStmnt(Stmnt st) throws CompileError {
  196. Bytecode bc = bytecode;
  197. Stmnt body = (Stmnt)st.getLeft();
  198. if (body == null)
  199. return;
  200. ASTList catchList = (ASTList)st.getRight().getLeft();
  201. Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft();
  202. List<Integer> gotoList = new ArrayList<Integer>();
  203. JsrHook jsrHook = null;
  204. if (finallyBlock != null)
  205. jsrHook = new JsrHook(this);
  206. int start = bc.currentPc();
  207. body.accept(this);
  208. int end = bc.currentPc();
  209. if (start == end)
  210. throw new CompileError("empty try block");
  211. boolean tryNotReturn = !hasReturned;
  212. if (tryNotReturn) {
  213. bc.addOpcode(Opcode.GOTO);
  214. gotoList.add(bc.currentPc());
  215. bc.addIndex(0); // correct later
  216. }
  217. int var = getMaxLocals();
  218. incMaxLocals(1);
  219. while (catchList != null) {
  220. // catch clause
  221. Pair p = (Pair)catchList.head();
  222. catchList = catchList.tail();
  223. Declarator decl = (Declarator)p.getLeft();
  224. Stmnt block = (Stmnt)p.getRight();
  225. decl.setLocalVar(var);
  226. CtClass type = resolver.lookupClassByJvmName(decl.getClassName());
  227. decl.setClassName(MemberResolver.javaToJvmName(type.getName()));
  228. bc.addExceptionHandler(start, end, bc.currentPc(), type);
  229. bc.growStack(1);
  230. bc.addAstore(var);
  231. hasReturned = false;
  232. if (block != null)
  233. block.accept(this);
  234. if (!hasReturned) {
  235. bc.addOpcode(Opcode.GOTO);
  236. gotoList.add(bc.currentPc());
  237. bc.addIndex(0); // correct later
  238. tryNotReturn = true;
  239. }
  240. }
  241. if (finallyBlock != null) {
  242. jsrHook.remove(this);
  243. // catch (any) clause
  244. int pcAnyCatch = bc.currentPc();
  245. bc.addExceptionHandler(start, pcAnyCatch, pcAnyCatch, 0);
  246. bc.growStack(1);
  247. bc.addAstore(var);
  248. hasReturned = false;
  249. finallyBlock.accept(this);
  250. if (!hasReturned) {
  251. bc.addAload(var);
  252. bc.addOpcode(ATHROW);
  253. }
  254. addFinally(jsrHook.jsrList, finallyBlock);
  255. }
  256. int pcEnd = bc.currentPc();
  257. patchGoto(gotoList, pcEnd);
  258. hasReturned = !tryNotReturn;
  259. if (finallyBlock != null) {
  260. if (tryNotReturn)
  261. finallyBlock.accept(this);
  262. }
  263. }
  264. /**
  265. * Adds a finally clause for earch return statement.
  266. */
  267. private void addFinally(List<int[]> returnList, Stmnt finallyBlock)
  268. throws CompileError
  269. {
  270. Bytecode bc = bytecode;
  271. for (final int[] ret:returnList) {
  272. int pc = ret[0];
  273. bc.write16bit(pc, bc.currentPc() - pc + 1);
  274. ReturnHook hook = new JsrHook2(this, ret);
  275. finallyBlock.accept(this);
  276. hook.remove(this);
  277. if (!hasReturned) {
  278. bc.addOpcode(Opcode.GOTO);
  279. bc.addIndex(pc + 3 - bc.currentPc());
  280. }
  281. }
  282. }
  283. @Override
  284. public void atNewExpr(NewExpr expr) throws CompileError {
  285. if (expr.isArray())
  286. atNewArrayExpr(expr);
  287. else {
  288. CtClass clazz = resolver.lookupClassByName(expr.getClassName());
  289. String cname = clazz.getName();
  290. ASTList args = expr.getArguments();
  291. bytecode.addNew(cname);
  292. bytecode.addOpcode(DUP);
  293. atMethodCallCore(clazz, MethodInfo.nameInit, args,
  294. false, true, -1, null);
  295. exprType = CLASS;
  296. arrayDim = 0;
  297. className = MemberResolver.javaToJvmName(cname);
  298. }
  299. }
  300. public void atNewArrayExpr(NewExpr expr) throws CompileError {
  301. int type = expr.getArrayType();
  302. ASTList size = expr.getArraySize();
  303. ASTList classname = expr.getClassName();
  304. ArrayInit init = expr.getInitializer();
  305. if (size.length() > 1) {
  306. if (init != null)
  307. throw new CompileError(
  308. "sorry, multi-dimensional array initializer " +
  309. "for new is not supported");
  310. atMultiNewArray(type, classname, size);
  311. return;
  312. }
  313. ASTree sizeExpr = size.head();
  314. atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init);
  315. }
  316. private void atNewArrayExpr2(int type, ASTree sizeExpr,
  317. String jvmClassname, ArrayInit init) throws CompileError {
  318. if (init == null)
  319. if (sizeExpr == null)
  320. throw new CompileError("no array size");
  321. else
  322. sizeExpr.accept(this);
  323. else
  324. if (sizeExpr == null) {
  325. int s = init.size();
  326. bytecode.addIconst(s);
  327. }
  328. else
  329. throw new CompileError("unnecessary array size specified for new");
  330. String elementClass;
  331. if (type == CLASS) {
  332. elementClass = resolveClassName(jvmClassname);
  333. bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass));
  334. }
  335. else {
  336. elementClass = null;
  337. int atype = 0;
  338. switch (type) {
  339. case BOOLEAN :
  340. atype = T_BOOLEAN;
  341. break;
  342. case CHAR :
  343. atype = T_CHAR;
  344. break;
  345. case FLOAT :
  346. atype = T_FLOAT;
  347. break;
  348. case DOUBLE :
  349. atype = T_DOUBLE;
  350. break;
  351. case BYTE :
  352. atype = T_BYTE;
  353. break;
  354. case SHORT :
  355. atype = T_SHORT;
  356. break;
  357. case INT :
  358. atype = T_INT;
  359. break;
  360. case LONG :
  361. atype = T_LONG;
  362. break;
  363. default :
  364. badNewExpr();
  365. break;
  366. }
  367. bytecode.addOpcode(NEWARRAY);
  368. bytecode.add(atype);
  369. }
  370. if (init != null) {
  371. int s = init.size();
  372. ASTList list = init;
  373. for (int i = 0; i < s; i++) {
  374. bytecode.addOpcode(DUP);
  375. bytecode.addIconst(i);
  376. list.head().accept(this);
  377. if (!isRefType(type))
  378. atNumCastExpr(exprType, type);
  379. bytecode.addOpcode(getArrayWriteOp(type, 0));
  380. list = list.tail();
  381. }
  382. }
  383. exprType = type;
  384. arrayDim = 1;
  385. className = elementClass;
  386. }
  387. private static void badNewExpr() throws CompileError {
  388. throw new CompileError("bad new expression");
  389. }
  390. @Override
  391. protected void atArrayVariableAssign(ArrayInit init, int varType,
  392. int varArray, String varClass) throws CompileError {
  393. atNewArrayExpr2(varType, null, varClass, init);
  394. }
  395. @Override
  396. public void atArrayInit(ArrayInit init) throws CompileError {
  397. throw new CompileError("array initializer is not supported");
  398. }
  399. protected void atMultiNewArray(int type, ASTList classname, ASTList size)
  400. throws CompileError
  401. {
  402. int count, dim;
  403. dim = size.length();
  404. for (count = 0; size != null; size = size.tail()) {
  405. ASTree s = size.head();
  406. if (s == null)
  407. break; // int[][][] a = new int[3][4][];
  408. ++count;
  409. s.accept(this);
  410. if (exprType != INT)
  411. throw new CompileError("bad type for array size");
  412. }
  413. String desc;
  414. exprType = type;
  415. arrayDim = dim;
  416. if (type == CLASS) {
  417. className = resolveClassName(classname);
  418. desc = toJvmArrayName(className, dim);
  419. }
  420. else
  421. desc = toJvmTypeName(type, dim);
  422. bytecode.addMultiNewarray(desc, count);
  423. }
  424. @Override
  425. public void atCallExpr(CallExpr expr) throws CompileError {
  426. String mname = null;
  427. CtClass targetClass = null;
  428. ASTree method = expr.oprand1();
  429. ASTList args = (ASTList)expr.oprand2();
  430. boolean isStatic = false;
  431. boolean isSpecial = false;
  432. int aload0pos = -1;
  433. MemberResolver.Method cached = expr.getMethod();
  434. if (method instanceof Member) {
  435. mname = ((Member)method).get();
  436. targetClass = thisClass;
  437. if (inStaticMethod || (cached != null && cached.isStatic()))
  438. isStatic = true; // should be static
  439. else {
  440. aload0pos = bytecode.currentPc();
  441. bytecode.addAload(0); // this
  442. }
  443. }
  444. else if (method instanceof Keyword) { // constructor
  445. isSpecial = true;
  446. mname = MethodInfo.nameInit; // <init>
  447. targetClass = thisClass;
  448. if (inStaticMethod)
  449. throw new CompileError("a constructor cannot be static");
  450. bytecode.addAload(0); // this
  451. if (((Keyword)method).get() == SUPER)
  452. targetClass = MemberResolver.getSuperclass(targetClass);
  453. }
  454. else if (method instanceof Expr) {
  455. Expr e = (Expr)method;
  456. mname = ((Symbol)e.oprand2()).get();
  457. int op = e.getOperator();
  458. if (op == MEMBER) { // static method
  459. targetClass
  460. = resolver.lookupClass(((Symbol)e.oprand1()).get(), false);
  461. isStatic = true;
  462. }
  463. else if (op == '.') {
  464. ASTree target = e.oprand1();
  465. String classFollowedByDotSuper = TypeChecker.isDotSuper(target);
  466. if (classFollowedByDotSuper != null) {
  467. isSpecial = true;
  468. targetClass = MemberResolver.getSuperInterface(thisClass,
  469. classFollowedByDotSuper);
  470. if (inStaticMethod || (cached != null && cached.isStatic()))
  471. isStatic = true; // should be static
  472. else {
  473. aload0pos = bytecode.currentPc();
  474. bytecode.addAload(0); // this
  475. }
  476. }
  477. else {
  478. if (target instanceof Keyword)
  479. if (((Keyword)target).get() == SUPER)
  480. isSpecial = true;
  481. try {
  482. target.accept(this);
  483. }
  484. catch (NoFieldException nfe) {
  485. if (nfe.getExpr() != target)
  486. throw nfe;
  487. // it should be a static method.
  488. exprType = CLASS;
  489. arrayDim = 0;
  490. className = nfe.getField(); // JVM-internal
  491. isStatic = true;
  492. }
  493. if (arrayDim > 0)
  494. targetClass = resolver.lookupClass(javaLangObject, true);
  495. else if (exprType == CLASS /* && arrayDim == 0 */)
  496. targetClass = resolver.lookupClassByJvmName(className);
  497. else
  498. badMethod();
  499. }
  500. }
  501. else
  502. badMethod();
  503. }
  504. else
  505. fatal();
  506. atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
  507. aload0pos, cached);
  508. }
  509. private static void badMethod() throws CompileError {
  510. throw new CompileError("bad method");
  511. }
  512. /*
  513. * atMethodCallCore() is also called by doit() in NewExpr.ProceedForNew
  514. *
  515. * @param targetClass the class at which method lookup starts.
  516. * @param found not null if the method look has been already done.
  517. */
  518. public void atMethodCallCore(CtClass targetClass, String mname,
  519. ASTList args, boolean isStatic, boolean isSpecial,
  520. int aload0pos, MemberResolver.Method found)
  521. throws CompileError
  522. {
  523. int nargs = getMethodArgsLength(args);
  524. int[] types = new int[nargs];
  525. int[] dims = new int[nargs];
  526. String[] cnames = new String[nargs];
  527. if (!isStatic && found != null && found.isStatic()) {
  528. bytecode.addOpcode(POP);
  529. isStatic = true;
  530. }
  531. @SuppressWarnings("unused")
  532. int stack = bytecode.getStackDepth();
  533. // generate code for evaluating arguments.
  534. atMethodArgs(args, types, dims, cnames);
  535. if (found == null)
  536. found = resolver.lookupMethod(targetClass, thisClass, thisMethod,
  537. mname, types, dims, cnames);
  538. if (found == null) {
  539. String msg;
  540. if (mname.equals(MethodInfo.nameInit))
  541. msg = "constructor not found";
  542. else
  543. msg = "Method " + mname + " not found in "
  544. + targetClass.getName();
  545. throw new CompileError(msg);
  546. }
  547. atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
  548. aload0pos, found);
  549. }
  550. private boolean isFromSameDeclaringClass(CtClass outer, CtClass inner) {
  551. try {
  552. while (outer != null) {
  553. if (isEnclosing(outer, inner))
  554. return true;
  555. outer = outer.getDeclaringClass();
  556. }
  557. }
  558. catch (NotFoundException e) {}
  559. return false;
  560. }
  561. private void atMethodCallCore2(CtClass targetClass, String mname,
  562. boolean isStatic, boolean isSpecial,
  563. int aload0pos,
  564. MemberResolver.Method found)
  565. throws CompileError
  566. {
  567. CtClass declClass = found.declaring;
  568. MethodInfo minfo = found.info;
  569. String desc = minfo.getDescriptor();
  570. int acc = minfo.getAccessFlags();
  571. if (mname.equals(MethodInfo.nameInit)) {
  572. isSpecial = true;
  573. if (declClass != targetClass)
  574. throw new CompileError("no such constructor: " + targetClass.getName());
  575. if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
  576. if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_8
  577. || !isFromSameDeclaringClass(declClass, thisClass)) {
  578. desc = getAccessibleConstructor(desc, declClass, minfo);
  579. bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter
  580. }
  581. }
  582. }
  583. else if (AccessFlag.isPrivate(acc))
  584. if (declClass == thisClass)
  585. isSpecial = true;
  586. else {
  587. isSpecial = false;
  588. isStatic = true;
  589. String origDesc = desc;
  590. if ((acc & AccessFlag.STATIC) == 0)
  591. desc = Descriptor.insertParameter(declClass.getName(),
  592. origDesc);
  593. acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
  594. if (!isFromSameDeclaringClass(declClass, thisClass))
  595. mname = getAccessiblePrivate(mname, origDesc, desc,
  596. minfo, declClass);
  597. }
  598. boolean popTarget = false;
  599. if ((acc & AccessFlag.STATIC) != 0) {
  600. if (!isStatic) {
  601. /* this method is static but the target object is
  602. on stack. It must be popped out. If aload0pos >= 0,
  603. then the target object was pushed by aload_0. It is
  604. overwritten by NOP.
  605. */
  606. isStatic = true;
  607. if (aload0pos >= 0)
  608. bytecode.write(aload0pos, NOP);
  609. else
  610. popTarget = true;
  611. }
  612. bytecode.addInvokestatic(declClass, mname, desc);
  613. }
  614. else if (isSpecial) // if (isSpecial && notStatic(acc))
  615. bytecode.addInvokespecial(targetClass, mname, desc);
  616. else {
  617. if (!Modifier.isPublic(declClass.getModifiers())
  618. || declClass.isInterface() != targetClass.isInterface())
  619. declClass = targetClass;
  620. if (declClass.isInterface()) {
  621. int nargs = Descriptor.paramSize(desc) + 1;
  622. bytecode.addInvokeinterface(declClass, mname, desc, nargs);
  623. }
  624. else
  625. if (isStatic)
  626. throw new CompileError(mname + " is not static");
  627. else
  628. bytecode.addInvokevirtual(declClass, mname, desc);
  629. }
  630. setReturnType(desc, isStatic, popTarget);
  631. }
  632. /*
  633. * Finds (or adds if necessary) a hidden accessor if the method
  634. * is in an enclosing class.
  635. *
  636. * @param desc the descriptor of the method.
  637. * @param declClass the class declaring the method.
  638. */
  639. protected String getAccessiblePrivate(String methodName, String desc,
  640. String newDesc, MethodInfo minfo,
  641. CtClass declClass)
  642. throws CompileError
  643. {
  644. if (isEnclosing(declClass, thisClass)) {
  645. AccessorMaker maker = declClass.getAccessorMaker();
  646. if (maker != null)
  647. return maker.getMethodAccessor(methodName, desc, newDesc,
  648. minfo);
  649. }
  650. throw new CompileError("Method " + methodName
  651. + " is private");
  652. }
  653. /*
  654. * Finds (or adds if necessary) a hidden constructor if the given
  655. * constructor is in an enclosing class.
  656. *
  657. * @param desc the descriptor of the constructor.
  658. * @param declClass the class declaring the constructor.
  659. * @param minfo the method info of the constructor.
  660. * @return the descriptor of the hidden constructor.
  661. */
  662. protected String getAccessibleConstructor(String desc, CtClass declClass,
  663. MethodInfo minfo)
  664. throws CompileError
  665. {
  666. if (isEnclosing(declClass, thisClass)) {
  667. AccessorMaker maker = declClass.getAccessorMaker();
  668. if (maker != null)
  669. return maker.getConstructor(declClass, desc, minfo);
  670. }
  671. throw new CompileError("the called constructor is private in "
  672. + declClass.getName());
  673. }
  674. private boolean isEnclosing(CtClass outer, CtClass inner) {
  675. try {
  676. while (inner != null) {
  677. inner = inner.getDeclaringClass();
  678. if (inner == outer)
  679. return true;
  680. }
  681. }
  682. catch (NotFoundException e) {}
  683. return false;
  684. }
  685. public int getMethodArgsLength(ASTList args) {
  686. return ASTList.length(args);
  687. }
  688. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  689. String[] cnames) throws CompileError {
  690. int i = 0;
  691. while (args != null) {
  692. ASTree a = args.head();
  693. a.accept(this);
  694. types[i] = exprType;
  695. dims[i] = arrayDim;
  696. cnames[i] = className;
  697. ++i;
  698. args = args.tail();
  699. }
  700. }
  701. void setReturnType(String desc, boolean isStatic, boolean popTarget)
  702. throws CompileError
  703. {
  704. int i = desc.indexOf(')');
  705. if (i < 0)
  706. badMethod();
  707. char c = desc.charAt(++i);
  708. int dim = 0;
  709. while (c == '[') {
  710. ++dim;
  711. c = desc.charAt(++i);
  712. }
  713. arrayDim = dim;
  714. if (c == 'L') {
  715. int j = desc.indexOf(';', i + 1);
  716. if (j < 0)
  717. badMethod();
  718. exprType = CLASS;
  719. className = desc.substring(i + 1, j);
  720. }
  721. else {
  722. exprType = MemberResolver.descToType(c);
  723. className = null;
  724. }
  725. int etype = exprType;
  726. if (isStatic) {
  727. if (popTarget) {
  728. if (is2word(etype, dim)) {
  729. bytecode.addOpcode(DUP2_X1);
  730. bytecode.addOpcode(POP2);
  731. bytecode.addOpcode(POP);
  732. }
  733. else if (etype == VOID)
  734. bytecode.addOpcode(POP);
  735. else {
  736. bytecode.addOpcode(SWAP);
  737. bytecode.addOpcode(POP);
  738. }
  739. }
  740. }
  741. }
  742. @Override
  743. protected void atFieldAssign(Expr expr, int op, ASTree left,
  744. ASTree right, boolean doDup) throws CompileError
  745. {
  746. CtField f = fieldAccess(left, false);
  747. boolean is_static = resultStatic;
  748. if (op != '=' && !is_static)
  749. bytecode.addOpcode(DUP);
  750. int fi;
  751. if (op == '=') {
  752. FieldInfo finfo = f.getFieldInfo2();
  753. setFieldType(finfo);
  754. AccessorMaker maker = isAccessibleField(f, finfo);
  755. if (maker == null)
  756. fi = addFieldrefInfo(f, finfo);
  757. else
  758. fi = 0;
  759. }
  760. else
  761. fi = atFieldRead(f, is_static);
  762. int fType = exprType;
  763. int fDim = arrayDim;
  764. String cname = className;
  765. atAssignCore(expr, op, right, fType, fDim, cname);
  766. boolean is2w = is2word(fType, fDim);
  767. if (doDup) {
  768. int dup_code;
  769. if (is_static)
  770. dup_code = (is2w ? DUP2 : DUP);
  771. else
  772. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  773. bytecode.addOpcode(dup_code);
  774. }
  775. atFieldAssignCore(f, is_static, fi, is2w);
  776. exprType = fType;
  777. arrayDim = fDim;
  778. className = cname;
  779. }
  780. /* If fi == 0, the field must be a private field in an enclosing class.
  781. */
  782. private void atFieldAssignCore(CtField f, boolean is_static, int fi,
  783. boolean is2byte) throws CompileError {
  784. if (fi != 0) {
  785. if (is_static) {
  786. bytecode.add(PUTSTATIC);
  787. bytecode.growStack(is2byte ? -2 : -1);
  788. }
  789. else {
  790. bytecode.add(PUTFIELD);
  791. bytecode.growStack(is2byte ? -3 : -2);
  792. }
  793. bytecode.addIndex(fi);
  794. }
  795. else {
  796. CtClass declClass = f.getDeclaringClass();
  797. AccessorMaker maker = declClass.getAccessorMaker();
  798. // make should be non null.
  799. FieldInfo finfo = f.getFieldInfo2();
  800. MethodInfo minfo = maker.getFieldSetter(finfo, is_static);
  801. bytecode.addInvokestatic(declClass, minfo.getName(),
  802. minfo.getDescriptor());
  803. }
  804. }
  805. /* overwritten in JvstCodeGen.
  806. */
  807. @Override
  808. public void atMember(Member mem) throws CompileError {
  809. atFieldRead(mem);
  810. }
  811. @Override
  812. protected void atFieldRead(ASTree expr) throws CompileError
  813. {
  814. CtField f = fieldAccess(expr, true);
  815. if (f == null) {
  816. atArrayLength(expr);
  817. return;
  818. }
  819. boolean is_static = resultStatic;
  820. ASTree cexpr = TypeChecker.getConstantFieldValue(f);
  821. if (cexpr == null)
  822. atFieldRead(f, is_static);
  823. else {
  824. cexpr.accept(this);
  825. setFieldType(f.getFieldInfo2());
  826. }
  827. }
  828. private void atArrayLength(ASTree expr) throws CompileError {
  829. if (arrayDim == 0)
  830. throw new CompileError(".length applied to a non array");
  831. bytecode.addOpcode(ARRAYLENGTH);
  832. exprType = INT;
  833. arrayDim = 0;
  834. }
  835. /**
  836. * Generates bytecode for reading a field value.
  837. * It returns a fieldref_info index or zero if the field is a private
  838. * one declared in an enclosing class.
  839. */
  840. private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
  841. FieldInfo finfo = f.getFieldInfo2();
  842. boolean is2byte = setFieldType(finfo);
  843. AccessorMaker maker = isAccessibleField(f, finfo);
  844. if (maker != null) {
  845. MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
  846. bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
  847. minfo.getDescriptor());
  848. return 0;
  849. }
  850. int fi = addFieldrefInfo(f, finfo);
  851. if (isStatic) {
  852. bytecode.add(GETSTATIC);
  853. bytecode.growStack(is2byte ? 2 : 1);
  854. }
  855. else {
  856. bytecode.add(GETFIELD);
  857. bytecode.growStack(is2byte ? 1 : 0);
  858. }
  859. bytecode.addIndex(fi);
  860. return fi;
  861. }
  862. /**
  863. * Returns null if the field is accessible. Otherwise, it throws
  864. * an exception or it returns AccessorMaker if the field is a private
  865. * one declared in an enclosing class.
  866. */
  867. private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
  868. throws CompileError
  869. {
  870. if (AccessFlag.isPrivate(finfo.getAccessFlags())
  871. && f.getDeclaringClass() != thisClass) {
  872. CtClass declClass = f.getDeclaringClass();
  873. if (isEnclosing(declClass, thisClass)) {
  874. AccessorMaker maker = declClass.getAccessorMaker();
  875. if (maker != null)
  876. return maker;
  877. }
  878. throw new CompileError("Field " + f.getName() + " in "
  879. + declClass.getName() + " is private.");
  880. }
  881. return null; // accessible field
  882. }
  883. /**
  884. * Sets exprType, arrayDim, and className.
  885. *
  886. * @return true if the field type is long or double.
  887. */
  888. private boolean setFieldType(FieldInfo finfo) throws CompileError {
  889. String type = finfo.getDescriptor();
  890. int i = 0;
  891. int dim = 0;
  892. char c = type.charAt(i);
  893. while (c == '[') {
  894. ++dim;
  895. c = type.charAt(++i);
  896. }
  897. arrayDim = dim;
  898. exprType = MemberResolver.descToType(c);
  899. if (c == 'L')
  900. className = type.substring(i + 1, type.indexOf(';', i + 1));
  901. else
  902. className = null;
  903. boolean is2byte = dim == 0 && (c == 'J' || c == 'D');
  904. return is2byte;
  905. }
  906. private int addFieldrefInfo(CtField f, FieldInfo finfo) {
  907. ConstPool cp = bytecode.getConstPool();
  908. String cname = f.getDeclaringClass().getName();
  909. int ci = cp.addClassInfo(cname);
  910. String name = finfo.getName();
  911. String type = finfo.getDescriptor();
  912. return cp.addFieldrefInfo(ci, name, type);
  913. }
  914. @Override
  915. protected void atClassObject2(String cname) throws CompileError {
  916. if (getMajorVersion() < ClassFile.JAVA_5)
  917. super.atClassObject2(cname);
  918. else
  919. bytecode.addLdc(bytecode.getConstPool().addClassInfo(cname));
  920. }
  921. @Override
  922. protected void atFieldPlusPlus(int token, boolean isPost,
  923. ASTree oprand, Expr expr, boolean doDup)
  924. throws CompileError
  925. {
  926. CtField f = fieldAccess(oprand, false);
  927. boolean is_static = resultStatic;
  928. if (!is_static)
  929. bytecode.addOpcode(DUP);
  930. int fi = atFieldRead(f, is_static);
  931. int t = exprType;
  932. boolean is2w = is2word(t, arrayDim);
  933. int dup_code;
  934. if (is_static)
  935. dup_code = (is2w ? DUP2 : DUP);
  936. else
  937. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  938. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  939. atFieldAssignCore(f, is_static, fi, is2w);
  940. }
  941. /* This method also returns a value in resultStatic.
  942. *
  943. * @param acceptLength true if array length is acceptable
  944. */
  945. protected CtField fieldAccess(ASTree expr, boolean acceptLength)
  946. throws CompileError
  947. {
  948. if (expr instanceof Member) {
  949. String name = ((Member)expr).get();
  950. CtField f = null;
  951. try {
  952. f = thisClass.getField(name);
  953. }
  954. catch (NotFoundException e) {
  955. // EXPR might be part of a static member access?
  956. throw new NoFieldException(name, expr);
  957. }
  958. boolean is_static = Modifier.isStatic(f.getModifiers());
  959. if (!is_static)
  960. if (inStaticMethod)
  961. throw new CompileError(
  962. "not available in a static method: " + name);
  963. else
  964. bytecode.addAload(0); // this
  965. resultStatic = is_static;
  966. return f;
  967. }
  968. else if (expr instanceof Expr) {
  969. Expr e = (Expr)expr;
  970. int op = e.getOperator();
  971. if (op == MEMBER) {
  972. /* static member by # (extension by Javassist)
  973. * For example, if int.class is parsed, the resulting tree
  974. * is (# "java.lang.Integer" "TYPE").
  975. */
  976. CtField f = resolver.lookupField(((Symbol)e.oprand1()).get(),
  977. (Symbol)e.oprand2());
  978. resultStatic = true;
  979. return f;
  980. }
  981. else if (op == '.') {
  982. CtField f = null;
  983. try {
  984. e.oprand1().accept(this);
  985. /* Don't call lookupFieldByJvmName2().
  986. * The left operand of . is not a class name but
  987. * a normal expression.
  988. */
  989. if (exprType == CLASS && arrayDim == 0)
  990. f = resolver.lookupFieldByJvmName(className,
  991. (Symbol)e.oprand2());
  992. else if (acceptLength && arrayDim > 0
  993. && ((Symbol)e.oprand2()).get().equals("length"))
  994. return null; // expr is an array length.
  995. else
  996. badLvalue();
  997. boolean is_static = Modifier.isStatic(f.getModifiers());
  998. if (is_static)
  999. bytecode.addOpcode(POP);
  1000. resultStatic = is_static;
  1001. return f;
  1002. }
  1003. catch (NoFieldException nfe) {
  1004. if (nfe.getExpr() != e.oprand1())
  1005. throw nfe;
  1006. /* EXPR should be a static field.
  1007. * If EXPR might be part of a qualified class name,
  1008. * lookupFieldByJvmName2() throws NoFieldException.
  1009. */
  1010. Symbol fname = (Symbol)e.oprand2();
  1011. String cname = nfe.getField();
  1012. f = resolver.lookupFieldByJvmName2(cname, fname, expr);
  1013. resultStatic = true;
  1014. return f;
  1015. }
  1016. }
  1017. else
  1018. badLvalue();
  1019. }
  1020. else
  1021. badLvalue();
  1022. resultStatic = false;
  1023. return null; // never reach
  1024. }
  1025. private static void badLvalue() throws CompileError {
  1026. throw new CompileError("bad l-value");
  1027. }
  1028. public CtClass[] makeParamList(MethodDecl md) throws CompileError {
  1029. CtClass[] params;
  1030. ASTList plist = md.getParams();
  1031. if (plist == null)
  1032. params = new CtClass[0];
  1033. else {
  1034. int i = 0;
  1035. params = new CtClass[plist.length()];
  1036. while (plist != null) {
  1037. params[i++] = resolver.lookupClass((Declarator)plist.head());
  1038. plist = plist.tail();
  1039. }
  1040. }
  1041. return params;
  1042. }
  1043. public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
  1044. CtClass[] clist;
  1045. ASTList list = md.getThrows();
  1046. if (list == null)
  1047. return null;
  1048. int i = 0;
  1049. clist = new CtClass[list.length()];
  1050. while (list != null) {
  1051. clist[i++] = resolver.lookupClassByName((ASTList)list.head());
  1052. list = list.tail();
  1053. }
  1054. return clist;
  1055. }
  1056. /* Converts a class name into a JVM-internal representation.
  1057. *
  1058. * It may also expand a simple class name to java.lang.*.
  1059. * For example, this converts Object into java/lang/Object.
  1060. */
  1061. @Override
  1062. protected String resolveClassName(ASTList name) throws CompileError {
  1063. return resolver.resolveClassName(name);
  1064. }
  1065. /* Expands a simple class name to java.lang.*.
  1066. * For example, this converts Object into java/lang/Object.
  1067. */
  1068. @Override
  1069. protected String resolveClassName(String jvmName) throws CompileError {
  1070. return resolver.resolveJvmClassName(jvmName);
  1071. }
  1072. }