Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

MemberCodeGen.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  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. atMethodArgs(args, types, dims, cnames);
  292. // used by invokeinterface
  293. int count = bytecode.getStackDepth() - stack + 1;
  294. if (found == null)
  295. found = resolver.lookupMethod(targetClass, thisMethod, mname,
  296. types, dims, cnames, false);
  297. if (found == null) {
  298. String msg;
  299. if (mname.equals(MethodInfo.nameInit))
  300. msg = "constructor not found";
  301. else
  302. msg = "Method " + mname + " not found in "
  303. + targetClass.getName();
  304. throw new CompileError(msg);
  305. }
  306. atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
  307. aload0pos, count, found);
  308. }
  309. private void atMethodCallCore2(CtClass targetClass, String mname,
  310. boolean isStatic, boolean isSpecial,
  311. int aload0pos, int count,
  312. MemberResolver.Method found)
  313. throws CompileError
  314. {
  315. CtClass declClass = found.declaring;
  316. MethodInfo minfo = found.info;
  317. String desc = minfo.getDescriptor();
  318. int acc = minfo.getAccessFlags();
  319. if (mname.equals(MethodInfo.nameInit)) {
  320. isSpecial = true;
  321. if (declClass != targetClass)
  322. throw new CompileError("no such a constructor");
  323. }
  324. else if (AccessFlag.isPrivate(acc))
  325. if (declClass == thisClass)
  326. isSpecial = true;
  327. else {
  328. String orgName = mname;
  329. isSpecial = false;
  330. isStatic = true;
  331. String origDesc = desc;
  332. if ((acc & AccessFlag.STATIC) == 0)
  333. desc = Descriptor.insertParameter(declClass.getName(),
  334. origDesc);
  335. acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
  336. mname = getAccessiblePrivate(mname, origDesc, desc,
  337. minfo, declClass);
  338. if (mname == null)
  339. throw new CompileError("Method " + orgName
  340. + " is private");
  341. }
  342. boolean popTarget = false;
  343. if ((acc & AccessFlag.STATIC) != 0) {
  344. if (!isStatic) {
  345. /* this method is static but the target object is
  346. on stack. It must be popped out. If aload0pos >= 0,
  347. then the target object was pushed by aload_0. It is
  348. overwritten by NOP.
  349. */
  350. isStatic = true;
  351. if (aload0pos >= 0)
  352. bytecode.write(aload0pos, NOP);
  353. else
  354. popTarget = true;
  355. }
  356. bytecode.addInvokestatic(declClass, mname, desc);
  357. }
  358. else if (isSpecial) // if (isSpecial && notStatic(acc))
  359. bytecode.addInvokespecial(declClass, mname, desc);
  360. else if (declClass.isInterface())
  361. bytecode.addInvokeinterface(declClass, mname, desc, count);
  362. else
  363. if (isStatic)
  364. throw new CompileError(mname + " is not static");
  365. else
  366. bytecode.addInvokevirtual(declClass, mname, desc);
  367. setReturnType(desc, isStatic, popTarget);
  368. }
  369. /*
  370. * Finds (or adds if necessary) a hidden accessor if the method
  371. * is in an enclosing class.
  372. *
  373. * @param desc the descriptor of the method.
  374. * @param declClass the class declaring the method.
  375. */
  376. protected String getAccessiblePrivate(String methodName, String desc,
  377. String newDesc, MethodInfo minfo,
  378. CtClass declClass)
  379. throws CompileError
  380. {
  381. if (isEnclosing(declClass, thisClass)) {
  382. AccessorMaker maker = declClass.getAccessorMaker();
  383. if (maker == null)
  384. return null;
  385. else
  386. return maker.getMethodAccessor(methodName, desc, newDesc,
  387. minfo);
  388. }
  389. else
  390. return null; // cannot access this private method.
  391. }
  392. private boolean isEnclosing(CtClass outer, CtClass inner) {
  393. try {
  394. while (inner != null) {
  395. inner = inner.getDeclaringClass();
  396. if (inner == outer)
  397. return true;
  398. }
  399. }
  400. catch (NotFoundException e) {}
  401. return false;
  402. }
  403. public int getMethodArgsLength(ASTList args) {
  404. return ASTList.length(args);
  405. }
  406. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  407. String[] cnames) throws CompileError {
  408. int i = 0;
  409. while (args != null) {
  410. ASTree a = args.head();
  411. a.accept(this);
  412. types[i] = exprType;
  413. dims[i] = arrayDim;
  414. cnames[i] = className;
  415. ++i;
  416. args = args.tail();
  417. }
  418. }
  419. void setReturnType(String desc, boolean isStatic, boolean popTarget)
  420. throws CompileError
  421. {
  422. int i = desc.indexOf(')');
  423. if (i < 0)
  424. badMethod();
  425. char c = desc.charAt(++i);
  426. int dim = 0;
  427. while (c == '[') {
  428. ++dim;
  429. c = desc.charAt(++i);
  430. }
  431. arrayDim = dim;
  432. if (c == 'L') {
  433. int j = desc.indexOf(';', i + 1);
  434. if (j < 0)
  435. badMethod();
  436. exprType = CLASS;
  437. className = desc.substring(i + 1, j);
  438. }
  439. else {
  440. exprType = MemberResolver.descToType(c);
  441. className = null;
  442. }
  443. int etype = exprType;
  444. if (isStatic) {
  445. if (popTarget) {
  446. if (is2word(etype, dim)) {
  447. bytecode.addOpcode(DUP2_X1);
  448. bytecode.addOpcode(POP2);
  449. bytecode.addOpcode(POP);
  450. }
  451. else if (etype == VOID)
  452. bytecode.addOpcode(POP);
  453. else {
  454. bytecode.addOpcode(SWAP);
  455. bytecode.addOpcode(POP);
  456. }
  457. }
  458. }
  459. }
  460. protected void atFieldAssign(Expr expr, int op, ASTree left,
  461. ASTree right, boolean doDup) throws CompileError
  462. {
  463. CtField f = fieldAccess(left);
  464. boolean is_static = resultStatic;
  465. if (op != '=' && !is_static)
  466. bytecode.addOpcode(DUP);
  467. int fi;
  468. if (op == '=') {
  469. FieldInfo finfo = f.getFieldInfo2();
  470. setFieldType(finfo);
  471. AccessorMaker maker = isAccessibleField(f, finfo);
  472. if (maker == null)
  473. fi = addFieldrefInfo(f, finfo);
  474. else
  475. fi = 0;
  476. }
  477. else
  478. fi = atFieldRead(f, is_static);
  479. int fType = exprType;
  480. int fDim = arrayDim;
  481. String cname = className;
  482. atAssignCore(expr, op, right, fType, fDim, cname);
  483. boolean is2w = is2word(fType, fDim);
  484. if (doDup) {
  485. int dup_code;
  486. if (is_static)
  487. dup_code = (is2w ? DUP2 : DUP);
  488. else
  489. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  490. bytecode.addOpcode(dup_code);
  491. }
  492. atFieldAssignCore(f, is_static, fi, is2w);
  493. exprType = fType;
  494. arrayDim = fDim;
  495. className = cname;
  496. }
  497. /* If fi == 0, the field must be a private field in an enclosing class.
  498. */
  499. private void atFieldAssignCore(CtField f, boolean is_static, int fi,
  500. boolean is2byte) throws CompileError {
  501. if (fi != 0) {
  502. if (is_static) {
  503. bytecode.add(PUTSTATIC);
  504. bytecode.growStack(is2byte ? -2 : -1);
  505. }
  506. else {
  507. bytecode.add(PUTFIELD);
  508. bytecode.growStack(is2byte ? -3 : -2);
  509. }
  510. bytecode.addIndex(fi);
  511. }
  512. else {
  513. CtClass declClass = f.getDeclaringClass();
  514. AccessorMaker maker = declClass.getAccessorMaker();
  515. // make should be non null.
  516. FieldInfo finfo = f.getFieldInfo2();
  517. MethodInfo minfo = maker.getFieldSetter(finfo, is_static);
  518. bytecode.addInvokestatic(declClass, minfo.getName(),
  519. minfo.getDescriptor());
  520. }
  521. }
  522. /* overwritten in JvstCodeGen.
  523. */
  524. public void atMember(Member mem) throws CompileError {
  525. atFieldRead(mem);
  526. }
  527. protected void atFieldRead(ASTree expr) throws CompileError
  528. {
  529. CtField f = fieldAccess(expr);
  530. boolean is_static = resultStatic;
  531. atFieldRead(f, is_static);
  532. }
  533. /**
  534. * Generates bytecode for reading a field value.
  535. * It returns a fieldref_info index or zero if the field is a private
  536. * one declared in an enclosing class.
  537. */
  538. private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
  539. FieldInfo finfo = f.getFieldInfo2();
  540. boolean is2byte = setFieldType(finfo);
  541. AccessorMaker maker = isAccessibleField(f, finfo);
  542. if (maker != null) {
  543. MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
  544. bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
  545. minfo.getDescriptor());
  546. return 0;
  547. }
  548. else {
  549. int fi = addFieldrefInfo(f, finfo);
  550. if (isStatic) {
  551. bytecode.add(GETSTATIC);
  552. bytecode.growStack(is2byte ? 2 : 1);
  553. }
  554. else {
  555. bytecode.add(GETFIELD);
  556. bytecode.growStack(is2byte ? 1 : 0);
  557. }
  558. bytecode.addIndex(fi);
  559. return fi;
  560. }
  561. }
  562. /**
  563. * Returns null if the field is accessible. Otherwise, it throws
  564. * an exception or it returns AccessorMaker if the field is a private
  565. * one declared in an enclosing class.
  566. */
  567. private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
  568. throws CompileError
  569. {
  570. if (AccessFlag.isPrivate(finfo.getAccessFlags())
  571. && f.getDeclaringClass() != thisClass) {
  572. CtClass declClass = f.getDeclaringClass();
  573. if (isEnclosing(declClass, thisClass)) {
  574. AccessorMaker maker = declClass.getAccessorMaker();
  575. if (maker != null)
  576. return maker;
  577. else
  578. throw new CompileError("fatal error. bug?");
  579. }
  580. else
  581. throw new CompileError("Field " + f.getName() + " in "
  582. + declClass.getName() + " is private.");
  583. }
  584. return null; // accessible field
  585. }
  586. /**
  587. * Sets exprType, arrayDim, and className.
  588. *
  589. * @return true if the field type is long or double.
  590. */
  591. private boolean setFieldType(FieldInfo finfo) throws CompileError {
  592. String type = finfo.getDescriptor();
  593. int i = 0;
  594. int dim = 0;
  595. char c = type.charAt(i);
  596. while (c == '[') {
  597. ++dim;
  598. c = type.charAt(++i);
  599. }
  600. arrayDim = dim;
  601. exprType = MemberResolver.descToType(c);
  602. if (c == 'L')
  603. className = type.substring(i + 1, type.indexOf(';', i + 1));
  604. else
  605. className = null;
  606. boolean is2byte = (c == 'J' || c == 'D');
  607. return is2byte;
  608. }
  609. private int addFieldrefInfo(CtField f, FieldInfo finfo) {
  610. ConstPool cp = bytecode.getConstPool();
  611. String cname = f.getDeclaringClass().getName();
  612. int ci = cp.addClassInfo(cname);
  613. String name = finfo.getName();
  614. String type = finfo.getDescriptor();
  615. return cp.addFieldrefInfo(ci, name, type);
  616. }
  617. protected void atFieldPlusPlus(int token, boolean isPost,
  618. ASTree oprand, Expr expr, boolean doDup)
  619. throws CompileError
  620. {
  621. CtField f = fieldAccess(oprand);
  622. boolean is_static = resultStatic;
  623. if (!is_static)
  624. bytecode.addOpcode(DUP);
  625. int fi = atFieldRead(f, is_static);
  626. int t = exprType;
  627. boolean is2w = is2word(t, arrayDim);
  628. int dup_code;
  629. if (is_static)
  630. dup_code = (is2w ? DUP2 : DUP);
  631. else
  632. dup_code = (is2w ? DUP2_X1 : DUP_X1);
  633. atPlusPlusCore(dup_code, doDup, token, isPost, expr);
  634. atFieldAssignCore(f, is_static, fi, is2w);
  635. }
  636. /* This method also returns a value in resultStatic.
  637. */
  638. protected CtField fieldAccess(ASTree expr) throws CompileError {
  639. if (expr instanceof Member) {
  640. String name = ((Member)expr).get();
  641. CtField f = null;
  642. try {
  643. f = thisClass.getField(name);
  644. }
  645. catch (NotFoundException e) {
  646. // EXPR might be part of a static member access?
  647. throw new NoFieldException(name, expr);
  648. }
  649. boolean is_static = Modifier.isStatic(f.getModifiers());
  650. if (!is_static)
  651. if (inStaticMethod)
  652. throw new CompileError(
  653. "not available in a static method: " + name);
  654. else
  655. bytecode.addAload(0); // this
  656. resultStatic = is_static;
  657. return f;
  658. }
  659. else if (expr instanceof Expr) {
  660. Expr e = (Expr)expr;
  661. int op = e.getOperator();
  662. if (op == MEMBER) {
  663. // static member by # (extension by Javassist)
  664. CtField f = resolver.lookupField(((Symbol)e.oprand1()).get(),
  665. (Symbol)e.oprand2());
  666. resultStatic = true;
  667. return f;
  668. }
  669. else if (op == '.') {
  670. CtField f = null;
  671. try {
  672. e.oprand1().accept(this);
  673. /* Don't call lookupFieldByJvmName2().
  674. * The left operand of . is not a class name but
  675. * a normal expression.
  676. */
  677. if (exprType == CLASS && arrayDim == 0)
  678. f = resolver.lookupFieldByJvmName(className,
  679. (Symbol)e.oprand2());
  680. else
  681. badLvalue();
  682. boolean is_static = Modifier.isStatic(f.getModifiers());
  683. if (is_static)
  684. bytecode.addOpcode(POP);
  685. resultStatic = is_static;
  686. return f;
  687. }
  688. catch (NoFieldException nfe) {
  689. if (nfe.getExpr() != e.oprand1())
  690. throw nfe;
  691. /* EXPR should be a static field.
  692. * If EXPR might be part of a qualified class name,
  693. * lookupFieldByJvmName2() throws NoFieldException.
  694. */
  695. Symbol fname = (Symbol)e.oprand2();
  696. String cname = nfe.getField();
  697. f = resolver.lookupFieldByJvmName2(cname, fname, expr);
  698. resolver.recordPackage(cname);
  699. resultStatic = true;
  700. return f;
  701. }
  702. }
  703. else
  704. badLvalue();
  705. }
  706. else
  707. badLvalue();
  708. resultStatic = false;
  709. return null; // never reach
  710. }
  711. private static void badLvalue() throws CompileError {
  712. throw new CompileError("bad l-value");
  713. }
  714. public CtClass[] makeParamList(MethodDecl md) throws CompileError {
  715. CtClass[] params;
  716. ASTList plist = md.getParams();
  717. if (plist == null)
  718. params = new CtClass[0];
  719. else {
  720. int i = 0;
  721. params = new CtClass[plist.length()];
  722. while (plist != null) {
  723. params[i++] = resolver.lookupClass((Declarator)plist.head());
  724. plist = plist.tail();
  725. }
  726. }
  727. return params;
  728. }
  729. public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
  730. CtClass[] clist;
  731. ASTList list = md.getThrows();
  732. if (list == null)
  733. return null;
  734. else {
  735. int i = 0;
  736. clist = new CtClass[list.length()];
  737. while (list != null) {
  738. clist[i++] = resolver.lookupClassByName((ASTList)list.head());
  739. list = list.tail();
  740. }
  741. return clist;
  742. }
  743. }
  744. /* Converts a class name into a JVM-internal representation.
  745. *
  746. * It may also expand a simple class name to java.lang.*.
  747. * For example, this converts Object into java/lang/Object.
  748. */
  749. protected String resolveClassName(ASTList name) throws CompileError {
  750. return resolver.resolveClassName(name);
  751. }
  752. /* Expands a simple class name to java.lang.*.
  753. * For example, this converts Object into java/lang/Object.
  754. */
  755. protected String resolveClassName(String jvmName) throws CompileError {
  756. return resolver.resolveJvmClassName(jvmName);
  757. }
  758. }