/Users/lyon/j4p/src/javassist/expr/NewExpr.java

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