/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