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

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