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