/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later, * or the Apache License Version 2.0. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */ package javassist.expr; import javassist.CannotCompileException; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtPrimitiveType; import javassist.NotFoundException; import javassist.bytecode.BadBytecode; import javassist.bytecode.Bytecode; import javassist.bytecode.CodeAttribute; import javassist.bytecode.CodeIterator; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.MethodInfo; import javassist.bytecode.Opcode; import javassist.compiler.CompileError; import javassist.compiler.Javac; import javassist.compiler.JvstCodeGen; import javassist.compiler.JvstTypeChecker; import javassist.compiler.ProceedHandler; import javassist.compiler.ast.ASTList; /** * Array creation. * *
This class does not provide methods for obtaining the initial
* values of array elements.
*/
public class NewArray extends Expr {
int opcode;
protected NewArray(int pos, CodeIterator i, CtClass declaring,
MethodInfo m, int op) {
super(pos, i, declaring, m);
opcode = op;
}
/**
* Returns the method or constructor containing the array creation
* represented by this object.
*/
@Override
public CtBehavior where() { return super.where(); }
/**
* Returns the line number of the source line containing the
* array creation.
*
* @return -1 if this information is not available.
*/
@Override
public int getLineNumber() {
return super.getLineNumber();
}
/**
* Returns the source file containing the array creation.
*
* @return null if this information is not available.
*/
@Override
public String getFileName() {
return super.getFileName();
}
/**
* Returns the list of exceptions that the expression may throw.
* This list includes both the exceptions that the try-catch statements
* including the expression can catch and the exceptions that
* the throws declaration allows the method to throw.
*/
@Override
public CtClass[] mayThrow() {
return super.mayThrow();
}
/**
* Returns the type of array components. If the created array is
* a two-dimensional array of int
,
* the type returned by this method is
* not int[]
but int
.
*/
public CtClass getComponentType() throws NotFoundException {
if (opcode == Opcode.NEWARRAY) {
int atype = iterator.byteAt(currentPos + 1);
return getPrimitiveType(atype);
}
else if (opcode == Opcode.ANEWARRAY
|| opcode == Opcode.MULTIANEWARRAY) {
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
int dim = Descriptor.arrayDimension(desc);
desc = Descriptor.toArrayComponent(desc, dim);
return Descriptor.toCtClass(desc, thisClass.getClassPool());
}
else
throw new RuntimeException("bad opcode: " + opcode);
}
CtClass getPrimitiveType(int atype) {
switch (atype) {
case Opcode.T_BOOLEAN :
return CtClass.booleanType;
case Opcode.T_CHAR :
return CtClass.charType;
case Opcode.T_FLOAT :
return CtClass.floatType;
case Opcode.T_DOUBLE :
return CtClass.doubleType;
case Opcode.T_BYTE :
return CtClass.byteType;
case Opcode.T_SHORT :
return CtClass.shortType;
case Opcode.T_INT :
return CtClass.intType;
case Opcode.T_LONG :
return CtClass.longType;
default :
throw new RuntimeException("bad atype: " + atype);
}
}
/**
* Returns the dimension of the created array.
*/
public int getDimension() {
if (opcode == Opcode.NEWARRAY)
return 1;
else if (opcode == Opcode.ANEWARRAY
|| opcode == Opcode.MULTIANEWARRAY) {
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
return Descriptor.arrayDimension(desc)
+ (opcode == Opcode.ANEWARRAY ? 1 : 0);
}
else
throw new RuntimeException("bad opcode: " + opcode);
}
/**
* Returns the number of dimensions of arrays to be created.
* If the opcode is multianewarray, this method returns the second
* operand. Otherwise, it returns 1.
*/
public int getCreatedDimensions() {
if (opcode == Opcode.MULTIANEWARRAY)
return iterator.byteAt(currentPos + 3);
return 1;
}
/**
* Replaces the array creation with the bytecode derived from
* the given source text.
*
*
$0 is available even if the called method is static.
* If the field access is writing, $_ is available but the value
* of $_ is ignored.
*
* @param statement a Java statement except try-catch.
*/
@Override
public void replace(String statement) throws CannotCompileException {
try {
replace2(statement);
}
catch (CompileError e) { throw new CannotCompileException(e); }
catch (NotFoundException e) { throw new CannotCompileException(e); }
catch (BadBytecode e) {
throw new CannotCompileException("broken method");
}
}
private void replace2(String statement)
throws CompileError, NotFoundException, BadBytecode,
CannotCompileException
{
thisClass.getClassFile(); // to call checkModify().
ConstPool constPool = getConstPool();
int pos = currentPos;
CtClass retType;
int codeLength;
int index = 0;
int dim = 1;
String desc;
if (opcode == Opcode.NEWARRAY) {
index = iterator.byteAt(currentPos + 1); // atype
CtPrimitiveType cpt = (CtPrimitiveType)getPrimitiveType(index);
desc = "[" + cpt.getDescriptor();
codeLength = 2;
}
else if (opcode == Opcode.ANEWARRAY) {
index = iterator.u16bitAt(pos + 1);
desc = constPool.getClassInfo(index);
if (desc.startsWith("["))
desc = "[" + desc;
else
desc = "[L" + desc + ";";
codeLength = 3;
}
else if (opcode == Opcode.MULTIANEWARRAY) {
index = iterator.u16bitAt(currentPos + 1);
desc = constPool.getClassInfo(index);
dim = iterator.byteAt(currentPos + 3);
codeLength = 4;
}
else
throw new RuntimeException("bad opcode: " + opcode);
retType = Descriptor.toCtClass(desc, thisClass.getClassPool());
Javac jc = new Javac(thisClass);
CodeAttribute ca = iterator.get();
CtClass[] params = new CtClass[dim];
for (int i = 0; i < dim; ++i)
params[i] = CtClass.intType;
int paramVar = ca.getMaxLocals();
jc.recordParams(javaLangObject, params,
true, paramVar, withinStatic());
/* Is $_ included in the source code?
*/
checkResultValue(retType, statement);
int retVar = jc.recordReturnType(retType, true);
jc.recordProceed(new ProceedForArray(retType, opcode, index, dim));
Bytecode bytecode = jc.getBytecode();
storeStack(params, true, paramVar, bytecode);
jc.recordLocalVariables(ca, pos);
bytecode.addOpcode(ACONST_NULL); // initialize $_
bytecode.addAstore(retVar);
jc.compileStmnt(statement);
bytecode.addAload(retVar);
replace0(pos, bytecode, codeLength);
}
/*