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.

FieldAccess.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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.expr;
  17. import javassist.CannotCompileException;
  18. import javassist.ClassPool;
  19. import javassist.CtBehavior;
  20. import javassist.CtClass;
  21. import javassist.CtField;
  22. import javassist.CtPrimitiveType;
  23. import javassist.NotFoundException;
  24. import javassist.bytecode.BadBytecode;
  25. import javassist.bytecode.Bytecode;
  26. import javassist.bytecode.CodeAttribute;
  27. import javassist.bytecode.CodeIterator;
  28. import javassist.bytecode.ConstPool;
  29. import javassist.bytecode.Descriptor;
  30. import javassist.bytecode.MethodInfo;
  31. import javassist.bytecode.Opcode;
  32. import javassist.compiler.CompileError;
  33. import javassist.compiler.Javac;
  34. import javassist.compiler.JvstCodeGen;
  35. import javassist.compiler.JvstTypeChecker;
  36. import javassist.compiler.ProceedHandler;
  37. import javassist.compiler.ast.ASTList;
  38. /**
  39. * Expression for accessing a field.
  40. */
  41. public class FieldAccess extends Expr {
  42. int opcode;
  43. protected FieldAccess(int pos, CodeIterator i, CtClass declaring,
  44. MethodInfo m, int op) {
  45. super(pos, i, declaring, m);
  46. opcode = op;
  47. }
  48. /**
  49. * Returns the method or constructor containing the field-access
  50. * expression represented by this object.
  51. */
  52. @Override
  53. public CtBehavior where() { return super.where(); }
  54. /**
  55. * Returns the line number of the source line containing the
  56. * field access.
  57. *
  58. * @return -1 if this information is not available.
  59. */
  60. @Override
  61. public int getLineNumber() {
  62. return super.getLineNumber();
  63. }
  64. /**
  65. * Returns the source file containing the field access.
  66. *
  67. * @return null if this information is not available.
  68. */
  69. @Override
  70. public String getFileName() {
  71. return super.getFileName();
  72. }
  73. /**
  74. * Returns true if the field is static.
  75. */
  76. public boolean isStatic() {
  77. return isStatic(opcode);
  78. }
  79. static boolean isStatic(int c) {
  80. return c == Opcode.GETSTATIC || c == Opcode.PUTSTATIC;
  81. }
  82. /**
  83. * Returns true if the field is read.
  84. */
  85. public boolean isReader() {
  86. return opcode == Opcode.GETFIELD || opcode == Opcode.GETSTATIC;
  87. }
  88. /**
  89. * Returns true if the field is written in.
  90. */
  91. public boolean isWriter() {
  92. return opcode == Opcode.PUTFIELD || opcode == Opcode.PUTSTATIC;
  93. }
  94. /**
  95. * Returns the class in which the field is declared.
  96. */
  97. private CtClass getCtClass() throws NotFoundException {
  98. return thisClass.getClassPool().get(getClassName());
  99. }
  100. /**
  101. * Returns the name of the class in which the field is declared.
  102. */
  103. public String getClassName() {
  104. int index = iterator.u16bitAt(currentPos + 1);
  105. return getConstPool().getFieldrefClassName(index);
  106. }
  107. /**
  108. * Returns the name of the field.
  109. */
  110. public String getFieldName() {
  111. int index = iterator.u16bitAt(currentPos + 1);
  112. return getConstPool().getFieldrefName(index);
  113. }
  114. /**
  115. * Returns the field accessed by this expression.
  116. */
  117. public CtField getField() throws NotFoundException {
  118. CtClass cc = getCtClass();
  119. int index = iterator.u16bitAt(currentPos + 1);
  120. ConstPool cp = getConstPool();
  121. return cc.getField(cp.getFieldrefName(index), cp.getFieldrefType(index));
  122. }
  123. /**
  124. * Returns the list of exceptions that the expression may throw.
  125. * This list includes both the exceptions that the try-catch statements
  126. * including the expression can catch and the exceptions that
  127. * the throws declaration allows the method to throw.
  128. */
  129. @Override
  130. public CtClass[] mayThrow() {
  131. return super.mayThrow();
  132. }
  133. /**
  134. * Returns the signature of the field type.
  135. * The signature is represented by a character string
  136. * called field descriptor, which is defined in the JVM specification.
  137. *
  138. * @see javassist.bytecode.Descriptor#toCtClass(String, ClassPool)
  139. * @since 3.1
  140. */
  141. public String getSignature() {
  142. int index = iterator.u16bitAt(currentPos + 1);
  143. return getConstPool().getFieldrefType(index);
  144. }
  145. /**
  146. * Replaces the method call with the bytecode derived from
  147. * the given source text.
  148. *
  149. * <p>$0 is available even if the called method is static.
  150. * If the field access is writing, $_ is available but the value
  151. * of $_ is ignored.
  152. *
  153. * @param statement a Java statement except try-catch.
  154. */
  155. @Override
  156. public void replace(String statement) throws CannotCompileException {
  157. thisClass.getClassFile(); // to call checkModify().
  158. ConstPool constPool = getConstPool();
  159. int pos = currentPos;
  160. int index = iterator.u16bitAt(pos + 1);
  161. Javac jc = new Javac(thisClass);
  162. CodeAttribute ca = iterator.get();
  163. try {
  164. CtClass[] params;
  165. CtClass retType;
  166. CtClass fieldType
  167. = Descriptor.toCtClass(constPool.getFieldrefType(index),
  168. thisClass.getClassPool());
  169. boolean read = isReader();
  170. if (read) {
  171. params = new CtClass[0];
  172. retType = fieldType;
  173. }
  174. else {
  175. params = new CtClass[1];
  176. params[0] = fieldType;
  177. retType = CtClass.voidType;
  178. }
  179. int paramVar = ca.getMaxLocals();
  180. jc.recordParams(constPool.getFieldrefClassName(index), params,
  181. true, paramVar, withinStatic());
  182. /* Is $_ included in the source code?
  183. */
  184. boolean included = checkResultValue(retType, statement);
  185. if (read)
  186. included = true;
  187. int retVar = jc.recordReturnType(retType, included);
  188. if (read)
  189. jc.recordProceed(new ProceedForRead(retType, opcode,
  190. index, paramVar));
  191. else {
  192. // because $type is not the return type...
  193. jc.recordType(fieldType);
  194. jc.recordProceed(new ProceedForWrite(params[0], opcode,
  195. index, paramVar));
  196. }
  197. Bytecode bytecode = jc.getBytecode();
  198. storeStack(params, isStatic(), paramVar, bytecode);
  199. jc.recordLocalVariables(ca, pos);
  200. if (included)
  201. if (retType == CtClass.voidType) {
  202. bytecode.addOpcode(ACONST_NULL);
  203. bytecode.addAstore(retVar);
  204. }
  205. else {
  206. bytecode.addConstZero(retType);
  207. bytecode.addStore(retVar, retType); // initialize $_
  208. }
  209. jc.compileStmnt(statement);
  210. if (read)
  211. bytecode.addLoad(retVar, retType);
  212. replace0(pos, bytecode, 3);
  213. }
  214. catch (CompileError e) { throw new CannotCompileException(e); }
  215. catch (NotFoundException e) { throw new CannotCompileException(e); }
  216. catch (BadBytecode e) {
  217. throw new CannotCompileException("broken method");
  218. }
  219. }
  220. /* <field type> $proceed()
  221. */
  222. static class ProceedForRead implements ProceedHandler {
  223. CtClass fieldType;
  224. int opcode;
  225. int targetVar, index;
  226. ProceedForRead(CtClass type, int op, int i, int var) {
  227. fieldType = type;
  228. targetVar = var;
  229. opcode = op;
  230. index = i;
  231. }
  232. @Override
  233. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
  234. throws CompileError
  235. {
  236. if (args != null && !gen.isParamListName(args))
  237. throw new CompileError(Javac.proceedName
  238. + "() cannot take a parameter for field reading", lineNumber);
  239. int stack;
  240. if (isStatic(opcode))
  241. stack = 0;
  242. else {
  243. stack = -1;
  244. bytecode.addAload(targetVar);
  245. }
  246. if (fieldType instanceof CtPrimitiveType)
  247. stack += ((CtPrimitiveType)fieldType).getDataSize();
  248. else
  249. ++stack;
  250. bytecode.add(opcode);
  251. bytecode.addIndex(index);
  252. bytecode.growStack(stack);
  253. gen.setType(fieldType, lineNumber);
  254. }
  255. @Override
  256. public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
  257. throws CompileError
  258. {
  259. c.setType(fieldType, lineNumber);
  260. }
  261. }
  262. /* void $proceed(<field type>)
  263. * the return type is not the field type but void.
  264. */
  265. static class ProceedForWrite implements ProceedHandler {
  266. CtClass fieldType;
  267. int opcode;
  268. int targetVar, index;
  269. ProceedForWrite(CtClass type, int op, int i, int var) {
  270. fieldType = type;
  271. targetVar = var;
  272. opcode = op;
  273. index = i;
  274. }
  275. @Override
  276. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
  277. throws CompileError
  278. {
  279. if (gen.getMethodArgsLength(args) != 1)
  280. throw new CompileError(Javac.proceedName
  281. + "() cannot take more than one parameter "
  282. + "for field writing", lineNumber);
  283. int stack;
  284. if (isStatic(opcode))
  285. stack = 0;
  286. else {
  287. stack = -1;
  288. bytecode.addAload(targetVar);
  289. }
  290. gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
  291. gen.doNumCast(fieldType);
  292. if (fieldType instanceof CtPrimitiveType)
  293. stack -= ((CtPrimitiveType)fieldType).getDataSize();
  294. else
  295. --stack;
  296. bytecode.add(opcode);
  297. bytecode.addIndex(index);
  298. bytecode.growStack(stack);
  299. gen.setType(CtClass.voidType, lineNumber);
  300. gen.addNullIfVoid();
  301. }
  302. @Override
  303. public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
  304. throws CompileError
  305. {
  306. c.atMethodArgs(args, new int[1], new int[1], new String[1]);
  307. c.setType(CtClass.voidType, lineNumber);
  308. c.addNullIfVoid();
  309. }
  310. }
  311. }