001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.expr;
017:
018: import javassist.*;
019: import javassist.bytecode.*;
020: import javassist.compiler.*;
021: import javassist.compiler.ast.ASTList;
022:
023: /**
024: * Array creation.
025: *
026: * <p>This class does not provide methods for obtaining the initial
027: * values of array elements.
028: */
029: public class NewArray extends Expr {
030: int opcode;
031:
032: protected NewArray(int pos, CodeIterator i, CtClass declaring,
033: MethodInfo m, int op) {
034: super (pos, i, declaring, m);
035: opcode = op;
036: }
037:
038: /**
039: * Returns the method or constructor containing the array creation
040: * represented by this object.
041: */
042: public CtBehavior where() {
043: return super .where();
044: }
045:
046: /**
047: * Returns the line number of the source line containing the
048: * array creation.
049: *
050: * @return -1 if this information is not available.
051: */
052: public int getLineNumber() {
053: return super .getLineNumber();
054: }
055:
056: /**
057: * Returns the source file containing the array creation.
058: *
059: * @return null if this information is not available.
060: */
061: public String getFileName() {
062: return super .getFileName();
063: }
064:
065: /**
066: * Returns the list of exceptions that the expression may throw.
067: * This list includes both the exceptions that the try-catch statements
068: * including the expression can catch and the exceptions that
069: * the throws declaration allows the method to throw.
070: */
071: public CtClass[] mayThrow() {
072: return super .mayThrow();
073: }
074:
075: /**
076: * Returns the type of array components. If the created array is
077: * a two-dimensional array of <tt>int</tt>,
078: * the type returned by this method is
079: * not <tt>int[]</tt> but <tt>int</tt>.
080: */
081: public CtClass getComponentType() throws NotFoundException {
082: if (opcode == Opcode.NEWARRAY) {
083: int atype = iterator.byteAt(currentPos + 1);
084: return getPrimitiveType(atype);
085: } else if (opcode == Opcode.ANEWARRAY
086: || opcode == Opcode.MULTIANEWARRAY) {
087: int index = iterator.u16bitAt(currentPos + 1);
088: String desc = getConstPool().getClassInfo(index);
089: int dim = Descriptor.arrayDimension(desc);
090: desc = Descriptor.toArrayComponent(desc, dim);
091: return Descriptor.toCtClass(desc, this Class.getClassPool());
092: } else
093: throw new RuntimeException("bad opcode: " + opcode);
094: }
095:
096: CtClass getPrimitiveType(int atype) {
097: switch (atype) {
098: case Opcode.T_BOOLEAN:
099: 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: */
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: } else
132: throw new RuntimeException("bad opcode: " + opcode);
133: }
134:
135: /**
136: * Returns the number of dimensions of arrays to be created.
137: * If the opcode is multianewarray, this method returns the second
138: * operand. Otherwise, it returns 1.
139: */
140: public int getCreatedDimensions() {
141: if (opcode == Opcode.MULTIANEWARRAY)
142: return iterator.byteAt(currentPos + 3);
143: else
144: return 1;
145: }
146:
147: /**
148: * Replaces the array creation with the bytecode derived from
149: * the given source text.
150: *
151: * <p>$0 is available even if the called method is static.
152: * If the field access is writing, $_ is available but the value
153: * of $_ is ignored.
154: *
155: * @param statement a Java statement.
156: */
157: public void replace(String statement) throws CannotCompileException {
158: try {
159: replace2(statement);
160: } catch (CompileError e) {
161: throw new CannotCompileException(e);
162: } catch (NotFoundException e) {
163: throw new CannotCompileException(e);
164: } catch (BadBytecode e) {
165: throw new CannotCompileException("broken method");
166: }
167: }
168:
169: private void replace2(String statement) throws CompileError,
170: NotFoundException, BadBytecode, CannotCompileException {
171: ConstPool constPool = getConstPool();
172: int pos = currentPos;
173: CtClass retType;
174: int codeLength;
175: int index = 0;
176: int dim = 1;
177: String desc;
178: if (opcode == Opcode.NEWARRAY) {
179: index = iterator.byteAt(currentPos + 1); // atype
180: CtPrimitiveType cpt = (CtPrimitiveType) getPrimitiveType(index);
181: desc = "[" + cpt.getDescriptor();
182: codeLength = 2;
183: } else if (opcode == Opcode.ANEWARRAY) {
184: index = iterator.u16bitAt(pos + 1);
185: desc = constPool.getClassInfo(index);
186: if (desc.startsWith("["))
187: desc = "[" + desc;
188: else
189: desc = "[L" + desc + ";";
190:
191: codeLength = 3;
192: } else if (opcode == Opcode.MULTIANEWARRAY) {
193: index = iterator.u16bitAt(currentPos + 1);
194: desc = constPool.getClassInfo(index);
195: dim = iterator.byteAt(currentPos + 3);
196: codeLength = 4;
197: } else
198: throw new RuntimeException("bad opcode: " + opcode);
199:
200: retType = Descriptor.toCtClass(desc, this Class.getClassPool());
201:
202: Javac jc = new Javac(this Class);
203: CodeAttribute ca = iterator.get();
204:
205: CtClass[] params = new CtClass[dim];
206: for (int i = 0; i < dim; ++i)
207: params[i] = CtClass.intType;
208:
209: int paramVar = ca.getMaxLocals();
210: jc.recordParams(javaLangObject, params, true, paramVar,
211: withinStatic());
212:
213: /* Is $_ included in the source code?
214: */
215: checkResultValue(retType, statement);
216: int retVar = jc.recordReturnType(retType, true);
217: jc.recordProceed(new ProceedForArray(retType, opcode, index,
218: dim));
219:
220: Bytecode bytecode = jc.getBytecode();
221: storeStack(params, true, paramVar, bytecode);
222: jc.recordLocalVariables(ca, pos);
223:
224: bytecode.addOpcode(ACONST_NULL); // initialize $_
225: bytecode.addAstore(retVar);
226:
227: jc.compileStmnt(statement);
228: bytecode.addAload(retVar);
229:
230: replace0(pos, bytecode, codeLength);
231: }
232:
233: /* <array type> $proceed(<dim> ..)
234: */
235: static class ProceedForArray implements ProceedHandler {
236: CtClass arrayType;
237: int opcode;
238: int index, dimension;
239:
240: ProceedForArray(CtClass type, int op, int i, int dim) {
241: arrayType = type;
242: opcode = op;
243: index = i;
244: dimension = dim;
245: }
246:
247: public void doit(JvstCodeGen gen, Bytecode bytecode,
248: ASTList args) throws CompileError {
249: int num = gen.getMethodArgsLength(args);
250: if (num != dimension)
251: throw new CompileError(Javac.proceedName
252: + "() with a wrong number of parameters");
253:
254: gen.atMethodArgs(args, new int[num], new int[num],
255: new String[num]);
256: bytecode.addOpcode(opcode);
257: if (opcode == Opcode.ANEWARRAY)
258: bytecode.addIndex(index);
259: else if (opcode == Opcode.NEWARRAY)
260: bytecode.add(index);
261: else /* if (opcode == Opcode.MULTIANEWARRAY) */{
262: bytecode.addIndex(index);
263: bytecode.add(dimension);
264: bytecode.growStack(1 - dimension);
265: }
266:
267: gen.setType(arrayType);
268: }
269:
270: public void setReturnType(JvstTypeChecker c, ASTList args)
271: throws CompileError {
272: c.setType(arrayType);
273: }
274: }
275: }
|