/Users/lyon/j4p/src/javassist/CtNewWrappedMethod.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; 
17    
18   import javassist.bytecode.*; 
19   import javassist.compiler.JvstCodeGen; 
20    
21   import java.util.Hashtable; 
22    
23   import javassist.CtMethod.ConstParameter; 
24    
25   class CtNewWrappedMethod { 
26    
27       private static final String addedWrappedMethod = "_added_m$"; 
28    
29       public static CtMethod wrapped(CtClass returnType, String mname, 
30                                      CtClass[] parameterTypes, 
31                                      CtClass[] exceptionTypes, 
32                                      CtMethod body, ConstParameter constParam, 
33                                      CtClass declaring) 
34               throws CannotCompileException { 
35           CtMethod mt = new CtMethod(returnType, mname, parameterTypes, 
36                   declaring); 
37           mt.setModifiers(body.getModifiers()); 
38           try { 
39               mt.setExceptionTypes(exceptionTypes); 
40           } catch (NotFoundException e) { 
41               throw new CannotCompileException(e); 
42           } 
43    
44           Bytecode code = makeBody(declaring, declaring.getClassFile2(), body, 
45                   parameterTypes, returnType, constParam); 
46           mt.getMethodInfo2().setCodeAttribute(code.toCodeAttribute()); 
47           return mt; 
48       } 
49    
50       static Bytecode makeBody(CtClass clazz, ClassFile classfile, 
51                                CtMethod wrappedBody, 
52                                CtClass[] parameters, 
53                                CtClass returnType, 
54                                ConstParameter cparam) 
55               throws CannotCompileException { 
56           boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers()); 
57           Bytecode code = new Bytecode(classfile.getConstPool(), 0, 0); 
58           int stacksize = makeBody0(clazz, classfile, wrappedBody, isStatic, 
59                   parameters, returnType, cparam, code); 
60           code.setMaxStack(stacksize); 
61           code.setMaxLocals(isStatic, parameters, 0); 
62           return code; 
63       } 
64    
65       protected static int makeBody0(CtClass clazz, ClassFile classfile, 
66                                      CtMethod wrappedBody, 
67                                      boolean isStatic, CtClass[] parameters, 
68                                      CtClass returnType, ConstParameter cparam, 
69                                      Bytecode code) 
70               throws CannotCompileException { 
71           if (!(clazz instanceof CtClassType)) 
72               throw new CannotCompileException("bad declaring class" 
73                       + clazz.getName()); 
74    
75           if (!isStatic) 
76               code.addAload(0); 
77    
78           int stacksize = compileParameterList(code, parameters, 
79                   (isStatic ? 0 : 1)); 
80           int stacksize2; 
81           String desc; 
82           if (cparam == null) { 
83               stacksize2 = 0; 
84               desc = ConstParameter.defaultDescriptor(); 
85           } else { 
86               stacksize2 = cparam.compile(code); 
87               desc = cparam.descriptor(); 
88           } 
89    
90           checkSignature(wrappedBody, desc); 
91    
92           String bodyname; 
93           try { 
94               bodyname = addBodyMethod((CtClassType) clazz, classfile, 
95                       wrappedBody); 
96               /* if an exception is thrown below, the method added above 
97                * should be removed. (future work :<) 
98                */ 
99           } catch (BadBytecode e) { 
100              throw new CannotCompileException(e); 
101          } 
102   
103          if (isStatic) 
104              code.addInvokestatic(Bytecode.THIS, bodyname, desc); 
105          else 
106              code.addInvokespecial(Bytecode.THIS, bodyname, desc); 
107   
108          compileReturn(code, returnType);        // consumes 2 stack entries 
109   
110          if (stacksize < stacksize2 + 2) 
111              stacksize = stacksize2 + 2; 
112   
113          return stacksize; 
114      } 
115   
116      private static void checkSignature(CtMethod wrappedBody, 
117                                         String descriptor) 
118              throws CannotCompileException { 
119          if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor())) 
120              throw new CannotCompileException( 
121                      "wrapped method with a bad signature: " 
122                      + wrappedBody.getDeclaringClass().getName() 
123                      + '.' + wrappedBody.getName()); 
124      } 
125   
126      private static String addBodyMethod(CtClassType clazz, 
127                                          ClassFile classfile, 
128                                          CtMethod src) 
129              throws BadBytecode { 
130          Hashtable bodies = clazz.getHiddenMethods(); 
131          String bodyname = (String) bodies.get(src); 
132          if (bodyname == null) { 
133              do { 
134                  bodyname = addedWrappedMethod + clazz.getUniqueNumber(); 
135              } while (classfile.getMethod(bodyname) != null); 
136   
137              ClassMap map = new ClassMap(); 
138              map.put(src.getDeclaringClass().getName(), clazz.getName()); 
139              MethodInfo body = new MethodInfo(classfile.getConstPool(), 
140                      bodyname, src.getMethodInfo2(), 
141                      map); 
142              int acc = body.getAccessFlags(); 
143              body.setAccessFlags(AccessFlag.setPrivate(acc)); 
144              classfile.addMethod(body); 
145              bodies.put(src, bodyname); 
146          } 
147   
148          return bodyname; 
149      } 
150   
151      /* compileParameterList() returns the stack size used 
152       * by the produced code. 
153       * 
154       * @param regno     the index of the local variable in which 
155       *                  the first argument is received. 
156       *                  (0: static method, 1: regular method.) 
157       */ 
158      static int compileParameterList(Bytecode code, 
159                                      CtClass[] params, int regno) { 
160          return JvstCodeGen.compileParameterList(code, params, regno); 
161      } 
162   
163      /* 
164       * The produced codes cosume 1 or 2 stack entries. 
165       */ 
166      private static void compileReturn(Bytecode code, CtClass type) { 
167          if (type.isPrimitive()) { 
168              CtPrimitiveType pt = (CtPrimitiveType) type; 
169              if (pt != CtClass.voidType) { 
170                  String wrapper = pt.getWrapperName(); 
171                  code.addCheckcast(wrapper); 
172                  code.addInvokevirtual(wrapper, pt.getGetMethodName(), 
173                          pt.getGetMethodDescriptor()); 
174              } 
175   
176              code.addOpcode(pt.getReturnOp()); 
177          } else { 
178              code.addCheckcast(type); 
179              code.addOpcode(Bytecode.ARETURN); 
180          } 
181      } 
182  } 
183