Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2007 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.CannotCompileException;
  17. import javassist.ClassPool;
  18. import javassist.CtBehavior;
  19. import javassist.CtClass;
  20. import javassist.CtConstructor;
  21. import javassist.CtPrimitiveType;
  22. import javassist.NotFoundException;
  23. import javassist.bytecode.AccessFlag;
  24. import javassist.bytecode.BadBytecode;
  25. import javassist.bytecode.Bytecode;
  26. import javassist.bytecode.ClassFile;
  27. import javassist.bytecode.CodeAttribute;
  28. import javassist.bytecode.CodeIterator;
  29. import javassist.bytecode.ConstPool;
  30. import javassist.bytecode.ExceptionTable;
  31. import javassist.bytecode.ExceptionsAttribute;
  32. import javassist.bytecode.MethodInfo;
  33. import javassist.bytecode.Opcode;
  34. import javassist.compiler.Javac;
  35. import java.util.Iterator;
  36. import java.util.LinkedList;
  37. /**
  38. * Expression.
  39. */
  40. public abstract class Expr implements Opcode {
  41. int currentPos;
  42. CodeIterator iterator;
  43. CtClass thisClass;
  44. MethodInfo thisMethod;
  45. boolean edited;
  46. int maxLocals, maxStack;
  47. static final String javaLangObject = "java.lang.Object";
  48. /**
  49. * Undocumented constructor. Do not use; internal-use only.
  50. */
  51. protected Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m) {
  52. currentPos = pos;
  53. iterator = i;
  54. thisClass = declaring;
  55. thisMethod = m;
  56. }
  57. /**
  58. * Returns the class that declares the method enclosing
  59. * this expression.
  60. *
  61. * @since 3.7
  62. */
  63. public CtClass getEnclosingClass() { return thisClass; }
  64. protected final ConstPool getConstPool() {
  65. return thisMethod.getConstPool();
  66. }
  67. protected final boolean edited() {
  68. return edited;
  69. }
  70. protected final int locals() {
  71. return maxLocals;
  72. }
  73. protected final int stack() {
  74. return maxStack;
  75. }
  76. /**
  77. * Returns true if this method is static.
  78. */
  79. protected final boolean withinStatic() {
  80. return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0;
  81. }
  82. /**
  83. * Returns the constructor or method containing the expression.
  84. */
  85. public CtBehavior where() {
  86. MethodInfo mi = thisMethod;
  87. CtBehavior[] cb = thisClass.getDeclaredBehaviors();
  88. for (int i = cb.length - 1; i >= 0; --i)
  89. if (cb[i].getMethodInfo2() == mi)
  90. return cb[i];
  91. CtConstructor init = thisClass.getClassInitializer();
  92. if (init != null && init.getMethodInfo2() == mi)
  93. return init;
  94. /* getDeclaredBehaviors() returns a list of methods/constructors.
  95. * Although the list is cached in a CtClass object, it might be
  96. * recreated for some reason. Thus, the member name and the signature
  97. * must be also checked.
  98. */
  99. for (int i = cb.length - 1; i >= 0; --i) {
  100. if (thisMethod.getName().equals(cb[i].getMethodInfo2().getName())
  101. && thisMethod.getDescriptor()
  102. .equals(cb[i].getMethodInfo2().getDescriptor())) {
  103. return cb[i];
  104. }
  105. }
  106. throw new RuntimeException("fatal: not found");
  107. }
  108. /**
  109. * Returns the list of exceptions that the expression may throw. This list
  110. * includes both the exceptions that the try-catch statements including the
  111. * expression can catch and the exceptions that the throws declaration
  112. * allows the method to throw.
  113. */
  114. public CtClass[] mayThrow() {
  115. ClassPool pool = thisClass.getClassPool();
  116. ConstPool cp = thisMethod.getConstPool();
  117. LinkedList list = new LinkedList();
  118. try {
  119. CodeAttribute ca = thisMethod.getCodeAttribute();
  120. ExceptionTable et = ca.getExceptionTable();
  121. int pos = currentPos;
  122. int n = et.size();
  123. for (int i = 0; i < n; ++i)
  124. if (et.startPc(i) <= pos && pos < et.endPc(i)) {
  125. int t = et.catchType(i);
  126. if (t > 0)
  127. try {
  128. addClass(list, pool.get(cp.getClassInfo(t)));
  129. }
  130. catch (NotFoundException e) {
  131. }
  132. }
  133. }
  134. catch (NullPointerException e) {
  135. }
  136. ExceptionsAttribute ea = thisMethod.getExceptionsAttribute();
  137. if (ea != null) {
  138. String[] exceptions = ea.getExceptions();
  139. if (exceptions != null) {
  140. int n = exceptions.length;
  141. for (int i = 0; i < n; ++i)
  142. try {
  143. addClass(list, pool.get(exceptions[i]));
  144. }
  145. catch (NotFoundException e) {
  146. }
  147. }
  148. }
  149. return (CtClass[])list.toArray(new CtClass[list.size()]);
  150. }
  151. private static void addClass(LinkedList list, CtClass c) {
  152. Iterator it = list.iterator();
  153. while (it.hasNext())
  154. if (it.next() == c)
  155. return;
  156. list.add(c);
  157. }
  158. /**
  159. * Returns the index of the bytecode corresponding to the expression. It is
  160. * the index into the byte array containing the Java bytecode that
  161. * implements the method.
  162. */
  163. public int indexOfBytecode() {
  164. return currentPos;
  165. }
  166. /**
  167. * Returns the line number of the source line containing the expression.
  168. *
  169. * @return -1 if this information is not available.
  170. */
  171. public int getLineNumber() {
  172. return thisMethod.getLineNumber(currentPos);
  173. }
  174. /**
  175. * Returns the source file containing the expression.
  176. *
  177. * @return null if this information is not available.
  178. */
  179. public String getFileName() {
  180. ClassFile cf = thisClass.getClassFile2();
  181. if (cf == null)
  182. return null;
  183. else
  184. return cf.getSourceFile();
  185. }
  186. static final boolean checkResultValue(CtClass retType, String prog)
  187. throws CannotCompileException {
  188. /*
  189. * Is $_ included in the source code?
  190. */
  191. boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0);
  192. if (!hasIt && retType != CtClass.voidType)
  193. throw new CannotCompileException(
  194. "the resulting value is not stored in "
  195. + Javac.resultVarName);
  196. return hasIt;
  197. }
  198. /*
  199. * If isStaticCall is true, null is assigned to $0. So $0 must be declared
  200. * by calling Javac.recordParams().
  201. *
  202. * After executing this method, the current stack depth might be less than
  203. * 0.
  204. */
  205. static final void storeStack(CtClass[] params, boolean isStaticCall,
  206. int regno, Bytecode bytecode) {
  207. storeStack0(0, params.length, params, regno + 1, bytecode);
  208. if (isStaticCall)
  209. bytecode.addOpcode(ACONST_NULL);
  210. bytecode.addAstore(regno);
  211. }
  212. private static void storeStack0(int i, int n, CtClass[] params, int regno,
  213. Bytecode bytecode) {
  214. if (i >= n)
  215. return;
  216. else {
  217. CtClass c = params[i];
  218. int size;
  219. if (c instanceof CtPrimitiveType)
  220. size = ((CtPrimitiveType)c).getDataSize();
  221. else
  222. size = 1;
  223. storeStack0(i + 1, n, params, regno + size, bytecode);
  224. bytecode.addStore(regno, c);
  225. }
  226. }
  227. // The implementation of replace() should call thisClass.checkModify()
  228. // so that isModify() will return true. Otherwise, thisClass.classfile
  229. // might be released during compilation and the compiler might generate
  230. // bytecode with a wrong copy of ConstPool.
  231. /**
  232. * Replaces this expression with the bytecode derived from
  233. * the given source text.
  234. *
  235. * @param statement a Java statement.
  236. */
  237. public abstract void replace(String statement) throws CannotCompileException;
  238. /**
  239. * Replaces this expression with the bytecode derived from
  240. * the given source text and <code>ExprEditor</code>.
  241. *
  242. * @param statement a Java statement.
  243. * @param recursive if not null, the substituted bytecode
  244. * is recursively processed by the given
  245. * <code>ExprEditor</code>.
  246. * @since 3.1
  247. */
  248. public void replace(String statement, ExprEditor recursive)
  249. throws CannotCompileException
  250. {
  251. replace(statement);
  252. if (recursive != null)
  253. runEditor(recursive, iterator);
  254. }
  255. protected void replace0(int pos, Bytecode bytecode, int size)
  256. throws BadBytecode {
  257. byte[] code = bytecode.get();
  258. edited = true;
  259. int gap = code.length - size;
  260. for (int i = 0; i < size; ++i)
  261. iterator.writeByte(NOP, pos + i);
  262. if (gap > 0)
  263. iterator.insertGap(pos, gap);
  264. iterator.write(code, pos);
  265. iterator.insert(bytecode.getExceptionTable(), pos);
  266. maxLocals = bytecode.getMaxLocals();
  267. maxStack = bytecode.getMaxStack();
  268. }
  269. protected void runEditor(ExprEditor ed, CodeIterator oldIterator)
  270. throws CannotCompileException
  271. {
  272. CodeAttribute codeAttr = oldIterator.get();
  273. int orgLocals = codeAttr.getMaxLocals();
  274. int orgStack = codeAttr.getMaxStack();
  275. int newLocals = locals();
  276. codeAttr.setMaxStack(stack());
  277. codeAttr.setMaxLocals(newLocals);
  278. ExprEditor.LoopContext context
  279. = new ExprEditor.LoopContext(newLocals);
  280. int size = oldIterator.getCodeLength();
  281. int endPos = oldIterator.lookAhead();
  282. oldIterator.move(currentPos);
  283. if (ed.doit(thisClass, thisMethod, context, oldIterator, endPos))
  284. edited = true;
  285. oldIterator.move(endPos + oldIterator.getCodeLength() - size);
  286. codeAttr.setMaxLocals(orgLocals);
  287. codeAttr.setMaxStack(orgStack);
  288. maxLocals = context.maxLocals;
  289. maxStack += context.maxStack;
  290. }
  291. }