/*
 * 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.

/** * Array creation. * * <p>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.
/** * 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.
Returns:-1 if this information is not available.
/** * 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.
Returns:null if this information is not available.
/** * 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.
/** * 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.
/** * Returns the type of array components. If the created array is * a two-dimensional array of <code>int</code>, * the type returned by this method is * not <code>int[]</code> but <code>int</code>. */
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.
/** * 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.
/** * 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.

Params:
  • statement – a Java statement except try-catch.
/** * Replaces the array creation with the bytecode derived from * the given source text. * * <p>$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); } /* <array type> $proceed(<dim> ..) */ static class ProceedForArray implements ProceedHandler { CtClass arrayType; int opcode; int index, dimension; ProceedForArray(CtClass type, int op, int i, int dim) { arrayType = type; opcode = op; index = i; dimension = dim; } @Override public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) throws CompileError { int num = gen.getMethodArgsLength(args); if (num != dimension) throw new CompileError(Javac.proceedName + "() with a wrong number of parameters"); gen.atMethodArgs(args, new int[num], new int[num], new String[num]); bytecode.addOpcode(opcode); if (opcode == Opcode.ANEWARRAY) bytecode.addIndex(index); else if (opcode == Opcode.NEWARRAY) bytecode.add(index); else /* if (opcode == Opcode.MULTIANEWARRAY) */ { bytecode.addIndex(index); bytecode.add(dimension); bytecode.growStack(1 - dimension); } gen.setType(arrayType); } @Override public void setReturnType(JvstTypeChecker c, ASTList args) throws CompileError { c.setType(arrayType); } } }