/Users/lyon/j4p/src/javassist/bytecode/MethodInfo.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.bytecode;
17
18 import java.io.DataInputStream;
19 import java.io.DataOutputStream;
20 import java.io.IOException;
21 import java.util.Map;
22 import java.util.List;
23 import java.util.LinkedList;
24
25 import javassist.CannotCompileException;
26
27 /**
28 * <code>method_info</code> structure.
29 *
30 * @see javassist.CtMethod#getMethodInfo()
31 * @see javassist.CtConstructor#getMethodInfo()
32 */
33 public final class MethodInfo {
34 ConstPool constPool;
35 int accessFlags;
36 int name;
37 int descriptor;
38 LinkedList attribute; // may be null
39
40 /**
41 * The name of constructors: <code><init></code>.
42 */
43 public static final String nameInit = "<init>";
44
45 /**
46 * The name of class initializer (static initializer):
47 * <code><clinit></code>.
48 */
49 public static final String nameClinit = "<clinit>";
50
51 private MethodInfo(ConstPool cp) {
52 constPool = cp;
53 attribute = null;
54 }
55
56 /**
57 * Constructs a <code>method_info</code> structure.
58 *
59 * @param cp a constant pool table
60 * @param methodname method name
61 * @param desc method descriptor
62 *
63 * @see Descriptor
64 */
65 public MethodInfo(ConstPool cp, String methodname, String desc) {
66 this(cp);
67 accessFlags = 0;
68 name = cp.addUtf8Info(methodname);
69 descriptor = constPool.addUtf8Info(desc);
70 }
71
72 MethodInfo(ConstPool cp, DataInputStream in) throws IOException {
73 this(cp);
74 read(in);
75 }
76
77 /**
78 * Constructs a copy of <code>method_info</code> structure.
79 * Class names appearing in the source <code>method_info</code>
80 * are renamed according to <code>classnameMap</code>.
81 *
82 * <p>Note: only <code>Code</code> and <code>Exceptions</code>
83 * attributes are copied from the source. The other attributes
84 * are ignored.
85 *
86 * @param cp a constant pool table
87 * @param methodname a method name
88 * @param src a source <code>method_info</code>
89 * @param classnameMap specifies pairs of replaced and substituted
90 * name.
91 * @see Descriptor
92 */
93 public MethodInfo(ConstPool cp, String methodname, MethodInfo src,
94 Map classnameMap) throws BadBytecode {
95 this(cp);
96 read(src, methodname, classnameMap);
97 }
98
99 /**
100 * Returns a method name.
101 */
102 public String getName() {
103 return constPool.getUtf8Info(name);
104 }
105
106 /**
107 * Sets a method name.
108 */
109 public void setName(String newName) {
110 name = constPool.addUtf8Info(newName);
111 }
112
113 /**
114 * Returns true if this is not a constructor or a class initializer
115 * (static initializer).
116 */
117 public boolean isMethod() {
118 String n = getName();
119 return !n.equals(nameInit) && !n.equals(nameClinit);
120 }
121
122 /**
123 * Returns a constant pool table used by this method.
124 */
125 public ConstPool getConstPool() {
126 return constPool;
127 }
128
129 /**
130 * Returns true if this is a constructor.
131 */
132 public boolean isConstructor() {
133 return getName().equals(nameInit);
134 }
135
136 /**
137 * Returns true if this is a class initializer (static initializer).
138 */
139 public boolean isStaticInitializer() {
140 return getName().equals(nameClinit);
141 }
142
143 /**
144 * Returns access flags.
145 *
146 * @see AccessFlag
147 */
148 public int getAccessFlags() {
149 return accessFlags;
150 }
151
152 /**
153 * Sets access flags.
154 *
155 * @see AccessFlag
156 */
157 public void setAccessFlags(int acc) {
158 accessFlags = acc;
159 }
160
161 /**
162 * Returns a method descriptor.
163 *
164 * @see Descriptor
165 */
166 public String getDescriptor() {
167 return constPool.getUtf8Info(descriptor);
168 }
169
170 /**
171 * Sets a method descriptor.
172 *
173 * @see Descriptor
174 */
175 public void setDescriptor(String desc) {
176 if (!desc.equals(getDescriptor()))
177 descriptor = constPool.addUtf8Info(desc);
178 }
179
180 /**
181 * Returns all the attributes.
182 *
183 * @return a list of <code>AttributeInfo</code> objects.
184 * @see AttributeInfo
185 */
186 public List getAttributes() {
187 if (attribute == null)
188 attribute = new LinkedList();
189
190 return attribute;
191 }
192
193 /**
194 * Returns the attribute with the specified name.
195 * If it is not found, this method returns null.
196 *
197 * @param name attribute name
198 * @return an <code>AttributeInfo</code> object or null.
199 */
200 public AttributeInfo getAttribute(String name) {
201 return AttributeInfo.lookup(attribute, name);
202 }
203
204 /**
205 * Appends an attribute. If there is already an attribute with
206 * the same name, the new one substitutes for it.
207 */
208 public void addAttribute(AttributeInfo info) {
209 if (attribute == null)
210 attribute = new LinkedList();
211
212 AttributeInfo.remove(attribute, info.getName());
213 attribute.add(info);
214 }
215
216 /**
217 * Returns an Exceptions attribute.
218 *
219 * @return an Exceptions attribute
220 * or null if it is not specified.
221 */
222 public ExceptionsAttribute getExceptionsAttribute() {
223 AttributeInfo info
224 = AttributeInfo.lookup(attribute, ExceptionsAttribute.class);
225 return (ExceptionsAttribute) info;
226 }
227
228 /**
229 * Returns a Code attribute.
230 *
231 * @return a Code attribute
232 * or null if it is not specified.
233 */
234 public CodeAttribute getCodeAttribute() {
235 AttributeInfo info
236 = AttributeInfo.lookup(attribute, CodeAttribute.class);
237 return (CodeAttribute) info;
238 }
239
240 /**
241 * Removes an Exception attribute.
242 */
243 public void removeExceptionsAttribute() {
244 AttributeInfo.remove(attribute, ExceptionsAttribute.class);
245 }
246
247 /**
248 * Adds an Exception attribute.
249 *
250 * <p>The added attribute must share the same constant pool table
251 * as this <code>method_info</code> structure.
252 */
253 public void setExceptionsAttribute(ExceptionsAttribute cattr) {
254 removeExceptionsAttribute();
255 if (attribute == null)
256 attribute = new LinkedList();
257
258 attribute.add(cattr);
259 }
260
261 /**
262 * Removes a Code attribute.
263 */
264 public void removeCodeAttribute() {
265 AttributeInfo.remove(attribute, CodeAttribute.class);
266 }
267
268 /**
269 * Adds a Code attribute.
270 *
271 * <p>The added attribute must share the same constant pool table
272 * as this <code>method_info</code> structure.
273 */
274 public void setCodeAttribute(CodeAttribute cattr) {
275 removeCodeAttribute();
276 if (attribute == null)
277 attribute = new LinkedList();
278
279 attribute.add(cattr);
280 }
281
282 /**
283 * Returns the line number of the source line corresponding to the
284 * specified bytecode contained in this method.
285 *
286 * @param pos the position of the bytecode (>= 0).
287 * an index into the code array.
288 * @return -1 if this information is not available.
289 */
290 public int getLineNumber(int pos) {
291 CodeAttribute ca = getCodeAttribute();
292 if (ca == null)
293 return -1;
294
295 LineNumberAttribute ainfo
296 = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag);
297 if (ainfo == null)
298 return -1;
299
300 return ainfo.toLineNumber(pos);
301 }
302
303 /**
304 * Changes a super constructor called by this constructor.
305 *
306 * <p>This method modifies a call to <code>super()</code>,
307 * which should be at the
308 * head of a constructor body, so that a constructor in a different
309 * super class is called. This method does not change actural
310 * parameters. Hence the new super class must have a constructor
311 * with the same signature as the original one.
312 *
313 * <p>This method should be called when the super class
314 * of the class declaring this method is changed.
315 *
316 * <p>This method does not perform anything unless this
317 * <code>MethodInfo</code> represents a constructor.
318 *
319 * @param superclass the new super class
320 */
321 public void setSuperclass(String superclass) throws BadBytecode {
322 if (!isConstructor())
323 return;
324
325 CodeAttribute ca = getCodeAttribute();
326 byte[] code = ca.getCode();
327 CodeIterator iterator = ca.iterator();
328 int pos = iterator.skipSuperConstructor();
329 if (pos >= 0) { // not this()
330 ConstPool cp = constPool;
331 int mref = ByteArray.readU16bit(code, pos + 1);
332 int nt = cp.getMethodrefNameAndType(mref);
333 int sc = cp.addClassInfo(superclass);
334 int mref2 = cp.addMethodrefInfo(sc, nt);
335 ByteArray.write16bit(mref2, code, pos + 1);
336 }
337 }
338
339 private void read(MethodInfo src, String methodname, Map classnames)
340 throws BadBytecode {
341 ConstPool destCp = constPool;
342 accessFlags = src.accessFlags;
343 name = destCp.addUtf8Info(methodname);
344
345 ConstPool srcCp = src.constPool;
346 String desc = srcCp.getUtf8Info(src.descriptor);
347 String desc2 = Descriptor.rename(desc, classnames);
348 descriptor = destCp.addUtf8Info(desc2);
349
350 attribute = new LinkedList();
351 ExceptionsAttribute eattr = src.getExceptionsAttribute();
352 if (eattr != null)
353 attribute.add(eattr.copy(destCp, classnames));
354
355 CodeAttribute cattr = src.getCodeAttribute();
356 if (cattr != null)
357 attribute.add(cattr.copy(destCp, classnames));
358 }
359
360 private void read(DataInputStream in) throws IOException {
361 accessFlags = in.readUnsignedShort();
362 name = in.readUnsignedShort();
363 descriptor = in.readUnsignedShort();
364 int n = in.readUnsignedShort();
365 attribute = new LinkedList();
366 for (int i = 0; i < n; ++i)
367 attribute.add(AttributeInfo.read(constPool, in));
368 }
369
370 void write(DataOutputStream out) throws IOException {
371 out.writeShort(accessFlags);
372 out.writeShort(name);
373 out.writeShort(descriptor);
374
375 if (attribute == null)
376 out.writeShort(0);
377 else {
378 out.writeShort(attribute.size());
379 AttributeInfo.writeAll(attribute, out);
380 }
381 }
382 }
383