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

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