Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

NewArray.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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.CtBehavior;
  19. import javassist.CtClass;
  20. import javassist.CtPrimitiveType;
  21. import javassist.NotFoundException;
  22. import javassist.bytecode.BadBytecode;
  23. import javassist.bytecode.Bytecode;
  24. import javassist.bytecode.CodeAttribute;
  25. import javassist.bytecode.CodeIterator;
  26. import javassist.bytecode.ConstPool;
  27. import javassist.bytecode.Descriptor;
  28. import javassist.bytecode.MethodInfo;
  29. import javassist.bytecode.Opcode;
  30. import javassist.compiler.CompileError;
  31. import javassist.compiler.Javac;
  32. import javassist.compiler.JvstCodeGen;
  33. import javassist.compiler.JvstTypeChecker;
  34. import javassist.compiler.ProceedHandler;
  35. import javassist.compiler.ast.ASTList;
  36. /**
  37. * Array creation.
  38. *
  39. * <p>This class does not provide methods for obtaining the initial
  40. * values of array elements.
  41. */
  42. public class NewArray extends Expr {
  43. int opcode;
  44. protected NewArray(int pos, CodeIterator i, CtClass declaring,
  45. MethodInfo m, int op) {
  46. super(pos, i, declaring, m);
  47. opcode = op;
  48. }
  49. /**
  50. * Returns the method or constructor containing the array creation
  51. * represented by this object.
  52. */
  53. @Override
  54. public CtBehavior where() { return super.where(); }
  55. /**
  56. * Returns the line number of the source line containing the
  57. * array creation.
  58. *
  59. * @return -1 if this information is not available.
  60. */
  61. @Override
  62. public int getLineNumber() {
  63. return super.getLineNumber();
  64. }
  65. /**
  66. * Returns the source file containing the array creation.
  67. *
  68. * @return null if this information is not available.
  69. */
  70. @Override
  71. public String getFileName() {
  72. return super.getFileName();
  73. }
  74. /**
  75. * Returns the list of exceptions that the expression may throw.
  76. * This list includes both the exceptions that the try-catch statements
  77. * including the expression can catch and the exceptions that
  78. * the throws declaration allows the method to throw.
  79. */
  80. @Override
  81. public CtClass[] mayThrow() {
  82. return super.mayThrow();
  83. }
  84. /**
  85. * Returns the type of array components. If the created array is
  86. * a two-dimensional array of <code>int</code>,
  87. * the type returned by this method is
  88. * not <code>int[]</code> but <code>int</code>.
  89. */
  90. public CtClass getComponentType() throws NotFoundException {
  91. if (opcode == Opcode.NEWARRAY) {
  92. int atype = iterator.byteAt(currentPos + 1);
  93. return getPrimitiveType(atype);
  94. }
  95. else if (opcode == Opcode.ANEWARRAY
  96. || opcode == Opcode.MULTIANEWARRAY) {
  97. int index = iterator.u16bitAt(currentPos + 1);
  98. String desc = getConstPool().getClassInfo(index);
  99. int dim = Descriptor.arrayDimension(desc);
  100. desc = Descriptor.toArrayComponent(desc, dim);
  101. return Descriptor.toCtClass(desc, thisClass.getClassPool());
  102. }
  103. else
  104. throw new RuntimeException("bad opcode: " + opcode);
  105. }
  106. CtClass getPrimitiveType(int atype) {
  107. switch (atype) {
  108. case Opcode.T_BOOLEAN :
  109. return CtClass.booleanType;
  110. case Opcode.T_CHAR :
  111. return CtClass.charType;
  112. case Opcode.T_FLOAT :
  113. return CtClass.floatType;
  114. case Opcode.T_DOUBLE :
  115. return CtClass.doubleType;
  116. case Opcode.T_BYTE :
  117. return CtClass.byteType;
  118. case Opcode.T_SHORT :
  119. return CtClass.shortType;
  120. case Opcode.T_INT :
  121. return CtClass.intType;
  122. case Opcode.T_LONG :
  123. return CtClass.longType;
  124. default :
  125. throw new RuntimeException("bad atype: " + atype);
  126. }
  127. }
  128. /**
  129. * Returns the dimension of the created array.
  130. */
  131. public int getDimension() {
  132. if (opcode == Opcode.NEWARRAY)
  133. return 1;
  134. else if (opcode == Opcode.ANEWARRAY
  135. || opcode == Opcode.MULTIANEWARRAY) {
  136. int index = iterator.u16bitAt(currentPos + 1);
  137. String desc = getConstPool().getClassInfo(index);
  138. return Descriptor.arrayDimension(desc)
  139. + (opcode == Opcode.ANEWARRAY ? 1 : 0);
  140. }
  141. else
  142. throw new RuntimeException("bad opcode: " + opcode);
  143. }
  144. /**
  145. * Returns the number of dimensions of arrays to be created.
  146. * If the opcode is multianewarray, this method returns the second
  147. * operand. Otherwise, it returns 1.
  148. */
  149. public int getCreatedDimensions() {
  150. if (opcode == Opcode.MULTIANEWARRAY)
  151. return iterator.byteAt(currentPos + 3);
  152. return 1;
  153. }
  154. /**
  155. * Replaces the array creation with the bytecode derived from
  156. * the given source text.
  157. *
  158. * <p>$0 is available even if the called method is static.
  159. * If the field access is writing, $_ is available but the value
  160. * of $_ is ignored.
  161. *
  162. * @param statement a Java statement except try-catch.
  163. */
  164. @Override
  165. public void replace(String statement) throws CannotCompileException {
  166. try {
  167. replace2(statement);
  168. }
  169. catch (CompileError e) { throw new CannotCompileException(e); }
  170. catch (NotFoundException e) { throw new CannotCompileException(e); }
  171. catch (BadBytecode e) {
  172. throw new CannotCompileException("broken method");
  173. }
  174. }
  175. private void replace2(String statement)
  176. throws CompileError, NotFoundException, BadBytecode,
  177. CannotCompileException
  178. {
  179. thisClass.getClassFile(); // to call checkModify().
  180. ConstPool constPool = getConstPool();
  181. int pos = currentPos;
  182. CtClass retType;
  183. int codeLength;
  184. int index = 0;
  185. int dim = 1;
  186. String desc;
  187. if (opcode == Opcode.NEWARRAY) {
  188. index = iterator.byteAt(currentPos + 1); // atype
  189. CtPrimitiveType cpt = (CtPrimitiveType)getPrimitiveType(index);
  190. desc = "[" + cpt.getDescriptor();
  191. codeLength = 2;
  192. }
  193. else if (opcode == Opcode.ANEWARRAY) {
  194. index = iterator.u16bitAt(pos + 1);
  195. desc = constPool.getClassInfo(index);
  196. if (desc.startsWith("["))
  197. desc = "[" + desc;
  198. else
  199. desc = "[L" + desc + ";";
  200. codeLength = 3;
  201. }
  202. else if (opcode == Opcode.MULTIANEWARRAY) {
  203. index = iterator.u16bitAt(currentPos + 1);
  204. desc = constPool.getClassInfo(index);
  205. dim = iterator.byteAt(currentPos + 3);
  206. codeLength = 4;
  207. }
  208. else
  209. throw new RuntimeException("bad opcode: " + opcode);
  210. retType = Descriptor.toCtClass(desc, thisClass.getClassPool());
  211. Javac jc = new Javac(thisClass);
  212. CodeAttribute ca = iterator.get();
  213. CtClass[] params = new CtClass[dim];
  214. for (int i = 0; i < dim; ++i)
  215. params[i] = CtClass.intType;
  216. int paramVar = ca.getMaxLocals();
  217. jc.recordParams(javaLangObject, params,
  218. true, paramVar, withinStatic());
  219. /* Is $_ included in the source code?
  220. */
  221. checkResultValue(retType, statement);
  222. int retVar = jc.recordReturnType(retType, true);
  223. jc.recordProceed(new ProceedForArray(retType, opcode, index, dim));
  224. Bytecode bytecode = jc.getBytecode();
  225. storeStack(params, true, paramVar, bytecode);
  226. jc.recordLocalVariables(ca, pos);
  227. bytecode.addOpcode(ACONST_NULL); // initialize $_
  228. bytecode.addAstore(retVar);
  229. jc.compileStmnt(statement);
  230. bytecode.addAload(retVar);
  231. replace0(pos, bytecode, codeLength);
  232. }
  233. /* <array type> $proceed(<dim> ..)
  234. */
  235. static class ProceedForArray implements ProceedHandler {
  236. CtClass arrayType;
  237. int opcode;
  238. int index, dimension;
  239. ProceedForArray(CtClass type, int op, int i, int dim) {
  240. arrayType = type;
  241. opcode = op;
  242. index = i;
  243. dimension = dim;
  244. }
  245. @Override
  246. public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber)
  247. throws CompileError
  248. {
  249. int num = gen.getMethodArgsLength(args);
  250. if (num != dimension)
  251. throw new CompileError(Javac.proceedName
  252. + "() with a wrong number of parameters", lineNumber);
  253. gen.atMethodArgs(args, new int[num],
  254. new int[num], new String[num]);
  255. bytecode.addOpcode(opcode);
  256. if (opcode == Opcode.ANEWARRAY)
  257. bytecode.addIndex(index);
  258. else if (opcode == Opcode.NEWARRAY)
  259. bytecode.add(index);
  260. else /* if (opcode == Opcode.MULTIANEWARRAY) */ {
  261. bytecode.addIndex(index);
  262. bytecode.add(dimension);
  263. bytecode.growStack(1 - dimension);
  264. }
  265. gen.setType(arrayType, lineNumber);
  266. }
  267. @Override
  268. public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
  269. throws CompileError
  270. {
  271. c.setType(arrayType, lineNumber);
  272. }
  273. }
  274. }