KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > attribute > CodeAttr


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile.attribute;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21 import java.io.DataInput JavaDoc;
22 import java.io.DataOutput JavaDoc;
23 import java.io.IOException JavaDoc;
24 import org.cojen.classfile.Attribute;
25 import org.cojen.classfile.AttributeFactory;
26 import org.cojen.classfile.CodeBuffer;
27 import org.cojen.classfile.ConstantPool;
28 import org.cojen.classfile.ExceptionHandler;
29 import org.cojen.classfile.LocalVariable;
30 import org.cojen.classfile.Location;
31
32 /**
33  * This class corresponds to the Code_attribute structure as defined in
34  * section 4.7.4 of <i>The Java Virtual Machine Specification</i>.
35  * To make it easier to create bytecode for the CodeAttr, use the
36  * CodeBuilder.
37  *
38  * @author Brian S O'Neill
39  * @see cojen.classfile.Opcode
40  * @see cojen.classfile.CodeBuilder
41  */

42 public class CodeAttr extends Attribute {
43
44     private CodeBuffer mCodeBuffer;
45     private List JavaDoc mAttributes = new ArrayList JavaDoc(2);
46     
47     private LineNumberTableAttr mLineNumberTable;
48     private LocalVariableTableAttr mLocalVariableTable;
49
50     private LineNumberTableAttr mOldLineNumberTable;
51     private LocalVariableTableAttr mOldLocalVariableTable;
52
53     public CodeAttr(ConstantPool cp) {
54         super(cp, CODE);
55     }
56
57     public CodeAttr(ConstantPool cp, String JavaDoc name) {
58         super(cp, name);
59     }
60     
61     public CodeAttr(ConstantPool cp, String JavaDoc name, int length,
62                     DataInput JavaDoc din, AttributeFactory attrFactory)
63         throws IOException JavaDoc
64     {
65         super(cp, name);
66
67         final int maxStackDepth = din.readUnsignedShort();
68         final int maxLocals = din.readUnsignedShort();
69
70         final byte[] byteCodes = new byte[din.readInt()];
71         din.readFully(byteCodes);
72
73         int exceptionHandlerCount = din.readUnsignedShort();
74         final ExceptionHandler[] handlers =
75             new ExceptionHandler[exceptionHandlerCount];
76
77         for (int i=0; i<exceptionHandlerCount; i++) {
78             handlers[i] = ExceptionHandler.readFrom(cp, din);
79         }
80         
81         mCodeBuffer = new CodeBuffer() {
82             public int getMaxStackDepth() {
83                 return maxStackDepth;
84             }
85             
86             public int getMaxLocals() {
87                 return maxLocals;
88             }
89             
90             public byte[] getByteCodes() {
91                 return (byte[])byteCodes.clone();
92             }
93             
94             public ExceptionHandler[] getExceptionHandlers() {
95                 return (ExceptionHandler[])handlers.clone();
96             }
97         };
98
99         int attributeCount = din.readUnsignedShort();
100         for (int i=0; i<attributeCount; i++) {
101             addAttribute(Attribute.readFrom(cp, din, attrFactory));
102         }
103     }
104
105     /**
106      * Returns null if no CodeBuffer is defined for this CodeAttr.
107      */

108     public CodeBuffer getCodeBuffer() {
109         return mCodeBuffer;
110     }
111
112     /**
113      * As a side effect of calling this method, new line number and local
114      * variable tables are created.
115      */

116     public void setCodeBuffer(CodeBuffer code) {
117         mCodeBuffer = code;
118         mOldLineNumberTable = mLineNumberTable;
119         mOldLocalVariableTable = mLocalVariableTable;
120         mAttributes.remove(mLineNumberTable);
121         mAttributes.remove(mLocalVariableTable);
122         mLineNumberTable = null;
123         mLocalVariableTable = null;
124     }
125     
126     /**
127      * Returns the line number in the source code from the given bytecode
128      * address (start_pc).
129      *
130      * @return -1 if no line number is mapped for the start_pc.
131      */

132     public int getLineNumber(Location start) {
133         LineNumberTableAttr table = mOldLineNumberTable;
134         if (table == null) {
135             table = mLineNumberTable;
136         }
137
138         if (table == null || start.getLocation() < 0) {
139             return -1;
140         } else {
141             return table.getLineNumber(start);
142         }
143     }
144
145     /**
146      * Map a bytecode address (start_pc) to a line number in the source code
147      * as a debugging aid.
148      */

149     public void mapLineNumber(Location start, int line_number) {
150         if (mLineNumberTable == null) {
151             addAttribute(new LineNumberTableAttr(getConstantPool()));
152         }
153         mLineNumberTable.addEntry(start, line_number);
154     }
155
156     /**
157      * Indicate a local variable's use information be recorded in the
158      * ClassFile as a debugging aid. If the LocalVariable doesn't provide
159      * both a start and end location, then its information is not recorded.
160      * This method should be called at most once per LocalVariable instance.
161      */

162     public void localVariableUse(LocalVariable localVar) {
163         if (mLocalVariableTable == null) {
164             addAttribute(new LocalVariableTableAttr(getConstantPool()));
165         }
166         mLocalVariableTable.addEntry(localVar);
167     }
168
169     public void addAttribute(Attribute attr) {
170         if (attr instanceof LineNumberTableAttr) {
171             if (mLineNumberTable != null) {
172                 mAttributes.remove(mLineNumberTable);
173             }
174             mLineNumberTable = (LineNumberTableAttr)attr;
175         } else if (attr instanceof LocalVariableTableAttr) {
176             if (mLocalVariableTable != null) {
177                 mAttributes.remove(mLocalVariableTable);
178             }
179             mLocalVariableTable = (LocalVariableTableAttr)attr;
180         }
181
182         mAttributes.add(attr);
183     }
184     
185     public Attribute[] getAttributes() {
186         Attribute[] attrs = new Attribute[mAttributes.size()];
187         return (Attribute[])mAttributes.toArray(attrs);
188     }
189
190     /**
191      * Returns the length (in bytes) of this object in the class file.
192      */

193     public int getLength() {
194         int length = 12;
195
196         if (mCodeBuffer != null) {
197             length += mCodeBuffer.getByteCodes().length;
198             ExceptionHandler[] handlers = mCodeBuffer.getExceptionHandlers();
199             if (handlers != null) {
200                 length += 8 * handlers.length;
201             }
202         }
203         
204         int size = mAttributes.size();
205         for (int i=0; i<size; i++) {
206             length += ((Attribute)mAttributes.get(i)).getLength();
207             length += 6; // attributes have an intial 6 byte length
208
}
209         
210         return length;
211     }
212
213     public void writeDataTo(DataOutput JavaDoc dout) throws IOException JavaDoc {
214         if (mCodeBuffer == null) {
215             throw new IllegalStateException JavaDoc("CodeAttr has no CodeBuffer set");
216         }
217
218         ExceptionHandler[] handlers = mCodeBuffer.getExceptionHandlers();
219         
220         dout.writeShort(mCodeBuffer.getMaxStackDepth());
221         dout.writeShort(mCodeBuffer.getMaxLocals());
222         
223         byte[] byteCodes = mCodeBuffer.getByteCodes();
224         dout.writeInt(byteCodes.length);
225         dout.write(byteCodes);
226
227         if (handlers != null) {
228             int exceptionHandlerCount = handlers.length;
229             dout.writeShort(exceptionHandlerCount);
230
231             for (int i=0; i<exceptionHandlerCount; i++) {
232                 handlers[i].writeTo(dout);
233             }
234         } else {
235             dout.writeShort(0);
236         }
237         
238         int size = mAttributes.size();
239         dout.writeShort(size);
240         for (int i=0; i<size; i++) {
241             Attribute attr = (Attribute)mAttributes.get(i);
242             attr.writeTo(dout);
243         }
244
245         mOldLineNumberTable = null;
246         mOldLocalVariableTable = null;
247     }
248 }
249
Popular Tags