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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 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. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.compiler;
  16. import javassist.*;
  17. import javassist.bytecode.*;
  18. import javassist.compiler.ast.*;
  19. /* Code generator methods depending on javassist.* classes.
  20. */
  21. public class MemberCodeGen extends CodeGen {
  22. protected MemberResolver resolver;
  23. protected CtClass thisClass;
  24. protected MethodInfo thisMethod;
  25. protected boolean resultStatic;
  26. public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp)
  27. {
  28. super(b);
  29. resolver = new MemberResolver(cp);
  30. thisClass = cc;
  31. thisMethod = null;
  32. }
  33. /**
  34. * Records the currently compiled method.
  35. */
  36. public void setThisMethod(CtMethod m) {
  37. thisMethod = m.getMethodInfo2();
  38. if (typeChecker != null)
  39. typeChecker.setThisMethod(thisMethod);
  40. }
  41. public CtClass getThisClass() { return thisClass; }
  42. /**
  43. * Returns the JVM-internal representation of this class name.
  44. */
  45. protected String getThisName() {
  46. return MemberResolver.javaToJvmName(thisClass.getName());
  47. }
  48. /**
  49. * Returns the JVM-internal representation of this super class name.
  50. */
  51. protected String getSuperName() throws CompileError {
  52. return MemberResolver.javaToJvmName(
  53. MemberResolver.getSuperclass(thisClass).getName());
  54. }
  55. protected void insertDefaultSuperCall() throws CompileError {
  56. bytecode.addAload(0);
  57. bytecode.addInvokespecial(MemberResolver.getSuperclass(thisClass),
  58. "<init>", "()V");
  59. }
  60. protected void atTryStmnt(Stmnt st) throws CompileError {
  61. Stmnt body = (Stmnt)st.getLeft();
  62. if (body == null)
  63. return;
  64. int start = bytecode.currentPc();
  65. body.accept(this);
  66. int end = bytecode.currentPc();
  67. if (start == end)
  68. throw new CompileError("empty try block");
  69. bytecode.addOpcode(Opcode.GOTO);
  70. int pc = bytecode.currentPc();
  71. bytecode.addIndex(0); // correct later
  72. int var = getMaxLocals();
  73. incMaxLocals(1);
  74. ASTList catchList = (ASTList)st.getRight().getLeft();
  75. while (catchList != null) {
  76. Pair p = (Pair)catchList.head();
  77. catchList = catchList.tail();
  78. Declarator decl = (Declarator)p.getLeft();
  79. Stmnt block = (Stmnt)p.getRight();
  80. decl.setLocalVar(var);
  81. CtClass type = resolver.lookupClassByJvmName(decl.getClassName());
  82. decl.setClassName(MemberResolver.javaToJvmName(type.getName()));
  83. bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
  84. type);
  85. bytecode.growStack(1);
  86. bytecode.addAstore(var);
  87. if (block != null)
  88. block.accept(this);
  89. bytecode.addOpcode(Opcode.GOTO);
  90. bytecode.addIndex(pc - bytecode.currentPc());
  91. }
  92. Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft();
  93. if (finallyBlock != null)
  94. throw new CompileError(
  95. "sorry, finally has not been supported yet");
  96. bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
  97. hasReturned = false;
  98. }
  99. public void atNewExpr(NewExpr expr) throws CompileError {
  100. if (expr.isArray())
  101. atNewArrayExpr(expr);
  102. else {
  103. CtClass clazz = resolver.lookupClassByName(expr.getClassName());
  104. String cname = clazz.getName();
  105. ASTList args = expr.getArguments();
  106. bytecode.addNew(cname);
  107. bytecode.addOpcode(DUP);
  108. atMethodCallCore(clazz, MethodInfo.nameInit, args,
  109. false, true, -1, null);
  110. exprType = CLASS;
  111. arrayDim = 0;
  112. className = MemberResolver.javaToJvmName(cname);
  113. }
  114. }
  115. public void atNewArrayExpr(NewExpr expr) throws CompileError {
  116. if (expr.getInitializer() != null)
  117. throw new CompileError("array initializer is not supported");
  118. int type = expr.getArrayType();
  119. ASTList size = expr.getArraySize();
  120. ASTList classname = expr.getClassName();
  121. if (size.length() > 1) {
  122. atMultiNewArray(type, classname, size);
  123. return;
  124. }
  125. size.head().accept(this);
  126. exprType = type;
  127. arrayDim = 1;
  128. if (type == CLASS) {
  129. className = resolveClassName(classname);
  130. bytecode.addAnewarray(MemberResolver.jvmToJavaName(className));
  131. }
  132. else {
  133. className = null;
  134. int atype = 0;
  135. switch (type) {
  136. case BOOLEAN :
  137. atype = T_BOOLEAN;
  138. break;
  139. case CHAR :
  140. atype = T_CHAR;
  141. break;
  142. case FLOAT :
  143. atype = T_FLOAT;
  144. break;
  145. case DOUBLE :
  146. atype = T_DOUBLE;
  147. break;
  148. case BYTE :
  149. atype = T_BYTE;
  150. break;
  151. case SHORT :
  152. atype = T_SHORT;
  153. break;
  154. case INT :
  155. atype = T_INT;
  156. break;
  157. case LONG :
  158. atype = T_LONG;
  159. break;
  160. default :
  161. badNewExpr();
  162. break;
  163. }
  164. bytecode.addOpcode(NEWARRAY);
  165. bytecode.add(atype);
  166. }
  167. }
  168. private static void badNewExpr() throws CompileError {
  169. throw new CompileError("bad new expression");
  170. }
  171. protected void atMultiNewArray(int type, ASTList classname, ASTList size)
  172. throws CompileError
  173. {
  174. int count, dim;
  175. dim = size.length();
  176. for (count = 0; size != null; size = size.tail()) {
  177. ASTree s = size.head();
  178. if (s == null)
  179. break; // int[][][] a = new int[3][4][];
  180. ++count;
  181. s.accept(this);
  182. if (exprType != INT)
  183. throw new CompileError("bad type for array size");
  184. }
  185. String desc;
  186. exprType = type;
  187. arrayDim = dim;
  188. if (type == CLASS) {
  189. className = resolveClassName(classname);
  190. desc = toJvmArrayName(className, dim);
  191. }
  192. else
  193. desc = toJvmTypeName(type, dim);
  194. bytecode.addMultiNewarray(desc, count);
  195. }
  196. public void atCallExpr(CallExpr expr) throws CompileError {
  197. String mname = null;
  198. CtClass targetClass = null;
  199. ASTree method = expr.oprand1();
  200. ASTList args = (ASTList)expr.oprand2();
  201. boolean isStatic = false;
  202. boolean isSpecial = false;
  203. int aload0pos = -1;
  204. MemberResolver.Method cached = expr.getMethod();
  205. if (method instanceof Member) {
  206. mname = ((Member)method).get();
  207. targetClass = thisClass;
  208. if (inStaticMethod || (cached != null && cached.isStatic()))
  209. isStatic = true; // should be static
  210. else {
  211. aload0pos = bytecode.currentPc();
  212. bytecode.addAload(0); // this
  213. }
  214. }
  215. else if (method instanceof Keyword) { // constructor
  216. isSpecial = true;
  217. mname = MethodInfo.nameInit; // <init>
  218. targetClass = thisClass;
  219. if (inStaticMethod)
  220. throw new CompileError("a constructor cannot be static");
  221. else
  222. bytecode.addAload(0); // this
  223. if (((Keyword)method).get() == SUPER)
  224. targetClass = MemberResolver.getSuperclass(targetClass);
  225. }
  226. else if (method instanceof Expr) {
  227. Expr e = (Expr)method;
  228. mname = ((Symbol)e.oprand2()).get();
  229. int op = e.getOperator();
  230. if (op == MEMBER) { // static method
  231. targetClass
  232. = resolver.lookupClass(((Symbol)e.oprand1()).get(), false);
  233. isStatic = true;
  234. }
  235. else if (op == '.') {
  236. ASTree target = e.oprand1();
  237. if (target instanceof Keyword)
  238. if (((Keyword)target).get() == SUPER)
  239. isSpecial = true;
  240. try {
  241. target.accept(this);
  242. }
  243. catch (NoFieldException nfe) {
  244. if (nfe.getExpr() != target)
  245. throw nfe;
  246. // it should be a static method.
  247. exprType = CLASS;
  248. arrayDim = 0;
  249. className = nfe.getField(); // JVM-internal
  250. resolver.recordPackage(className);
  251. isStatic = true;
  252. }
  253. if (arrayDim > 0)
  254. targetClass = resolver.lookupClass(javaLangObject, true);
  255. else if (exprType == CLASS /* && arrayDim == 0 */)
  256. targetClass = resolver.lookupClassByJvmName(className);
  257. else
  258. badMethod();
  259. }
  260. else
  261. badMethod();
  262. }
  263. else
  264. fatal();
  265. atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
  266. aload0pos, cached);
  267. }
  268. private static void badMethod() throws CompileError {
  269. throw new CompileError("bad method");
  270. }
  271. /*
  272. * atMethodCallCore() is also called by doit() in NewExpr.ProceedForNew
  273. *
  274. * @param targetClass the class at which method lookup starts.
  275. * @param found not null if the method look has been already done.
  276. */
  277. public void atMethodCallCore(CtClass targetClass, String mname,
  278. ASTList args, boolean isStatic, boolean isSpecial,
  279. int aload0pos, MemberResolver.Method found)
  280. throws CompileError
  281. {
  282. int nargs = getMethodArgsLength(args);
  283. int[] types = new int[nargs];
  284. int[] dims = new int[nargs];
  285. String[] cnames = new String[nargs];
  286. if (!isStatic && found != null && found.isStatic()) {
  287. bytecode.addOpcode(POP);
  288. isStatic = true;
  289. }
  290. int stack = bytecode.getStackDepth();
  291. // generate code for evaluating arguments.
  292. atMethodArgs(args, types, dims, cnames);
  293. // used by invokeinterface
  294. int count = bytecode.getStackDepth() - stack + 1;
  295. if (found == null)
  296. found = resolver.lookupMethod(targetClass, thisMethod, mname,
  297. types, dims, cnames, false);
  298. if (found == null) {
  299. String msg;
  300. if (mname.equals(MethodInfo.nameInit))
  301. msg = "constructor not found";
  302. else
  303. msg = "Method " + mname + " not found in "
  304. + targetClass.getName();
  305. throw new CompileError(msg);
  306. }
  307. atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
  308. aload0pos, count, found);
  309. }
  310. private void atMethodCallCore2(CtClass targetClass, String mname,
  311. boolean isStatic, boolean isSpecial,
  312. int aload0pos, int count,
  313. MemberResolver.Method found)
  314. throws CompileError
  315. {
  316. CtClass declClass = found.declaring;
  317. MethodInfo minfo = found.info;
  318. String desc = minfo.getDescriptor();
  319. int acc = minfo.getAccessFlags();
  320. if (mname.equals(MethodInfo.nameInit)) {
  321. isSpecial = true;
  322. if (declClass != targetClass)
  323. throw new CompileError("no such a constructor");
  324. if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
  325. desc = getAccessibleConstructor(desc, declClass, minfo);
  326. bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter
  327. }
  328. }
  329. else if (AccessFlag.isPrivate(acc))
  330. if (declClass == thisClass)
  331. isSpecial = true;
  332. else {
  333. isSpecial = false;
  334. isStatic = true;
  335. String origDesc = desc;
  336. if ((acc & AccessFlag.STATIC) == 0)
  337. desc = Descriptor.insertParameter(declClass.getName(),
  338. origDesc);
  339. acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
  340. mname = getAccessiblePrivate(mname, origDesc, desc,
  341. minfo, declClass);
  342. }
  343. boolean popTarget = false;
  344. if ((acc & AccessFlag.STATIC) != 0) {
  345. if (!isStatic) {
  346. /* this method is static but the target object is
  347. on stack. It must be popped out. If aload0pos >= 0,
  348. then the target object was pushed by aload_0. It is
  349. overwritten by NOP.
  350. */
  351. isStatic = true;
  352. if (aload0pos >= 0)
  353. bytecode.write(aload0pos, NOP);
  354. else
  355. popTarget = true;
  356. }
  357. bytecode.addInvokestatic(declClass, mname, desc);
  358. }
  359. else if (isSpecial) // if (isSpecial && notStatic(acc))
  360. bytecode.addInvokespecial(declClass, mname, desc);
  361. else if (declClass.isInterface())
  362. bytecode.addInvokeinterface(declClass, mname, desc, count);
  363. else
  364. if (isStatic)
  365. throw new CompileError(mname + " is not static");
  366. else
  367. bytecode.addInvokevirtual(declClass, mname, desc);
  368. setReturnType(desc, isStatic, popTarget);
  369. }
  370. /*
  371. * Finds (or adds if necessary) a hidden accessor if the method
  372. * is in an enclosing class.
  373. *
  374. * @param desc the descriptor of the method.
  375. * @param declClass the class declaring the method.
  376. */
  377. protected String getAccessiblePrivate(String methodName, String desc,
  378. String newDesc, MethodInfo minfo,
  379. CtClass declClass)
  380. throws CompileError
  381. {
  382. if (isEnclosing(declClass, thisClass)) {
  383. AccessorMaker maker = declClass.getAccessorMaker();
  384. if (maker != null)
  385. return maker.getMethodAccessor(methodName, desc, newDesc,
  386. minfo);
  387. }
  388. throw new CompileError("Method " + methodName
  389. + " is private");
  390. }
  391. /*
  392. * Finds (or adds if necessary) a hidden constructor if the given
  393. * constructor is in an enclosing class.
  394. *
  395. * @param desc the descriptor of the constructor.
  396. * @param declClass the class declaring the constructor.
  397. * @param minfo the method info of the constructor.
  398. * @return the descriptor of the hidden constructor.
  399. */
  400. protected String getAccessibleConstructor(String desc, CtClass declClass,
  401. MethodInfo minfo)
  402. throws CompileError
  403. {
  404. if (isEnclosing(declClass, thisClass)) {
  405. AccessorMaker maker = declClass.getAccessorMaker();
  406. if (maker != null)
  407. return maker.getConstructor(declClass, desc, minfo);
  408. }
  409. throw new CompileError("the called constructor is private in "
  410. + declClass.getName());
  411. }
  412. private boolean isEnclosing(CtClass outer, CtClass inner) {
  413. try {
  414. while (inner != null) {
  415. inner = inner.getDeclaringClass();
  416. if (inner == outer)
  417. return true;
  418. }
  419. }
  420. catch (NotFoundException e) {}
  421. return false;
  422. }
  423. public int getMethodArgsLength(ASTList args) {
  424. return ASTList.length(args);
  425. }
  426. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  427. String[] cnames) throws CompileError {
  428. int i = 0;
  429. while (args != null) {
  430. ASTree a = args.head();
  431. a.accept(this);
  432. types[i] = exprType;
  433. dims[i] = arrayDim;
  434. cnames[i] = className;
  435. ++i;
  436. args = args.tail();
  437. }
  438. }
  439. void setReturnType(String desc, boolean isStatic, boolean popTarget)
  440. throws CompileError
  441. {
  442. int i = desc.indexOf(')');
  443. if (i < 0)
  444. badMethod();
  445. char c = desc.charAt(++i);
  446. int dim = 0;
  447. while (c == '[') {
  448. ++dim;
  449. c = desc.charAt(++i);
  450. }
  451. arrayDim = dim;
  452. if (c == 'L') {
  453. int j = desc.indexOf(';', i + 1);
  454. if (j < 0)
  455. badMethod();
  456. exprType = CLASS;
  457. className = desc.substring(i + 1, j);
  458. }
  459. else {
  460. exprType = MemberResolver.descToType(c);
  461. className = null;
  462. }
  463. int etype = exprType;
  464. if (isStatic) {
  465. if (popTarget) {
  466. if (is2word(etype, dim)) {
  467. bytecode.addOpcode(DUP2_X1);
  468. bytecode.addOpcode(POP2);
  469. bytecode.addOpcode(POP);
  470. }
  471. else if (etype == VOID)
  472. bytecode.addOpcode(POP);
  473. else {
  474. bytecode.addOpcode(SWAP);
  475. bytecode.addOpcode(POP);
  476. }
  477. }
  478. }
  479. }
  480. protected void atFieldAssign(Expr expr, int op, ASTree left,
  481. ASTree right, boolean doDup) throws CompileError
  482. {
  483. CtField f = fieldAccess(left);
  484. boolean is_static = resultStatic;
  485. if (op != '=' && !is_static)
  486. bytecode.addOpcode(DUP);
  487. int fi;
  488. if (op == '=') {
  489. FieldInfo finfo = f.getFieldInfo2();
  490. setFieldType(finfo);
  491. AccessorMaker maker = isAccessibleField(f, finfo);
  492. if (maker == null)
  493. fi = addFieldrefInfo(f, finfo);
  494. else
  495. fi = 0;
  496. }
  497. else
  498. fi = atFieldRead(f, is_static);
  499. int fType = exprType;
  500. int fDim = arrayDim;
  501. String cname = className;
  502. atAssignCore(expr, op, right, fType, fDim, cname);
  503. boolean is2w = is2word(fType, fDim);
  504. if (doDup) {
  505. int dup_code;
  506. if (is_static)
  507. dup_code = (is2w ? DUP2 : DUP);
  508. else
  509. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  510. bytecode.addOpcode(dup_code);
  511. }
  512. atFieldAssignCore(f, is_static, fi, is2w);
  513. exprType = fType;
  514. arrayDim = fDim;
  515. className = cname;
  516. }
  517. /* If fi == 0, the field must be a private field in an enclosing class.
  518. */
  519. private void atFieldAssignCore(CtField f, boolean is_static, int fi,
  520. boolean is2byte) throws CompileError {
  521. if (fi != 0) {
  522. if (is_static) {
  523. bytecode.add(PUTSTATIC);
  524. bytecode.growStack(is2byte ? -2 : -1);
  525. }
  526. else {
  527. bytecode.add(PUTFIELD);
  528. bytecode.growStack(is2byte ? -3 : -2);
  529. }
  530. bytecode.addIndex(fi);
  531. }
  532. else {
  533. CtClass declClass = f.getDeclaringClass();
  534. AccessorMaker maker = declClass.getAccessorMaker();
  535. // make should be non null.
  536. FieldInfo finfo = f.getFieldInfo2();
  537. MethodInfo minfo = maker.getFieldSetter(finfo, is_static);
  538. bytecode.addInvokestatic(declClass, minfo.getName(),
  539. minfo.getDescriptor());
  540. }
  541. }
  542. /* overwritten in JvstCodeGen.
  543. */
  544. public void atMember(Member mem) throws CompileError {
  545. atFieldRead(mem);
  546. }
  547. protected void atFieldRead(ASTree expr) throws CompileError
  548. {
  549. CtField f = fieldAccess(expr);
  550. boolean is_static = resultStatic;
  551. atFieldRead(f, is_static);
  552. }
  553. /**
  554. * Generates bytecode for reading a field value.
  555. * It returns a fieldref_info index or zero if the field is a private
  556. * one declared in an enclosing class.
  557. */
  558. private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
  559. FieldInfo finfo = f.getFieldInfo2();
  560. boolean is2byte = setFieldType(finfo);
  561. AccessorMaker maker = isAccessibleField(f, finfo);
  562. if (maker != null) {
  563. MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
  564. bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
  565. minfo.getDescriptor());
  566. return 0;
  567. }
  568. else {
  569. int fi = addFieldrefInfo(f, finfo);
  570. if (isStatic) {
  571. bytecode.add(GETSTATIC);
  572. bytecode.growStack(is2byte ? 2 : 1);
  573. }
  574. else {
  575. bytecode.add(GETFIELD);
  576. bytecode.growStack(is2byte ? 1 : 0);
  577. }
  578. bytecode.addIndex(fi);
  579. return fi;
  580. }
  581. }
  582. /**
  583. * Returns null if the field is accessible. Otherwise, it throws
  584. * an exception or it returns AccessorMaker if the field is a private
  585. * one declared in an enclosing class.
  586. */
  587. private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
  588. throws CompileError
  589. {
  590. if (AccessFlag.isPrivate(finfo.getAccessFlags())
  591. && f.getDeclaringClass() != thisClass) {
  592. CtClass declClass = f.getDeclaringClass();
  593. if (isEnclosing(declClass, thisClass)) {
  594. AccessorMaker maker = declClass.getAccessorMaker();
  595. if (maker != null)
  596. return maker;
  597. else
  598. throw new CompileError("fatal error. bug?");
  599. }
  600. else
  601. throw new CompileError("Field " + f.getName() + " in "
  602. + declClass.getName() + " is private.");
  603. }
  604. return null; // accessible field
  605. }
  606. /**
  607. * Sets exprType, arrayDim, and className.
  608. *
  609. * @return true if the field type is long or double.
  610. */
  611. private boolean setFieldType(FieldInfo finfo) throws CompileError {
  612. String type = finfo.getDescriptor();
  613. int i = 0;
  614. int dim = 0;
  615. char c = type.charAt(i);
  616. while (c == '[') {
  617. ++dim;
  618. c = type.charAt(++i);
  619. }
  620. arrayDim = dim;
  621. exprType = MemberResolver.descToType(c);
  622. if (c == 'L')
  623. className = type.substring(i + 1, type.indexOf(';', i + 1));
  624. else
  625. className = null;
  626. boolean is2byte = (c == 'J' || c == 'D');
  627. return is2byte;
  628. }
  629. private int addFieldrefInfo(CtField f, FieldInfo finfo) {
  630. ConstPool cp = bytecode.getConstPool();
  631. String cname = f.getDeclaringClass().getName();
  632. int ci = cp.addClassInfo(cname);
  633. String name = finfo.getName();
  634. String type = finfo.getDescriptor();
  635. return cp.addFieldrefInfo(ci, name, type);
  636. }
  637. protected void atFieldPlusPlus(int token, boolean isPost,
  638. ASTree oprand, Expr expr, boolean doDup)
  639. throws CompileError
  640. {
  641. CtField f = fieldAccess(oprand);
  642. boolean is_static = resultStatic;
  643. if (!is_static)
  644. bytecode.addOpcode(DUP);
  645. int fi = atFieldRead(f, is_static);
  646. int t = exprType;
  647. boolean is2w = is2word(t, arrayDim);
  648. int dup_code;
  649. if (is_static)
  650. dup_code = (is2w ? DUP2 : DUP);
  651. else
  652. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  653. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  654. atFieldAssignCore(f, is_static, fi, is2w);
  655. }
  656. /* This method also returns a value in resultStatic.
  657. */
  658. protected CtField fieldAccess(ASTree expr) throws CompileError {
  659. if (expr instanceof Member) {
  660. String name = ((Member)expr).get();
  661. CtField f = null;
  662. try {
  663. f = thisClass.getField(name);
  664. }
  665. catch (NotFoundException e) {
  666. // EXPR might be part of a static member access?
  667. throw new NoFieldException(name, expr);
  668. }
  669. boolean is_static = Modifier.isStatic(f.getModifiers());
  670. if (!is_static)
  671. if (inStaticMethod)
  672. throw new CompileError(
  673. "not available in a static method: " + name);
  674. else
  675. bytecode.addAload(0); // this
  676. resultStatic = is_static;
  677. return f;
  678. }
  679. else if (expr instanceof Expr) {
  680. Expr e = (Expr)expr;
  681. int op = e.getOperator();
  682. if (op == MEMBER) {
  683. /* static member by # (extension by Javassist)
  684. * For example, if int.class is parsed, the resulting tree
  685. * is (# "java.lang.Integer" "TYPE").
  686. */
  687. CtField f = resolver.lookupField(((Symbol)e.oprand1()).get(),
  688. (Symbol)e.oprand2());
  689. resultStatic = true;
  690. return f;
  691. }
  692. else if (op == '.') {
  693. CtField f = null;
  694. try {
  695. e.oprand1().accept(this);
  696. /* Don't call lookupFieldByJvmName2().
  697. * The left operand of . is not a class name but
  698. * a normal expression.
  699. */
  700. if (exprType == CLASS && arrayDim == 0)
  701. f = resolver.lookupFieldByJvmName(className,
  702. (Symbol)e.oprand2());
  703. else
  704. badLvalue();
  705. boolean is_static = Modifier.isStatic(f.getModifiers());
  706. if (is_static)
  707. bytecode.addOpcode(POP);
  708. resultStatic = is_static;
  709. return f;
  710. }
  711. catch (NoFieldException nfe) {
  712. if (nfe.getExpr() != e.oprand1())
  713. throw nfe;
  714. /* EXPR should be a static field.
  715. * If EXPR might be part of a qualified class name,
  716. * lookupFieldByJvmName2() throws NoFieldException.
  717. */
  718. Symbol fname = (Symbol)e.oprand2();
  719. String cname = nfe.getField();
  720. f = resolver.lookupFieldByJvmName2(cname, fname, expr);
  721. resolver.recordPackage(cname);
  722. resultStatic = true;
  723. return f;
  724. }
  725. }
  726. else
  727. badLvalue();
  728. }
  729. else
  730. badLvalue();
  731. resultStatic = false;
  732. return null; // never reach
  733. }
  734. private static void badLvalue() throws CompileError {
  735. throw new CompileError("bad l-value");
  736. }
  737. public CtClass[] makeParamList(MethodDecl md) throws CompileError {
  738. CtClass[] params;
  739. ASTList plist = md.getParams();
  740. if (plist == null)
  741. params = new CtClass[0];
  742. else {
  743. int i = 0;
  744. params = new CtClass[plist.length()];
  745. while (plist != null) {
  746. params[i++] = resolver.lookupClass((Declarator)plist.head());
  747. plist = plist.tail();
  748. }
  749. }
  750. return params;
  751. }
  752. public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
  753. CtClass[] clist;
  754. ASTList list = md.getThrows();
  755. if (list == null)
  756. return null;
  757. else {
  758. int i = 0;
  759. clist = new CtClass[list.length()];
  760. while (list != null) {
  761. clist[i++] = resolver.lookupClassByName((ASTList)list.head());
  762. list = list.tail();
  763. }
  764. return clist;
  765. }
  766. }
  767. /* Converts a class name into a JVM-internal representation.
  768. *
  769. * It may also expand a simple class name to java.lang.*.
  770. * For example, this converts Object into java/lang/Object.
  771. */
  772. protected String resolveClassName(ASTList name) throws CompileError {
  773. return resolver.resolveClassName(name);
  774. }
  775. /* Expands a simple class name to java.lang.*.
  776. * For example, this converts Object into java/lang/Object.
  777. */
  778. protected String resolveClassName(String jvmName) throws CompileError {
  779. return resolver.resolveJvmClassName(jvmName);
  780. }
  781. }