001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.bytecode;
017:
018: import java.io.DataInputStream;
019: import java.io.DataOutputStream;
020: import java.io.IOException;
021: import java.util.List;
022: import java.util.LinkedList;
023: import java.util.Map;
024:
025: /**
026: * <code>Code_attribute</code>.
027: *
028: * <p>To browse the <code>code</code> field of
029: * a <code>Code_attribute</code> structure,
030: * use <code>CodeIterator</code>.
031: *
032: * @see CodeIterator
033: */
034: public class CodeAttribute extends AttributeInfo implements Opcode {
035: /**
036: * The name of this attribute <code>"Code"</code>.
037: */
038: public static final String tag = "Code";
039:
040: // code[] is stored in AttributeInfo.info.
041:
042: private int maxStack;
043: private int maxLocals;
044: private ExceptionTable exceptions;
045: private LinkedList attributes;
046:
047: /**
048: * Constructs a <code>Code_attribute</code>.
049: *
050: * @param cp constant pool table
051: * @param stack <code>max_stack</code>
052: * @param locals <code>max_locals</code>
053: * @param code <code>code[]</code>
054: * @param etable <code>exception_table[]</code>
055: */
056: public CodeAttribute(ConstPool cp, int stack, int locals,
057: byte[] code, ExceptionTable etable) {
058: super (cp, tag);
059: maxStack = stack;
060: maxLocals = locals;
061: info = code;
062: exceptions = etable;
063: attributes = new LinkedList();
064: }
065:
066: /**
067: * Constructs a copy of <code>Code_attribute</code>.
068: * Specified class names are replaced during the copy.
069: *
070: * @param cp constant pool table.
071: * @param src source Code attribute.
072: * @param classnames pairs of replaced and substituted
073: * class names.
074: */
075: private CodeAttribute(ConstPool cp, CodeAttribute src,
076: Map classnames) throws BadBytecode {
077: super (cp, tag);
078:
079: maxStack = src.getMaxStack();
080: maxLocals = src.getMaxLocals();
081: exceptions = src.getExceptionTable().copy(cp, classnames);
082: info = src.copyCode(cp, classnames, exceptions, this );
083:
084: attributes = new LinkedList();
085: List src_attr = src.getAttributes();
086: int num = src_attr.size();
087: for (int i = 0; i < num; ++i) {
088: AttributeInfo ai = (AttributeInfo) src_attr.get(i);
089: attributes.add(ai.copy(cp, classnames));
090: }
091: }
092:
093: CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
094: throws IOException {
095: super (cp, name_id, (byte[]) null);
096: int attr_len = in.readInt();
097:
098: maxStack = in.readUnsignedShort();
099: maxLocals = in.readUnsignedShort();
100:
101: int code_len = in.readInt();
102: info = new byte[code_len];
103: in.readFully(info);
104:
105: exceptions = new ExceptionTable(cp, in);
106:
107: attributes = new LinkedList();
108: int num = in.readUnsignedShort();
109: for (int i = 0; i < num; ++i)
110: attributes.add(AttributeInfo.read(cp, in));
111: }
112:
113: /**
114: * Makes a copy. Class names are replaced according to the
115: * given <code>Map</code> object.
116: *
117: * @param newCp the constant pool table used by the new copy.
118: * @param classnames pairs of replaced and substituted
119: * class names.
120: * @exception RuntimeCopyException if a <code>BadBytecode</code>
121: * exception is thrown, it is
122: * converted into
123: * <code>RuntimeCopyException</code>.
124: *
125: * @return <code>CodeAttribute</code> object.
126: */
127: public AttributeInfo copy(ConstPool newCp, Map classnames)
128: throws RuntimeCopyException {
129: try {
130: return new CodeAttribute(newCp, this , classnames);
131: } catch (BadBytecode e) {
132: throw new RuntimeCopyException("bad bytecode. fatal?");
133: }
134: }
135:
136: /**
137: * An exception that may be thrown by <code>copy()</code>
138: * in <code>CodeAttribute</code>.
139: */
140: public static class RuntimeCopyException extends RuntimeException {
141: /**
142: * Constructs an exception.
143: */
144: public RuntimeCopyException(String s) {
145: super (s);
146: }
147: }
148:
149: /**
150: * Returns the length of this <code>attribute_info</code>
151: * structure.
152: * The returned value is <code>attribute_length + 6</code>.
153: */
154: public int length() {
155: return 18 + info.length + exceptions.size() * 8
156: + AttributeInfo.getLength(attributes);
157: }
158:
159: void write(DataOutputStream out) throws IOException {
160: out.writeShort(name); // attribute_name_index
161: out.writeInt(length() - 6); // attribute_length
162: out.writeShort(maxStack); // max_stack
163: out.writeShort(maxLocals); // max_locals
164: out.writeInt(info.length); // code_length
165: out.write(info); // code
166: exceptions.write(out);
167: out.writeShort(attributes.size()); // attributes_count
168: AttributeInfo.writeAll(attributes, out); // attributes
169: }
170:
171: /**
172: * This method is not available.
173: *
174: * @throws java.lang.UnsupportedOperationException always thrown.
175: */
176: public byte[] get() {
177: throw new UnsupportedOperationException("CodeAttribute.get()");
178: }
179:
180: /**
181: * This method is not available.
182: *
183: * @throws java.lang.UnsupportedOperationException always thrown.
184: */
185: public void set(byte[] newinfo) {
186: throw new UnsupportedOperationException("CodeAttribute.set()");
187: }
188:
189: /**
190: * Returns the name of the class declaring the method including
191: * this code attribute.
192: */
193: public String getDeclaringClass() {
194: ConstPool cp = getConstPool();
195: return cp.getClassName();
196: }
197:
198: /**
199: * Returns <code>max_stack</code>.
200: */
201: public int getMaxStack() {
202: return maxStack;
203: }
204:
205: /**
206: * Sets <code>max_stack</code>.
207: */
208: public void setMaxStack(int value) {
209: maxStack = value;
210: }
211:
212: /**
213: * Computes the maximum stack size and sets <code>max_stack</code>
214: * to the computed size.
215: *
216: * @throws BadBytecode if this method fails in computing.
217: * @return the newly computed value of <code>max_stack</code>
218: */
219: public int computeMaxStack() throws BadBytecode {
220: maxStack = new CodeAnalyzer(this ).computeMaxStack();
221: return maxStack;
222: }
223:
224: /**
225: * Returns <code>max_locals</code>.
226: */
227: public int getMaxLocals() {
228: return maxLocals;
229: }
230:
231: /**
232: * Sets <code>max_locals</code>.
233: */
234: public void setMaxLocals(int value) {
235: maxLocals = value;
236: }
237:
238: /**
239: * Returns <code>code_length</code>.
240: */
241: public int getCodeLength() {
242: return info.length;
243: }
244:
245: /**
246: * Returns <code>code[]</code>.
247: */
248: public byte[] getCode() {
249: return info;
250: }
251:
252: /**
253: * Sets <code>code[]</code>.
254: */
255: void setCode(byte[] newinfo) {
256: super .set(newinfo);
257: }
258:
259: /**
260: * Makes a new iterator for reading this code attribute.
261: */
262: public CodeIterator iterator() {
263: return new CodeIterator(this );
264: }
265:
266: /**
267: * Returns <code>exception_table[]</code>.
268: */
269: public ExceptionTable getExceptionTable() {
270: return exceptions;
271: }
272:
273: /**
274: * Returns <code>attributes[]</code>.
275: * It returns a list of <code>AttributeInfo</code>.
276: * A new element can be added to the returned list
277: * and an existing element can be removed from the list.
278: *
279: * @see AttributeInfo
280: */
281: public List getAttributes() {
282: return attributes;
283: }
284:
285: /**
286: * Returns the attribute with the specified name.
287: * If it is not found, this method returns null.
288: *
289: * @param name attribute name
290: * @return an <code>AttributeInfo</code> object or null.
291: */
292: public AttributeInfo getAttribute(String name) {
293: return AttributeInfo.lookup(attributes, name);
294: }
295:
296: /**
297: * Copies code.
298: */
299: private byte[] copyCode(ConstPool destCp, Map classnames,
300: ExceptionTable etable, CodeAttribute destCa)
301: throws BadBytecode {
302: int len = getCodeLength();
303: byte[] newCode = new byte[len];
304:
305: LdcEntry ldc = copyCode(this .info, 0, len, this .getConstPool(),
306: newCode, destCp, classnames);
307: return LdcEntry.doit(newCode, ldc, etable, destCa);
308: }
309:
310: private static LdcEntry copyCode(byte[] code, int beginPos,
311: int endPos, ConstPool srcCp, byte[] newcode,
312: ConstPool destCp, Map classnameMap) throws BadBytecode {
313: int i2, index;
314: LdcEntry ldcEntry = null;
315:
316: for (int i = beginPos; i < endPos; i = i2) {
317: i2 = CodeIterator.nextOpcode(code, i);
318: byte c = code[i];
319: newcode[i] = c;
320: switch (c & 0xff) {
321: case LDC_W:
322: case LDC2_W:
323: case GETSTATIC:
324: case PUTSTATIC:
325: case GETFIELD:
326: case PUTFIELD:
327: case INVOKEVIRTUAL:
328: case INVOKESPECIAL:
329: case INVOKESTATIC:
330: case NEW:
331: case ANEWARRAY:
332: case CHECKCAST:
333: case INSTANCEOF:
334: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
335: classnameMap);
336: break;
337: case LDC:
338: index = code[i + 1] & 0xff;
339: index = srcCp.copy(index, destCp, classnameMap);
340: if (index < 0x100)
341: newcode[i + 1] = (byte) index;
342: else {
343: LdcEntry ldc = new LdcEntry();
344: ldc.where = i;
345: ldc.index = index;
346: ldc.next = ldcEntry;
347: ldcEntry = ldc;
348: }
349: break;
350: case INVOKEINTERFACE:
351: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
352: classnameMap);
353: newcode[i + 3] = code[i + 3];
354: newcode[i + 4] = code[i + 4];
355: break;
356: case MULTIANEWARRAY:
357: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
358: classnameMap);
359: newcode[i + 3] = code[i + 3];
360: break;
361: default:
362: while (++i < i2)
363: newcode[i] = code[i];
364:
365: break;
366: }
367: }
368:
369: return ldcEntry;
370: }
371:
372: private static void copyConstPoolInfo(int i, byte[] code,
373: ConstPool srcCp, byte[] newcode, ConstPool destCp,
374: Map classnameMap) {
375: int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff);
376: index = srcCp.copy(index, destCp, classnameMap);
377: newcode[i] = (byte) (index >> 8);
378: newcode[i + 1] = (byte) index;
379: }
380: }
381:
382: final class LdcEntry {
383: LdcEntry next;
384: int where;
385: int index;
386:
387: static byte[] doit(byte[] code, LdcEntry ldc,
388: ExceptionTable etable, CodeAttribute ca) throws BadBytecode {
389: while (ldc != null) {
390: int where = ldc.where;
391: code = CodeIterator.insertGap(code, where, 1, false,
392: etable, ca);
393: code[where] = (byte) Opcode.LDC_W;
394: ByteArray.write16bit(ldc.index, code, where + 1);
395: ldc = ldc.next;
396: }
397:
398: return code;
399: }
400: }
|