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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. //return cc.getField(getFieldName());
  103. }
  104. /**
  105. * Returns the list of exceptions that the expression may throw.
  106. * This list includes both the exceptions that the try-catch statements
  107. * including the expression can catch and the exceptions that
  108. * the throws declaration allows the method to throw.
  109. */
  110. public CtClass[] mayThrow() {
  111. return super.mayThrow();
  112. }
  113. /**
  114. * Returns the signature of the field type.
  115. * The signature is represented by a character string
  116. * called field descriptor, which is defined in the JVM specification.
  117. *
  118. * @see javassist.bytecode.Descriptor#toCtClass(String, ClassPool)
  119. * @since 3.1
  120. */
  121. public String getSignature() {
  122. int index = iterator.u16bitAt(currentPos + 1);
  123. return getConstPool().getFieldrefType(index);
  124. }
  125. /**
  126. * Replaces the method call with the bytecode derived from
  127. * the given source text.
  128. *
  129. * <p>$0 is available even if the called method is static.
  130. * If the field access is writing, $_ is available but the value
  131. * of $_ is ignored.
  132. *
  133. * @param statement a Java statement except try-catch.
  134. */
  135. public void replace(String statement) throws CannotCompileException {
  136. thisClass.getClassFile(); // to call checkModify().
  137. ConstPool constPool = getConstPool();
  138. int pos = currentPos;
  139. int index = iterator.u16bitAt(pos + 1);
  140. Javac jc = new Javac(thisClass);
  141. CodeAttribute ca = iterator.get();
  142. try {
  143. CtClass[] params;
  144. CtClass retType;
  145. CtClass fieldType
  146. = Descriptor.toCtClass(constPool.getFieldrefType(index),
  147. thisClass.getClassPool());
  148. boolean read = isReader();
  149. if (read) {
  150. params = new CtClass[0];
  151. retType = fieldType;
  152. }
  153. else {
  154. params = new CtClass[1];
  155. params[0] = fieldType;
  156. retType = CtClass.voidType;
  157. }
  158. int paramVar = ca.getMaxLocals();
  159. jc.recordParams(constPool.getFieldrefClassName(index), params,
  160. true, paramVar, withinStatic());
  161. /* Is $_ included in the source code?
  162. */
  163. boolean included = checkResultValue(retType, statement);
  164. if (read)
  165. included = true;
  166. int retVar = jc.recordReturnType(retType, included);
  167. if (read)
  168. jc.recordProceed(new ProceedForRead(retType, opcode,
  169. index, paramVar));
  170. else {
  171. // because $type is not the return type...
  172. jc.recordType(fieldType);
  173. jc.recordProceed(new ProceedForWrite(params[0], opcode,
  174. index, paramVar));
  175. }
  176. Bytecode bytecode = jc.getBytecode();
  177. storeStack(params, isStatic(), paramVar, bytecode);
  178. jc.recordLocalVariables(ca, pos);
  179. if (included)
  180. if (retType == CtClass.voidType) {
  181. bytecode.addOpcode(ACONST_NULL);
  182. bytecode.addAstore(retVar);
  183. }
  184. else {
  185. bytecode.addConstZero(retType);
  186. bytecode.addStore(retVar, retType); // initialize $_
  187. }
  188. jc.compileStmnt(statement);
  189. if (read)
  190. bytecode.addLoad(retVar, retType);
  191. replace0(pos, bytecode, 3);
  192. }
  193. catch (CompileError e) { throw new CannotCompileException(e); }
  194. catch (NotFoundException e) { throw new CannotCompileException(e); }
  195. catch (BadBytecode e) {
  196. throw new CannotCompileException("broken method");
  197. }
  198. }
  199. /* <field type> $proceed()
  200. */
  201. static class ProceedForRead implements ProceedHandler {
  202. CtClass fieldType;
  203. int opcode;
  204. int targetVar, index;
  205. ProceedForRead(CtClass type, int op, int i, int var) {
  206. fieldType = type;
  207. targetVar = var;
  208. opcode = op;
  209. index = i;
  210. }
  211. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
  212. throws CompileError
  213. {
  214. if (args != null && !gen.isParamListName(args))
  215. throw new CompileError(Javac.proceedName
  216. + "() cannot take a parameter for field reading");
  217. int stack;
  218. if (isStatic(opcode))
  219. stack = 0;
  220. else {
  221. stack = -1;
  222. bytecode.addAload(targetVar);
  223. }
  224. if (fieldType instanceof CtPrimitiveType)
  225. stack += ((CtPrimitiveType)fieldType).getDataSize();
  226. else
  227. ++stack;
  228. bytecode.add(opcode);
  229. bytecode.addIndex(index);
  230. bytecode.growStack(stack);
  231. gen.setType(fieldType);
  232. }
  233. public void setReturnType(JvstTypeChecker c, ASTList args)
  234. throws CompileError
  235. {
  236. c.setType(fieldType);
  237. }
  238. }
  239. /* void $proceed(<field type>)
  240. * the return type is not the field type but void.
  241. */
  242. static class ProceedForWrite implements ProceedHandler {
  243. CtClass fieldType;
  244. int opcode;
  245. int targetVar, index;
  246. ProceedForWrite(CtClass type, int op, int i, int var) {
  247. fieldType = type;
  248. targetVar = var;
  249. opcode = op;
  250. index = i;
  251. }
  252. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
  253. throws CompileError
  254. {
  255. if (gen.getMethodArgsLength(args) != 1)
  256. throw new CompileError(Javac.proceedName
  257. + "() cannot take more than one parameter "
  258. + "for field writing");
  259. int stack;
  260. if (isStatic(opcode))
  261. stack = 0;
  262. else {
  263. stack = -1;
  264. bytecode.addAload(targetVar);
  265. }
  266. gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
  267. gen.doNumCast(fieldType);
  268. if (fieldType instanceof CtPrimitiveType)
  269. stack -= ((CtPrimitiveType)fieldType).getDataSize();
  270. else
  271. --stack;
  272. bytecode.add(opcode);
  273. bytecode.addIndex(index);
  274. bytecode.growStack(stack);
  275. gen.setType(CtClass.voidType);
  276. gen.addNullIfVoid();
  277. }
  278. public void setReturnType(JvstTypeChecker c, ASTList args)
  279. throws CompileError
  280. {
  281. c.atMethodArgs(args, new int[1], new int[1], new String[1]);
  282. c.setType(CtClass.voidType);
  283. c.addNullIfVoid();
  284. }
  285. }
  286. }