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

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