123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * 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.
- *
- * <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.
- */
- @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 <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.
- */
- 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.
- *
- * <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, int lineNumber)
- throws CompileError
- {
- int num = gen.getMethodArgsLength(args);
- if (num != dimension)
- throw new CompileError(Javac.proceedName
- + "() with a wrong number of parameters", lineNumber);
-
- 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, lineNumber);
- }
-
- @Override
- public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber)
- throws CompileError
- {
- c.setType(arrayType, lineNumber);
- }
- }
- }
|