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.

NewExpr.java 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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.CtConstructor;
  22. import javassist.NotFoundException;
  23. import javassist.bytecode.BadBytecode;
  24. import javassist.bytecode.Bytecode;
  25. import javassist.bytecode.CodeAttribute;
  26. import javassist.bytecode.CodeIterator;
  27. import javassist.bytecode.ConstPool;
  28. import javassist.bytecode.Descriptor;
  29. import javassist.bytecode.MethodInfo;
  30. import javassist.bytecode.Opcode;
  31. import javassist.compiler.CompileError;
  32. import javassist.compiler.Javac;
  33. import javassist.compiler.JvstCodeGen;
  34. import javassist.compiler.JvstTypeChecker;
  35. import javassist.compiler.ProceedHandler;
  36. import javassist.compiler.ast.ASTList;
  37. /**
  38. * Object creation (<code>new</code> expression).
  39. */
  40. public class NewExpr extends Expr {
  41. String newTypeName;
  42. int newPos;
  43. /**
  44. * Undocumented constructor. Do not use; internal-use only.
  45. */
  46. protected NewExpr(int pos, CodeIterator i, CtClass declaring,
  47. MethodInfo m, String type, int np) {
  48. super(pos, i, declaring, m);
  49. newTypeName = type;
  50. newPos = np;
  51. }
  52. /*
  53. * Not used
  54. *
  55. private int getNameAndType(ConstPool cp) {
  56. int pos = currentPos;
  57. int c = iterator.byteAt(pos);
  58. int index = iterator.u16bitAt(pos + 1);
  59. if (c == INVOKEINTERFACE)
  60. return cp.getInterfaceMethodrefNameAndType(index);
  61. else
  62. return cp.getMethodrefNameAndType(index);
  63. } */
  64. /**
  65. * Returns the method or constructor containing the <code>new</code>
  66. * expression represented by this object.
  67. */
  68. @Override
  69. public CtBehavior where() { return super.where(); }
  70. /**
  71. * Returns the line number of the source line containing the
  72. * <code>new</code> expression.
  73. *
  74. * @return -1 if this information is not available.
  75. */
  76. @Override
  77. public int getLineNumber() {
  78. return super.getLineNumber();
  79. }
  80. /**
  81. * Returns the source file containing the <code>new</code> expression.
  82. *
  83. * @return null if this information is not available.
  84. */
  85. @Override
  86. public String getFileName() {
  87. return super.getFileName();
  88. }
  89. /**
  90. * Returns the class of the created object.
  91. */
  92. private CtClass getCtClass() throws NotFoundException {
  93. return thisClass.getClassPool().get(newTypeName);
  94. }
  95. /**
  96. * Returns the class name of the created object.
  97. */
  98. public String getClassName() {
  99. return newTypeName;
  100. }
  101. /**
  102. * Get the signature of the constructor
  103. *
  104. * The signature is represented by a character string
  105. * called method descriptor, which is defined in the JVM specification.
  106. *
  107. * @see javassist.CtBehavior#getSignature()
  108. * @see javassist.bytecode.Descriptor
  109. * @return the signature
  110. */
  111. public String getSignature() {
  112. ConstPool constPool = getConstPool();
  113. int methodIndex = iterator.u16bitAt(currentPos + 1); // constructor
  114. return constPool.getMethodrefType(methodIndex);
  115. }
  116. /**
  117. * Returns the constructor called for creating the object.
  118. */
  119. public CtConstructor getConstructor() throws NotFoundException {
  120. ConstPool cp = getConstPool();
  121. int index = iterator.u16bitAt(currentPos + 1);
  122. String desc = cp.getMethodrefType(index);
  123. return getCtClass().getConstructor(desc);
  124. }
  125. /**
  126. * Returns the list of exceptions that the expression may throw.
  127. * This list includes both the exceptions that the try-catch statements
  128. * including the expression can catch and the exceptions that
  129. * the throws declaration allows the method to throw.
  130. */
  131. @Override
  132. public CtClass[] mayThrow() {
  133. return super.mayThrow();
  134. }
  135. /*
  136. * Returns the parameter types of the constructor.
  137. public CtClass[] getParameterTypes() throws NotFoundException {
  138. ConstPool cp = getConstPool();
  139. int index = iterator.u16bitAt(currentPos + 1);
  140. String desc = cp.getMethodrefType(index);
  141. return Descriptor.getParameterTypes(desc, thisClass.getClassPool());
  142. }
  143. */
  144. private int canReplace() throws CannotCompileException {
  145. int op = iterator.byteAt(newPos + 3);
  146. if (op == Opcode.DUP) // Typical single DUP or Javaflow DUP DUP2_X2 POP2
  147. return ((iterator.byteAt(newPos + 4) == Opcode.DUP2_X2
  148. && iterator.byteAt(newPos + 5) == Opcode.POP2)) ? 6 : 4;
  149. else if (op == Opcode.DUP_X1
  150. && iterator.byteAt(newPos + 4) == Opcode.SWAP)
  151. return 5;
  152. else
  153. return 3; // for Eclipse. The generated code may include no DUP.
  154. // throw new CannotCompileException(
  155. // "sorry, cannot edit NEW followed by no DUP");
  156. }
  157. /**
  158. * Replaces the <code>new</code> expression with the bytecode derived from
  159. * the given source text.
  160. *
  161. * <p>$0 is available but the value is null.
  162. *
  163. * @param statement a Java statement except try-catch.
  164. */
  165. @Override
  166. public void replace(String statement) throws CannotCompileException {
  167. thisClass.getClassFile(); // to call checkModify().
  168. final int bytecodeSize = 3;
  169. int pos = newPos;
  170. int newIndex = iterator.u16bitAt(pos + 1);
  171. /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions.
  172. */
  173. int codeSize = canReplace();
  174. int end = pos + codeSize;
  175. //check isStoreBeforeInit ,such as : new xx/xx ; dup;[astoreN];invokespecial xx/xx;
  176. int beforeStoreOp = 0;
  177. int preOp = iterator.byteAt(currentPos - 1);
  178. if (iterator.byteAt(newPos + 3) == Opcode.DUP
  179. && (preOp >= Opcode.ASTORE_0
  180. && preOp <= Opcode.ASTORE_3) && currentPos - newPos == 5) {
  181. beforeStoreOp = preOp;
  182. }
  183. for (int i = pos; i < end; ++i)
  184. iterator.writeByte(NOP, i);
  185. ConstPool constPool = getConstPool();
  186. pos = currentPos;
  187. int methodIndex = iterator.u16bitAt(pos + 1); // constructor
  188. String signature = constPool.getMethodrefType(methodIndex);
  189. Javac jc = new Javac(thisClass);
  190. ClassPool cp = thisClass.getClassPool();
  191. CodeAttribute ca = iterator.get();
  192. try {
  193. CtClass[] params = Descriptor.getParameterTypes(signature, cp);
  194. CtClass newType = cp.get(newTypeName);
  195. int paramVar = ca.getMaxLocals();
  196. jc.recordParams(newTypeName, params,
  197. true, paramVar, withinStatic());
  198. int retVar = jc.recordReturnType(newType, true);
  199. jc.recordProceed(new ProceedForNew(newType, newIndex,
  200. methodIndex));
  201. /* Is $_ included in the source code?
  202. */
  203. checkResultValue(newType, statement);
  204. Bytecode bytecode = jc.getBytecode();
  205. storeStack(params, true, paramVar, bytecode);
  206. jc.recordLocalVariables(ca, pos);
  207. bytecode.addConstZero(newType);
  208. bytecode.addStore(retVar, newType); // initialize $_
  209. jc.compileStmnt(statement);
  210. if (codeSize > 3) // if the original code includes DUP.
  211. bytecode.addAload(retVar);
  212. if (beforeStoreOp >= Opcode.ASTORE_0) {
  213. bytecode.addOpcode(beforeStoreOp);
  214. replace0(pos - 1, bytecode, bytecodeSize + 1);
  215. } else {
  216. replace0(pos, bytecode, bytecodeSize);
  217. }
  218. }
  219. catch (CompileError e) { throw new CannotCompileException(e); }
  220. catch (NotFoundException e) { throw new CannotCompileException(e); }
  221. catch (BadBytecode e) {
  222. throw new CannotCompileException("broken method");
  223. }
  224. }
  225. static class ProceedForNew implements ProceedHandler {
  226. CtClass newType;
  227. int newIndex, methodIndex;
  228. ProceedForNew(CtClass nt, int ni, int mi) {
  229. newType = nt;
  230. newIndex = ni;
  231. methodIndex = mi;
  232. }
  233. @Override
  234. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
  235. throws CompileError
  236. {
  237. bytecode.addOpcode(NEW);
  238. bytecode.addIndex(newIndex);
  239. bytecode.addOpcode(DUP);
  240. gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
  241. false, true, -1, null);
  242. gen.setType(newType);
  243. }
  244. @Override
  245. public void setReturnType(JvstTypeChecker c, ASTList args)
  246. throws CompileError
  247. {
  248. c.atMethodCallCore(newType, MethodInfo.nameInit, args);
  249. c.setType(newType);
  250. }
  251. }
  252. }