/Users/lyon/j4p/src/javassist/bytecode/CodeAttribute.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.List;
22 import java.util.LinkedList;
23 import java.util.Map;
24
25 import javassist.CtClass;
26
27 /**
28 * <code>Code_attribute</code>.
29 *
30 * <p>To browse the <code>code</code> field of
31 * a <code>Code_attribute</code> structure,
32 * use <code>CodeIterator</code>.
33 *
34 * @see CodeIterator
35 */
36 public class CodeAttribute extends AttributeInfo implements Opcode {
37 /**
38 * The name of this attribute <code>"Code"</code>.
39 */
40 public static final String tag = "Code";
41
42 // code[] is stored in AttributeInfo.info.
43
44 private int maxStack;
45 private int maxLocals;
46 private ExceptionTable exceptions;
47 private LinkedList attributes;
48
49 /**
50 * Constructs a <code>Code_attribute</code>.
51 *
52 * @param cp constant pool table
53 * @param stack <code>max_stack</code>
54 * @param locals <code>max_locals</code>
55 * @param code <code>code[]</code>
56 * @param etable <code>exception_table[]</code>
57 */
58 public CodeAttribute(ConstPool cp, int stack, int locals, byte[] code,
59 ExceptionTable etable) {
60 super(cp, tag);
61 maxStack = stack;
62 maxLocals = locals;
63 info = code;
64 exceptions = etable;
65 attributes = new LinkedList();
66 }
67
68 /**
69 * Constructs a copy of <code>Code_attribute</code>.
70 * Specified class names are replaced during the copy.
71 *
72 * @param cp constant pool table.
73 * @param src source Code attribute.
74 * @param classnames pairs of replaced and substituted
75 * class names.
76 */
77 private CodeAttribute(ConstPool cp, CodeAttribute src, Map classnames)
78 throws BadBytecode {
79 super(cp, tag);
80
81 maxStack = src.getMaxStack();
82 maxLocals = src.getMaxLocals();
83 exceptions = src.getExceptionTable().copy(cp, classnames);
84 info = src.copyCode(cp, classnames, exceptions);
85 attributes = new LinkedList();
86
87 /* Since an index into the source constant pool table may not
88 be translated, we don't copy the attributes.
89 */
90 /*
91 List src_attr = src.getAttributes();
92 int num = src_attr.size();
93 for (int i = 0; i < num; ++i) {
94 AttributeInfo ai = (AttributeInfo)src_attr.get(i);
95 attributes.add(ai.copy(cp, classnames));
96 }
97 */
98 }
99
100 CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
101 throws IOException {
102 super(cp, name_id, (byte[]) null);
103 int attr_len = in.readInt();
104
105 maxStack = in.readUnsignedShort();
106 maxLocals = in.readUnsignedShort();
107
108 int code_len = in.readInt();
109 info = new byte[code_len];
110 in.readFully(info);
111
112 exceptions = new ExceptionTable(cp, in);
113
114 attributes = new LinkedList();
115 int num = in.readUnsignedShort();
116 for (int i = 0; i < num; ++i)
117 attributes.add(AttributeInfo.read(cp, in));
118 }
119
120 /**
121 * Makes a copy. Class names are replaced according to the
122 * given <code>Map</code> object.
123 *
124 * @param newCp the constant pool table used by the new copy.
125 * @param classnames pairs of replaced and substituted
126 * class names.
127 * @exception RuntimeCopyException if a <code>BadBytecode</code>
128 * exception is thrown, it is
129 * converted into
130 * <code>RuntimeCopyException</code>.
131 *
132 * @return <code>CodeAttribute</code> object.
133 */
134 public AttributeInfo copy(ConstPool newCp, Map classnames)
135 throws RuntimeCopyException {
136 try {
137 return new CodeAttribute(newCp, this, classnames);
138 } catch (BadBytecode e) {
139 throw new RuntimeCopyException("bad bytecode. fatal?");
140 }
141 }
142
143 /**
144 * An exception that may be thrown by <code>copy()</code>
145 * in <code>CodeAttribute</code>.
146 */
147 public static class RuntimeCopyException extends RuntimeException {
148 /**
149 * Constructs an exception.
150 */
151 public RuntimeCopyException(String s) {
152 super(s);
153 }
154 }
155
156 /**
157 * Returns the length of this <code>attribute_info</code>
158 * structure.
159 * The returned value is <code>attribute_length + 6</code>.
160 */
161 public int length() {
162 return 18 + info.length + exceptions.size() * 8
163 + AttributeInfo.getLength(attributes);
164 }
165
166 void write(DataOutputStream out) throws IOException {
167 out.writeShort(name); // attribute_name_index
168 out.writeInt(length() - 6); // attribute_length
169 out.writeShort(maxStack); // max_stack
170 out.writeShort(maxLocals); // max_locals
171 out.writeInt(info.length); // code_length
172 out.write(info); // code
173 exceptions.write(out);
174 out.writeShort(attributes.size()); // attributes_count
175 AttributeInfo.writeAll(attributes, out); // attributes
176 }
177
178 /**
179 * This method is not available.
180 *
181 * @throws java.lang.UnsupportedOperationException always thrown.
182 */
183 public byte[] get() {
184 throw new UnsupportedOperationException("CodeAttribute.get()");
185 }
186
187 /**
188 * This method is not available.
189 *
190 * @throws java.lang.UnsupportedOperationException always thrown.
191 */
192 public void set(byte[] newinfo) {
193 throw new UnsupportedOperationException("CodeAttribute.set()");
194 }
195
196 /**
197 * Returns the name of the class declaring the method including
198 * this code attribute.
199 */
200 public String getDeclaringClass() {
201 ConstPool cp = getConstPool();
202 return cp.getClassName();
203 }
204
205 /**
206 * Returns <code>max_stack</code>.
207 */
208 public int getMaxStack() {
209 return maxStack;
210 }
211
212 /**
213 * Sets <code>max_stack</code>.
214 */
215 public void setMaxStack(int value) {
216 maxStack = value;
217 }
218
219 /**
220 * Returns <code>max_locals</code>.
221 */
222 public int getMaxLocals() {
223 return maxLocals;
224 }
225
226 /**
227 * Sets <code>max_locals</code>.
228 */
229 public void setMaxLocals(int value) {
230 maxLocals = value;
231 }
232
233 /**
234 * Returns <code>code_length</code>.
235 */
236 public int getCodeLength() {
237 return info.length;
238 }
239
240 /**
241 * Returns <code>code[]</code>.
242 */
243 public byte[] getCode() {
244 return info;
245 }
246
247 /**
248 * Sets <code>code[]</code>.
249 */
250 void setCode(byte[] newinfo) {
251 super.set(newinfo);
252 }
253
254 /**
255 * Makes a new iterator for reading this code attribute.
256 */
257 public CodeIterator iterator() {
258 return new CodeIterator(this);
259 }
260
261 /**
262 * Returns <code>exception_table[]</code>.
263 */
264 public ExceptionTable getExceptionTable() {
265 return exceptions;
266 }
267
268 /**
269 * Returns <code>attributes[]</code>.
270 * It returns a list of <code>AttributeInfo</code>.
271 *
272 * @see AttributeInfo
273 */
274 public List getAttributes() {
275 return attributes;
276 }
277
278 /**
279 * Returns the attribute with the specified name.
280 * If it is not found, this method returns null.
281 *
282 * @param name attribute name
283 * @return an <code>AttributeInfo</code> object or null.
284 */
285 public AttributeInfo getAttribute(String name) {
286 return AttributeInfo.lookup(attributes, name);
287 }
288
289 /**
290 * Copies code.
291 */
292 private byte[] copyCode(ConstPool destCp, Map classnames,
293 ExceptionTable etable)
294 throws BadBytecode {
295 int len = getCodeLength();
296 byte[] newCode = new byte[len];
297
298 LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
299 newCode, destCp, classnames);
300 return LdcEntry.doit(newCode, ldc, etable);
301 }
302
303 private static LdcEntry copyCode(byte[] code, int beginPos, int endPos,
304 ConstPool srcCp, byte[] newcode,
305 ConstPool destCp, Map classnameMap)
306 throws BadBytecode {
307 int i2, index;
308 LdcEntry ldcEntry = null;
309
310 for (int i = beginPos; i < endPos; i = i2) {
311 i2 = CodeIterator.nextOpcode(code, i);
312 byte c = code[i];
313 newcode[i] = c;
314 switch (c & 0xff) {
315 case LDC_W:
316 case LDC2_W:
317 case GETSTATIC:
318 case PUTSTATIC:
319 case GETFIELD:
320 case PUTFIELD:
321 case INVOKEVIRTUAL:
322 case INVOKESPECIAL:
323 case INVOKESTATIC:
324 case NEW:
325 case ANEWARRAY:
326 case CHECKCAST:
327 case INSTANCEOF:
328 copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
329 classnameMap);
330 break;
331 case LDC:
332 index = code[i + 1] & 0xff;
333 index = srcCp.copy(index, destCp, classnameMap);
334 if (index < 0x100)
335 newcode[i + 1] = (byte) index;
336 else {
337 LdcEntry ldc = new LdcEntry();
338 ldc.where = i;
339 ldc.index = index;
340 ldc.next = ldcEntry;
341 ldcEntry = ldc;
342 }
343 break;
344 case INVOKEINTERFACE:
345 copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
346 classnameMap);
347 newcode[i + 3] = code[i + 3];
348 newcode[i + 4] = code[i + 4];
349 break;
350 case MULTIANEWARRAY:
351 copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
352 classnameMap);
353 newcode[i + 3] = code[i + 3];
354 break;
355 default :
356 while (++i < i2)
357 newcode[i] = code[i];
358
359 break;
360 }
361 }
362
363 return ldcEntry;
364 }
365
366 private static void copyConstPoolInfo(int i, byte[] code, ConstPool srcCp,
367 byte[] newcode, ConstPool destCp,
368 Map classnameMap) {
369 int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff);
370 index = srcCp.copy(index, destCp, classnameMap);
371 newcode[i] = (byte) (index >> 8);
372 newcode[i + 1] = (byte) index;
373 }
374 }
375
376 final class LdcEntry {
377 LdcEntry next;
378 int where;
379 int index;
380
381 static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable)
382 throws BadBytecode {
383 while (ldc != null) {
384 int where = ldc.where;
385 code = CodeIterator.insertGap(code, where, 1, false, etable);
386 code[where] = (byte) Opcode.LDC_W;
387 ByteArray.write16bit(ldc.index, code, where + 1);
388 ldc = ldc.next;
389 }
390
391 return code;
392 }
393 }
394