001: /*
002: * Copyright 2004 Brian S O'Neill
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.cojen.classfile.attribute;
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Set;
025: import java.io.DataInput;
026: import java.io.DataOutput;
027: import java.io.IOException;
028: import org.cojen.classfile.Attribute;
029: import org.cojen.classfile.ConstantPool;
030: import org.cojen.classfile.FixedLocation;
031: import org.cojen.classfile.LocalVariable;
032: import org.cojen.classfile.Location;
033: import org.cojen.classfile.LocationRange;
034: import org.cojen.classfile.LocationRangeImpl;
035: import org.cojen.classfile.TypeDesc;
036: import org.cojen.classfile.constant.ConstantUTFInfo;
037:
038: /**
039: * This class corresponds to the LocalVariableTable_attribute structure as
040: * defined in section 4.7.7 of <i>The Java Virtual Machine Specification</i>.
041: *
042: * @author Brian S O'Neill
043: */
044: public class LocalVariableTableAttr extends Attribute {
045:
046: private List mEntries = new ArrayList(10);
047: private List mCleanEntries;
048: private int mRangeCount;
049:
050: public LocalVariableTableAttr(ConstantPool cp) {
051: super (cp, LOCAL_VARIABLE_TABLE);
052: }
053:
054: public LocalVariableTableAttr(ConstantPool cp, String name) {
055: super (cp, name);
056: }
057:
058: public LocalVariableTableAttr(ConstantPool cp, String name,
059: int length, DataInput din) throws IOException {
060: super (cp, name);
061:
062: int size = din.readUnsignedShort();
063: for (int i = 0; i < size; i++) {
064: int start_pc = din.readUnsignedShort();
065: int end_pc = start_pc + din.readUnsignedShort() + 1;
066: int name_index = din.readUnsignedShort();
067: int descriptor_index = din.readUnsignedShort();
068: final int index = din.readUnsignedShort();
069:
070: final ConstantUTFInfo varName = (ConstantUTFInfo) cp
071: .getConstant(name_index);
072: final ConstantUTFInfo varDesc = (ConstantUTFInfo) cp
073: .getConstant(descriptor_index);
074:
075: final Location startLocation = new FixedLocation(start_pc);
076: final Location endLocation = new FixedLocation(end_pc);
077:
078: Set ranges = new HashSet();
079: ranges
080: .add(new LocationRangeImpl(startLocation,
081: endLocation));
082: final Set fRanges = Collections.unmodifiableSet(ranges);
083:
084: LocalVariable localVar = new LocalVariable() {
085: private String mName;
086: private TypeDesc mType;
087:
088: {
089: mName = varName.getValue();
090: mType = TypeDesc.forDescriptor(varDesc.getValue());
091: }
092:
093: public String getName() {
094: return mName;
095: }
096:
097: public void setName(String name) {
098: mName = name;
099: }
100:
101: public TypeDesc getType() {
102: return mType;
103: }
104:
105: public boolean isDoubleWord() {
106: return mType.isDoubleWord();
107: }
108:
109: public int getNumber() {
110: return index;
111: }
112:
113: public Set getLocationRangeSet() {
114: return fRanges;
115: }
116: };
117:
118: mEntries.add(new Entry(localVar, varName, varDesc));
119: }
120: }
121:
122: /**
123: * Add an entry into the LocalVariableTableAttr.
124: */
125: public void addEntry(LocalVariable localVar) {
126: String varName = localVar.getName();
127: if (varName != null) {
128: ConstantUTFInfo name = getConstantPool().addConstantUTF(
129: varName);
130: ConstantUTFInfo descriptor = getConstantPool()
131: .addConstantUTF(localVar.getType().getDescriptor());
132: mEntries.add(new Entry(localVar, name, descriptor));
133: }
134:
135: mCleanEntries = null;
136: }
137:
138: public int getLength() {
139: clean();
140: return 2 + 10 * mRangeCount;
141: }
142:
143: public void writeDataTo(DataOutput dout) throws IOException {
144: dout.writeShort(mRangeCount);
145:
146: int size = mCleanEntries.size();
147: for (int i = 0; i < size; i++) {
148: Entry entry = (Entry) mEntries.get(i);
149: LocalVariable localVar = entry.mLocalVar;
150:
151: Set ranges = localVar.getLocationRangeSet();
152: if (ranges == null) {
153: continue;
154: }
155:
156: int name_index = entry.mName.getIndex();
157: int descriptor_index = entry.mDescriptor.getIndex();
158: int index = localVar.getNumber();
159:
160: check("local variable table entry name index", name_index);
161: check("local variable table entry descriptor index",
162: descriptor_index);
163: check("local variable table entry index", index);
164:
165: Iterator it = ranges.iterator();
166: while (it.hasNext()) {
167: LocationRange range = (LocationRange) it.next();
168:
169: Location startLocation = range.getStartLocation();
170: Location endLocation = range.getEndLocation();
171:
172: int start_pc = startLocation.getLocation();
173: int length = endLocation.getLocation() - start_pc - 1;
174:
175: check("local variable table entry start PC", start_pc);
176:
177: dout.writeShort(start_pc);
178: dout.writeShort(length);
179: dout.writeShort(name_index);
180: dout.writeShort(descriptor_index);
181: dout.writeShort(index);
182: }
183: }
184: }
185:
186: private void check(String type, int addr)
187: throws IllegalStateException {
188: if (addr < 0 || addr > 65535) {
189: throw new IllegalStateException("Value for " + type
190: + " out of " + "valid range: " + addr);
191: }
192: }
193:
194: private void clean() {
195: if (mCleanEntries != null) {
196: return;
197: }
198:
199: // Clean out entries that are incomplete or bogus.
200:
201: int size = mEntries.size();
202: mCleanEntries = new ArrayList(size);
203: mRangeCount = 0;
204:
205: outer: for (int i = 0; i < size; i++) {
206: Entry entry = (Entry) mEntries.get(i);
207: LocalVariable localVar = entry.mLocalVar;
208:
209: Set ranges = localVar.getLocationRangeSet();
210: if (ranges == null || ranges.size() == 0) {
211: continue;
212: }
213:
214: Iterator it = ranges.iterator();
215: while (it.hasNext()) {
216: LocationRange range = (LocationRange) it.next();
217:
218: Location startLocation = range.getStartLocation();
219: Location endLocation = range.getEndLocation();
220:
221: if (startLocation == null || endLocation == null) {
222: continue outer;
223: }
224:
225: int start_pc = startLocation.getLocation();
226: int length = endLocation.getLocation() - start_pc - 1;
227:
228: if (length < 0) {
229: continue outer;
230: }
231: }
232:
233: mCleanEntries.add(entry);
234: mRangeCount += entry.getRangeCount();
235: }
236: }
237:
238: private static class Entry {
239: public LocalVariable mLocalVar;
240: public ConstantUTFInfo mName;
241: public ConstantUTFInfo mDescriptor;
242:
243: public Entry(LocalVariable localVar, ConstantUTFInfo name,
244: ConstantUTFInfo descriptor) {
245:
246: mLocalVar = localVar;
247: mName = name;
248: mDescriptor = descriptor;
249: }
250:
251: public int getRangeCount() {
252: return mLocalVar.getLocationRangeSet().size();
253: }
254: }
255: }
|