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  * Object creation (<tt>new</tt> expression).
     25  */
     26 public class NewExpr extends Expr {
     27     String newTypeName;
     28     int newPos;
     29 
     30     /**
     31      * Undocumented constructor.  Do not use; internal-use only.
     32      */
     33     protected NewExpr(int pos, CodeIterator i, CtClass declaring,
     34                       MethodInfo m, String type, int np) {
     35         super(pos, i, declaring, m);
     36         newTypeName = type;
     37         newPos = np;
     38     }
     39 
     40     /*
     41      * Not used
     42      *
     43     private int getNameAndType(ConstPool cp) {
     44         int pos = currentPos;
     45         int c = iterator.byteAt(pos);
     46         int index = iterator.u16bitAt(pos + 1);
     47 
     48         if (c == INVOKEINTERFACE)
     49             return cp.getInterfaceMethodrefNameAndType(index);
     50         else
     51             return cp.getMethodrefNameAndType(index);
     52     } */
     53 
     54     /**
     55      * Returns the method or constructor containing the <tt>new</tt>
     56      * expression represented by this object.
     57      */
     58     public CtBehavior where() { return super.where(); }
     59 
     60     /**
     61      * Returns the line number of the source line containing the
     62      * <tt>new</tt> expression.
     63      *
     64      * @return -1       if this information is not available.
     65      */
     66     public int getLineNumber() {
     67         return super.getLineNumber();
     68     }
     69 
     70     /**
     71      * Returns the source file containing the <tt>new</tt> expression.
     72      *
     73      * @return null     if this information is not available.
     74      */
     75     public String getFileName() {
     76         return super.getFileName();
     77     }
     78 
     79     /**
     80      * Returns the class of the created object.
     81      */
     82     private CtClass getCtClass() throws NotFoundException {
     83         return thisClass.getClassPool().get(newTypeName);
     84     }
     85 
     86     /**
     87      * Returns the class name of the created object.
     88      */
     89     public String getClassName() {
     90         return newTypeName;
     91     }
     92 
     93     /**
     94      * Get the signature of the constructor
     95      *
     96      * The signature is represented by a character string
     97      * called method descriptor, which is defined in the JVM specification.
     98      *
     99      * @see javassist.CtBehavior#getSignature()
    100      * @see javassist.bytecode.Descriptor
    101      * @return the signature
    102      */
    103     public String getSignature() {
    104         ConstPool constPool = getConstPool();
    105         int methodIndex = iterator.u16bitAt(currentPos + 1);   // constructor
    106         return constPool.getMethodrefType(methodIndex);
    107     }
    108 
    109     /**
    110      * Returns the constructor called for creating the object.
    111      */
    112     public CtConstructor getConstructor() throws NotFoundException {
    113         ConstPool cp = getConstPool();
    114         int index = iterator.u16bitAt(currentPos + 1);
    115         String desc = cp.getMethodrefType(index);
    116         return getCtClass().getConstructor(desc);
    117     }
    118 
    119     /**
    120      * Returns the list of exceptions that the expression may throw.
    121      * This list includes both the exceptions that the try-catch statements
    122      * including the expression can catch and the exceptions that
    123      * the throws declaration allows the method to throw.
    124      */
    125     public CtClass[] mayThrow() {
    126         return super.mayThrow();
    127     }
    128 
    129     /*
    130      * Returns the parameter types of the constructor.
    131 
    132     public CtClass[] getParameterTypes() throws NotFoundException {
    133         ConstPool cp = getConstPool();
    134         int index = iterator.u16bitAt(currentPos + 1);
    135         String desc = cp.getMethodrefType(index);
    136         return Descriptor.getParameterTypes(desc, thisClass.getClassPool());
    137     }
    138     */
    139 
    140     private int canReplace() throws CannotCompileException {
    141         int op = iterator.byteAt(newPos + 3);
    142         if (op == Opcode.DUP)
    143             return 4;
    144         else if (op == Opcode.DUP_X1
    145                  && iterator.byteAt(newPos + 4) == Opcode.SWAP)
    146             return 5;
    147         else
    148             return 3;   // for Eclipse.  The generated code may include no DUP.
    149             // throw new CannotCompileException(
    150             //            "sorry, cannot edit NEW followed by no DUP");
    151     }
    152 
    153     /**
    154      * Replaces the <tt>new</tt> expression with the bytecode derived from
    155      * the given source text.
    156      *
    157      * <p>$0 is available but the value is null.
    158      *
    159      * @param statement         a Java statement except try-catch.
    160      */
    161     public void replace(String statement) throws CannotCompileException {
    162         thisClass.getClassFile();   // to call checkModify().
    163 
    164         final int bytecodeSize = 3;
    165         int pos = newPos;
    166 
    167         int newIndex = iterator.u16bitAt(pos + 1);
    168 
    169         /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions.
    170          */
    171         int codeSize = canReplace();
    172         int end = pos + codeSize;
    173         for (int i = pos; i < end; ++i)
    174             iterator.writeByte(NOP, i);
    175 
    176         ConstPool constPool = getConstPool();
    177         pos = currentPos;
    178         int methodIndex = iterator.u16bitAt(pos + 1);   // constructor
    179 
    180         String signature = constPool.getMethodrefType(methodIndex);
    181 
    182         Javac jc = new Javac(thisClass);
    183         ClassPool cp = thisClass.getClassPool();
    184         CodeAttribute ca = iterator.get();
    185         try {
    186             CtClass[] params = Descriptor.getParameterTypes(signature, cp);
    187             CtClass newType = cp.get(newTypeName);
    188             int paramVar = ca.getMaxLocals();
    189             jc.recordParams(newTypeName, params,
    190                             true, paramVar, withinStatic());
    191             int retVar = jc.recordReturnType(newType, true);
    192             jc.recordProceed(new ProceedForNew(newType, newIndex,
    193                                                methodIndex));
    194 
    195             /* Is $_ included in the source code?
    196              */
    197             checkResultValue(newType, statement);
    198 
    199             Bytecode bytecode = jc.getBytecode();
    200             storeStack(params, true, paramVar, bytecode);
    201             jc.recordLocalVariables(ca, pos);
    202 
    203             bytecode.addConstZero(newType);
    204             bytecode.addStore(retVar, newType);     // initialize $_
    205 
    206             jc.compileStmnt(statement);
    207             if (codeSize > 3)   // if the original code includes DUP.
    208                 bytecode.addAload(retVar);
    209 
    210             replace0(pos, bytecode, bytecodeSize);
    211         }
    212         catch (CompileError e) { throw new CannotCompileException(e); }
    213         catch (NotFoundException e) { throw new CannotCompileException(e); }
    214         catch (BadBytecode e) {
    215             throw new CannotCompileException("broken method");
    216         }
    217     }
    218 
    219     static class ProceedForNew implements ProceedHandler {
    220         CtClass newType;
    221         int newIndex, methodIndex;
    222 
    223         ProceedForNew(CtClass nt, int ni, int mi) {
    224             newType = nt;
    225             newIndex = ni;
    226             methodIndex = mi;
    227         }
    228 
    229         public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
    230             throws CompileError
    231         {
    232             bytecode.addOpcode(NEW);
    233             bytecode.addIndex(newIndex);
    234             bytecode.addOpcode(DUP);
    235             gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
    236                                  false, true, -1, null);
    237             gen.setType(newType);
    238         }
    239 
    240         public void setReturnType(JvstTypeChecker c, ASTList args)
    241             throws CompileError
    242         {
    243             c.atMethodCallCore(newType, MethodInfo.nameInit, args);
    244             c.setType(newType);
    245         }
    246     }
    247 }
    248