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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  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.length();
  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.length();
  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 void atMethodCallCore2(CtClass targetClass, String mname,
  551. boolean isStatic, boolean isSpecial,
  552. int aload0pos,
  553. MemberResolver.Method found)
  554. throws CompileError
  555. {
  556. CtClass declClass = found.declaring;
  557. MethodInfo minfo = found.info;
  558. String desc = minfo.getDescriptor();
  559. int acc = minfo.getAccessFlags();
  560. if (mname.equals(MethodInfo.nameInit)) {
  561. isSpecial = true;
  562. if (declClass != targetClass)
  563. throw new CompileError("no such constructor: " + targetClass.getName());
  564. if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
  565. boolean isNested = false;
  566. if (declClass.getClassFile().getMajorVersion() >= ClassFile.JAVA_11) {
  567. try {
  568. CtClass[] nestedClasses = declClass.getNestedClasses();
  569. for (int i = 0; i < nestedClasses.length; i++) {
  570. if (thisClass == nestedClasses[i]) {
  571. isNested = true;
  572. break;
  573. }
  574. }
  575. } catch (NotFoundException ignored) { }
  576. }
  577. if (!isNested) {
  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. mname = getAccessiblePrivate(mname, origDesc, desc,
  595. minfo, declClass);
  596. }
  597. boolean popTarget = false;
  598. if ((acc & AccessFlag.STATIC) != 0) {
  599. if (!isStatic) {
  600. /* this method is static but the target object is
  601. on stack. It must be popped out. If aload0pos >= 0,
  602. then the target object was pushed by aload_0. It is
  603. overwritten by NOP.
  604. */
  605. isStatic = true;
  606. if (aload0pos >= 0)
  607. bytecode.write(aload0pos, NOP);
  608. else
  609. popTarget = true;
  610. }
  611. bytecode.addInvokestatic(declClass, mname, desc);
  612. }
  613. else if (isSpecial) // if (isSpecial && notStatic(acc))
  614. bytecode.addInvokespecial(targetClass, mname, desc);
  615. else {
  616. if (!Modifier.isPublic(declClass.getModifiers())
  617. || declClass.isInterface() != targetClass.isInterface())
  618. declClass = targetClass;
  619. if (declClass.isInterface()) {
  620. int nargs = Descriptor.paramSize(desc) + 1;
  621. bytecode.addInvokeinterface(declClass, mname, desc, nargs);
  622. }
  623. else
  624. if (isStatic)
  625. throw new CompileError(mname + " is not static");
  626. else
  627. bytecode.addInvokevirtual(declClass, mname, desc);
  628. }
  629. setReturnType(desc, isStatic, popTarget);
  630. }
  631. /*
  632. * Finds (or adds if necessary) a hidden accessor if the method
  633. * is in an enclosing class.
  634. *
  635. * @param desc the descriptor of the method.
  636. * @param declClass the class declaring the method.
  637. */
  638. protected String getAccessiblePrivate(String methodName, String desc,
  639. String newDesc, MethodInfo minfo,
  640. CtClass declClass)
  641. throws CompileError
  642. {
  643. if (isEnclosing(declClass, thisClass)) {
  644. AccessorMaker maker = declClass.getAccessorMaker();
  645. if (maker != null)
  646. return maker.getMethodAccessor(methodName, desc, newDesc,
  647. minfo);
  648. }
  649. throw new CompileError("Method " + methodName
  650. + " is private");
  651. }
  652. /*
  653. * Finds (or adds if necessary) a hidden constructor if the given
  654. * constructor is in an enclosing class.
  655. *
  656. * @param desc the descriptor of the constructor.
  657. * @param declClass the class declaring the constructor.
  658. * @param minfo the method info of the constructor.
  659. * @return the descriptor of the hidden constructor.
  660. */
  661. protected String getAccessibleConstructor(String desc, CtClass declClass,
  662. MethodInfo minfo)
  663. throws CompileError
  664. {
  665. if (isEnclosing(declClass, thisClass)) {
  666. AccessorMaker maker = declClass.getAccessorMaker();
  667. if (maker != null)
  668. return maker.getConstructor(declClass, desc, minfo);
  669. }
  670. throw new CompileError("the called constructor is private in "
  671. + declClass.getName());
  672. }
  673. private boolean isEnclosing(CtClass outer, CtClass inner) {
  674. try {
  675. while (inner != null) {
  676. inner = inner.getDeclaringClass();
  677. if (inner == outer)
  678. return true;
  679. }
  680. }
  681. catch (NotFoundException e) {}
  682. return false;
  683. }
  684. public int getMethodArgsLength(ASTList args) {
  685. return ASTList.length(args);
  686. }
  687. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  688. String[] cnames) throws CompileError {
  689. int i = 0;
  690. while (args != null) {
  691. ASTree a = args.head();
  692. a.accept(this);
  693. types[i] = exprType;
  694. dims[i] = arrayDim;
  695. cnames[i] = className;
  696. ++i;
  697. args = args.tail();
  698. }
  699. }
  700. void setReturnType(String desc, boolean isStatic, boolean popTarget)
  701. throws CompileError
  702. {
  703. int i = desc.indexOf(')');
  704. if (i < 0)
  705. badMethod();
  706. char c = desc.charAt(++i);
  707. int dim = 0;
  708. while (c == '[') {
  709. ++dim;
  710. c = desc.charAt(++i);
  711. }
  712. arrayDim = dim;
  713. if (c == 'L') {
  714. int j = desc.indexOf(';', i + 1);
  715. if (j < 0)
  716. badMethod();
  717. exprType = CLASS;
  718. className = desc.substring(i + 1, j);
  719. }
  720. else {
  721. exprType = MemberResolver.descToType(c);
  722. className = null;
  723. }
  724. int etype = exprType;
  725. if (isStatic) {
  726. if (popTarget) {
  727. if (is2word(etype, dim)) {
  728. bytecode.addOpcode(DUP2_X1);
  729. bytecode.addOpcode(POP2);
  730. bytecode.addOpcode(POP);
  731. }
  732. else if (etype == VOID)
  733. bytecode.addOpcode(POP);
  734. else {
  735. bytecode.addOpcode(SWAP);
  736. bytecode.addOpcode(POP);
  737. }
  738. }
  739. }
  740. }
  741. @Override
  742. protected void atFieldAssign(Expr expr, int op, ASTree left,
  743. ASTree right, boolean doDup) throws CompileError
  744. {
  745. CtField f = fieldAccess(left, false);
  746. boolean is_static = resultStatic;
  747. if (op != '=' && !is_static)
  748. bytecode.addOpcode(DUP);
  749. int fi;
  750. if (op == '=') {
  751. FieldInfo finfo = f.getFieldInfo2();
  752. setFieldType(finfo);
  753. AccessorMaker maker = isAccessibleField(f, finfo);
  754. if (maker == null)
  755. fi = addFieldrefInfo(f, finfo);
  756. else
  757. fi = 0;
  758. }
  759. else
  760. fi = atFieldRead(f, is_static);
  761. int fType = exprType;
  762. int fDim = arrayDim;
  763. String cname = className;
  764. atAssignCore(expr, op, right, fType, fDim, cname);
  765. boolean is2w = is2word(fType, fDim);
  766. if (doDup) {
  767. int dup_code;
  768. if (is_static)
  769. dup_code = (is2w ? DUP2 : DUP);
  770. else
  771. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  772. bytecode.addOpcode(dup_code);
  773. }
  774. atFieldAssignCore(f, is_static, fi, is2w);
  775. exprType = fType;
  776. arrayDim = fDim;
  777. className = cname;
  778. }
  779. /* If fi == 0, the field must be a private field in an enclosing class.
  780. */
  781. private void atFieldAssignCore(CtField f, boolean is_static, int fi,
  782. boolean is2byte) throws CompileError {
  783. if (fi != 0) {
  784. if (is_static) {
  785. bytecode.add(PUTSTATIC);
  786. bytecode.growStack(is2byte ? -2 : -1);
  787. }
  788. else {
  789. bytecode.add(PUTFIELD);
  790. bytecode.growStack(is2byte ? -3 : -2);
  791. }
  792. bytecode.addIndex(fi);
  793. }
  794. else {
  795. CtClass declClass = f.getDeclaringClass();
  796. AccessorMaker maker = declClass.getAccessorMaker();
  797. // make should be non null.
  798. FieldInfo finfo = f.getFieldInfo2();
  799. MethodInfo minfo = maker.getFieldSetter(finfo, is_static);
  800. bytecode.addInvokestatic(declClass, minfo.getName(),
  801. minfo.getDescriptor());
  802. }
  803. }
  804. /* overwritten in JvstCodeGen.
  805. */
  806. @Override
  807. public void atMember(Member mem) throws CompileError {
  808. atFieldRead(mem);
  809. }
  810. @Override
  811. protected void atFieldRead(ASTree expr) throws CompileError
  812. {
  813. CtField f = fieldAccess(expr, true);
  814. if (f == null) {
  815. atArrayLength(expr);
  816. return;
  817. }
  818. boolean is_static = resultStatic;
  819. ASTree cexpr = TypeChecker.getConstantFieldValue(f);
  820. if (cexpr == null)
  821. atFieldRead(f, is_static);
  822. else {
  823. cexpr.accept(this);
  824. setFieldType(f.getFieldInfo2());
  825. }
  826. }
  827. private void atArrayLength(ASTree expr) throws CompileError {
  828. if (arrayDim == 0)
  829. throw new CompileError(".length applied to a non array");
  830. bytecode.addOpcode(ARRAYLENGTH);
  831. exprType = INT;
  832. arrayDim = 0;
  833. }
  834. /**
  835. * Generates bytecode for reading a field value.
  836. * It returns a fieldref_info index or zero if the field is a private
  837. * one declared in an enclosing class.
  838. */
  839. private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
  840. FieldInfo finfo = f.getFieldInfo2();
  841. boolean is2byte = setFieldType(finfo);
  842. AccessorMaker maker = isAccessibleField(f, finfo);
  843. if (maker != null) {
  844. MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
  845. bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
  846. minfo.getDescriptor());
  847. return 0;
  848. }
  849. int fi = addFieldrefInfo(f, finfo);
  850. if (isStatic) {
  851. bytecode.add(GETSTATIC);
  852. bytecode.growStack(is2byte ? 2 : 1);
  853. }
  854. else {
  855. bytecode.add(GETFIELD);
  856. bytecode.growStack(is2byte ? 1 : 0);
  857. }
  858. bytecode.addIndex(fi);
  859. return fi;
  860. }
  861. /**
  862. * Returns null if the field is accessible. Otherwise, it throws
  863. * an exception or it returns AccessorMaker if the field is a private
  864. * one declared in an enclosing class.
  865. */
  866. private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
  867. throws CompileError
  868. {
  869. if (AccessFlag.isPrivate(finfo.getAccessFlags())
  870. && f.getDeclaringClass() != thisClass) {
  871. CtClass declClass = f.getDeclaringClass();
  872. if (isEnclosing(declClass, thisClass)) {
  873. AccessorMaker maker = declClass.getAccessorMaker();
  874. if (maker != null)
  875. return maker;
  876. }
  877. throw new CompileError("Field " + f.getName() + " in "
  878. + declClass.getName() + " is private.");
  879. }
  880. return null; // accessible field
  881. }
  882. /**
  883. * Sets exprType, arrayDim, and className.
  884. *
  885. * @return true if the field type is long or double.
  886. */
  887. private boolean setFieldType(FieldInfo finfo) throws CompileError {
  888. String type = finfo.getDescriptor();
  889. int i = 0;
  890. int dim = 0;
  891. char c = type.charAt(i);
  892. while (c == '[') {
  893. ++dim;
  894. c = type.charAt(++i);
  895. }
  896. arrayDim = dim;
  897. exprType = MemberResolver.descToType(c);
  898. if (c == 'L')
  899. className = type.substring(i + 1, type.indexOf(';', i + 1));
  900. else
  901. className = null;
  902. boolean is2byte = dim == 0 && (c == 'J' || c == 'D');
  903. return is2byte;
  904. }
  905. private int addFieldrefInfo(CtField f, FieldInfo finfo) {
  906. ConstPool cp = bytecode.getConstPool();
  907. String cname = f.getDeclaringClass().getName();
  908. int ci = cp.addClassInfo(cname);
  909. String name = finfo.getName();
  910. String type = finfo.getDescriptor();
  911. return cp.addFieldrefInfo(ci, name, type);
  912. }
  913. @Override
  914. protected void atClassObject2(String cname) throws CompileError {
  915. if (getMajorVersion() < ClassFile.JAVA_5)
  916. super.atClassObject2(cname);
  917. else
  918. bytecode.addLdc(bytecode.getConstPool().addClassInfo(cname));
  919. }
  920. @Override
  921. protected void atFieldPlusPlus(int token, boolean isPost,
  922. ASTree oprand, Expr expr, boolean doDup)
  923. throws CompileError
  924. {
  925. CtField f = fieldAccess(oprand, false);
  926. boolean is_static = resultStatic;
  927. if (!is_static)
  928. bytecode.addOpcode(DUP);
  929. int fi = atFieldRead(f, is_static);
  930. int t = exprType;
  931. boolean is2w = is2word(t, arrayDim);
  932. int dup_code;
  933. if (is_static)
  934. dup_code = (is2w ? DUP2 : DUP);
  935. else
  936. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  937. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  938. atFieldAssignCore(f, is_static, fi, is2w);
  939. }
  940. /* This method also returns a value in resultStatic.
  941. *
  942. * @param acceptLength true if array length is acceptable
  943. */
  944. protected CtField fieldAccess(ASTree expr, boolean acceptLength)
  945. throws CompileError
  946. {
  947. if (expr instanceof Member) {
  948. String name = ((Member)expr).get();
  949. CtField f = null;
  950. try {
  951. f = thisClass.getField(name);
  952. }
  953. catch (NotFoundException e) {
  954. // EXPR might be part of a static member access?
  955. throw new NoFieldException(name, expr);
  956. }
  957. boolean is_static = Modifier.isStatic(f.getModifiers());
  958. if (!is_static)
  959. if (inStaticMethod)
  960. throw new CompileError(
  961. "not available in a static method: " + name);
  962. else
  963. bytecode.addAload(0); // this
  964. resultStatic = is_static;
  965. return f;
  966. }
  967. else if (expr instanceof Expr) {
  968. Expr e = (Expr)expr;
  969. int op = e.getOperator();
  970. if (op == MEMBER) {
  971. /* static member by # (extension by Javassist)
  972. * For example, if int.class is parsed, the resulting tree
  973. * is (# "java.lang.Integer" "TYPE").
  974. */
  975. CtField f = resolver.lookupField(((Symbol)e.oprand1()).get(),
  976. (Symbol)e.oprand2());
  977. resultStatic = true;
  978. return f;
  979. }
  980. else if (op == '.') {
  981. CtField f = null;
  982. try {
  983. e.oprand1().accept(this);
  984. /* Don't call lookupFieldByJvmName2().
  985. * The left operand of . is not a class name but
  986. * a normal expression.
  987. */
  988. if (exprType == CLASS && arrayDim == 0)
  989. f = resolver.lookupFieldByJvmName(className,
  990. (Symbol)e.oprand2());
  991. else if (acceptLength && arrayDim > 0
  992. && ((Symbol)e.oprand2()).get().equals("length"))
  993. return null; // expr is an array length.
  994. else
  995. badLvalue();
  996. boolean is_static = Modifier.isStatic(f.getModifiers());
  997. if (is_static)
  998. bytecode.addOpcode(POP);
  999. resultStatic = is_static;
  1000. return f;
  1001. }
  1002. catch (NoFieldException nfe) {
  1003. if (nfe.getExpr() != e.oprand1())
  1004. throw nfe;
  1005. /* EXPR should be a static field.
  1006. * If EXPR might be part of a qualified class name,
  1007. * lookupFieldByJvmName2() throws NoFieldException.
  1008. */
  1009. Symbol fname = (Symbol)e.oprand2();
  1010. String cname = nfe.getField();
  1011. f = resolver.lookupFieldByJvmName2(cname, fname, expr);
  1012. resultStatic = true;
  1013. return f;
  1014. }
  1015. }
  1016. else
  1017. badLvalue();
  1018. }
  1019. else
  1020. badLvalue();
  1021. resultStatic = false;
  1022. return null; // never reach
  1023. }
  1024. private static void badLvalue() throws CompileError {
  1025. throw new CompileError("bad l-value");
  1026. }
  1027. public CtClass[] makeParamList(MethodDecl md) throws CompileError {
  1028. CtClass[] params;
  1029. ASTList plist = md.getParams();
  1030. if (plist == null)
  1031. params = new CtClass[0];
  1032. else {
  1033. int i = 0;
  1034. params = new CtClass[plist.length()];
  1035. while (plist != null) {
  1036. params[i++] = resolver.lookupClass((Declarator)plist.head());
  1037. plist = plist.tail();
  1038. }
  1039. }
  1040. return params;
  1041. }
  1042. public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
  1043. CtClass[] clist;
  1044. ASTList list = md.getThrows();
  1045. if (list == null)
  1046. return null;
  1047. int i = 0;
  1048. clist = new CtClass[list.length()];
  1049. while (list != null) {
  1050. clist[i++] = resolver.lookupClassByName((ASTList)list.head());
  1051. list = list.tail();
  1052. }
  1053. return clist;
  1054. }
  1055. /* Converts a class name into a JVM-internal representation.
  1056. *
  1057. * It may also expand a simple class name to java.lang.*.
  1058. * For example, this converts Object into java/lang/Object.
  1059. */
  1060. @Override
  1061. protected String resolveClassName(ASTList name) throws CompileError {
  1062. return resolver.resolveClassName(name);
  1063. }
  1064. /* Expands a simple class name to java.lang.*.
  1065. * For example, this converts Object into java/lang/Object.
  1066. */
  1067. @Override
  1068. protected String resolveClassName(String jvmName) throws CompileError {
  1069. return resolver.resolveJvmClassName(jvmName);
  1070. }
  1071. }