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