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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  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. // used by invokeinterface
  504. int count = bytecode.getStackDepth() - stack + 1;
  505. if (found == null)
  506. found = resolver.lookupMethod(targetClass, thisClass, thisMethod,
  507. mname, types, dims, cnames);
  508. if (found == null) {
  509. String msg;
  510. if (mname.equals(MethodInfo.nameInit))
  511. msg = "constructor not found";
  512. else
  513. msg = "Method " + mname + " not found in "
  514. + targetClass.getName();
  515. throw new CompileError(msg);
  516. }
  517. atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
  518. aload0pos, count, found);
  519. }
  520. private void atMethodCallCore2(CtClass targetClass, String mname,
  521. boolean isStatic, boolean isSpecial,
  522. int aload0pos, int count,
  523. MemberResolver.Method found)
  524. throws CompileError
  525. {
  526. CtClass declClass = found.declaring;
  527. MethodInfo minfo = found.info;
  528. String desc = minfo.getDescriptor();
  529. int acc = minfo.getAccessFlags();
  530. if (mname.equals(MethodInfo.nameInit)) {
  531. isSpecial = true;
  532. if (declClass != targetClass)
  533. throw new CompileError("no such constructor: " + targetClass.getName());
  534. if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
  535. desc = getAccessibleConstructor(desc, declClass, minfo);
  536. bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter
  537. }
  538. }
  539. else if (AccessFlag.isPrivate(acc))
  540. if (declClass == thisClass)
  541. isSpecial = true;
  542. else {
  543. isSpecial = false;
  544. isStatic = true;
  545. String origDesc = desc;
  546. if ((acc & AccessFlag.STATIC) == 0)
  547. desc = Descriptor.insertParameter(declClass.getName(),
  548. origDesc);
  549. acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
  550. mname = getAccessiblePrivate(mname, origDesc, desc,
  551. minfo, declClass);
  552. }
  553. boolean popTarget = false;
  554. if ((acc & AccessFlag.STATIC) != 0) {
  555. if (!isStatic) {
  556. /* this method is static but the target object is
  557. on stack. It must be popped out. If aload0pos >= 0,
  558. then the target object was pushed by aload_0. It is
  559. overwritten by NOP.
  560. */
  561. isStatic = true;
  562. if (aload0pos >= 0)
  563. bytecode.write(aload0pos, NOP);
  564. else
  565. popTarget = true;
  566. }
  567. bytecode.addInvokestatic(declClass, mname, desc);
  568. }
  569. else if (isSpecial) // if (isSpecial && notStatic(acc))
  570. bytecode.addInvokespecial(declClass, mname, desc);
  571. else {
  572. if (!Modifier.isPublic(declClass.getModifiers())
  573. || declClass.isInterface() != targetClass.isInterface())
  574. declClass = targetClass;
  575. if (declClass.isInterface())
  576. bytecode.addInvokeinterface(declClass, mname, desc, count);
  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. }