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