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