001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.pack200.bytecode;
018:
019: import java.io.DataOutputStream;
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.apache.harmony.pack200.Segment;
026:
027: public class CodeAttribute extends BCIRenumberedAttribute {
028: public List attributes = new ArrayList();
029: // instances
030: public List byteCodeOffsets = new ArrayList();
031: public List byteCodes = new ArrayList();
032: public int codeLength;
033: public List exceptionTable; // of ExceptionTableEntry
034: public int maxLocals;
035: public int maxStack;
036:
037: public CodeAttribute(int maxStack, int maxLocals,
038: byte codePacked[], Segment segment,
039: OperandManager operandManager, List exceptionTable) {
040: super ("Code"); //$NON-NLS-1$
041: this .maxLocals = maxLocals;
042: this .maxStack = maxStack;
043: this .codeLength = 0;
044: this .exceptionTable = exceptionTable;
045: byteCodeOffsets.add(new Integer(0));
046: int byteCodeIndex = 0;
047: for (int i = 0; i < codePacked.length; i++) {
048: ByteCode byteCode = ByteCode
049: .getByteCode(codePacked[i] & 0xff);
050: // Setting the offset must happen before extracting operands
051: // because label bytecodes need to know their offsets.
052: byteCode.setByteCodeIndex(byteCodeIndex);
053: byteCodeIndex++;
054: byteCode.extractOperands(operandManager, segment,
055: codeLength);
056: byteCodes.add(byteCode);
057: codeLength += byteCode.getLength();
058: int lastBytecodePosition = ((Integer) byteCodeOffsets
059: .get(byteCodeOffsets.size() - 1)).intValue();
060: // This code assumes all multiple byte bytecodes are
061: // replaced by a single-byte bytecode followed by
062: // another bytecode.
063: if (byteCode.hasMultipleByteCodes()) {
064: byteCodeOffsets.add(new Integer(
065: lastBytecodePosition + 1));
066: byteCodeIndex++;
067: }
068: // I've already added the first element (at 0) before
069: // entering this loop, so make sure I don't add one
070: // after the last element.
071: if (i < (codePacked.length - 1)) {
072: byteCodeOffsets.add(new Integer(lastBytecodePosition
073: + byteCode.getLength()));
074: }
075: if (byteCode.getOpcode() == 0xC4) {
076: // Special processing for wide bytecode - it knows what its
077: // instruction is from the opcode manager, so ignore the
078: // next instruction
079: i++;
080: }
081: }
082: // Now that all the bytecodes know their positions and
083: // sizes, fix up the byte code targets
084: // At this point, byteCodes may be a different size than
085: // codePacked because of wide bytecodes.
086: for (int i = 0; i < byteCodes.size(); i++) {
087: ByteCode byteCode = (ByteCode) byteCodes.get(i);
088: byteCode.applyByteCodeTargetFixup(this );
089: }
090: }
091:
092: protected int getLength() {
093: int attributesSize = 0;
094: Iterator it = attributes.iterator();
095: while (it.hasNext()) {
096: Attribute attribute = (Attribute) it.next();
097: attributesSize += attribute.getLengthIncludingHeader();
098: }
099: return 2 + 2 + 4 + codeLength + 2 + exceptionTable.size()
100: * (2 + 2 + 2 + 2) + 2 + attributesSize;
101: }
102:
103: protected ClassFileEntry[] getNestedClassFileEntries() {
104: ArrayList nestedEntries = new ArrayList();
105: nestedEntries.add(getAttributeName());
106: nestedEntries.addAll(byteCodes);
107: // TODO: Is this the right place to add code attribute
108: // attributes?
109: nestedEntries.addAll(attributes);
110: ClassFileEntry[] nestedEntryArray = new ClassFileEntry[nestedEntries
111: .size()];
112: nestedEntries.toArray(nestedEntryArray);
113: return nestedEntryArray;
114: }
115:
116: protected void resolve(ClassConstantPool pool) {
117: super .resolve(pool);
118: Iterator it = attributes.iterator();
119: while (it.hasNext()) {
120: Attribute attribute = (Attribute) it.next();
121: attribute.resolve(pool);
122: }
123: it = byteCodes.iterator();
124: while (it.hasNext()) {
125: ByteCode byteCode = (ByteCode) it.next();
126: byteCode.resolve(pool);
127: }
128: for (Iterator iter = exceptionTable.iterator(); iter.hasNext();) {
129: ExceptionTableEntry entry = (ExceptionTableEntry) iter
130: .next();
131: entry.resolve(pool);
132: }
133: }
134:
135: public String toString() {
136: return "Code: " + getLength() + " bytes";
137: }
138:
139: protected void writeBody(DataOutputStream dos) throws IOException {
140: dos.writeShort(maxStack);
141: dos.writeShort(maxLocals);
142: dos.writeInt(codeLength);
143: Iterator it = byteCodes.iterator();
144: while (it.hasNext()) {
145: ByteCode byteCode = (ByteCode) it.next();
146: byteCode.write(dos);
147: }
148: dos.writeShort(exceptionTable.size());
149: Iterator exceptionTableEntries = exceptionTable.iterator();
150: while (exceptionTableEntries.hasNext()) {
151: ExceptionTableEntry entry = (ExceptionTableEntry) exceptionTableEntries
152: .next();
153: entry.write(dos);
154: }
155: dos.writeShort(attributes.size());
156: it = attributes.iterator();
157: while (it.hasNext()) {
158: Attribute attribute = (Attribute) it.next();
159: attribute.write(dos);
160: }
161: }
162:
163: public void addAttribute(Attribute attribute) {
164: attributes.add(attribute);
165: }
166:
167: public List attributes() {
168: return attributes;
169: }
170:
171: protected int[] getStartPCs() {
172: // Do nothing here as we've overriden renumber
173: return null;
174: }
175:
176: public void renumber(List byteCodeOffsets) {
177: for (Iterator iter = exceptionTable.iterator(); iter.hasNext();) {
178: ExceptionTableEntry entry = (ExceptionTableEntry) iter
179: .next();
180: entry.renumber(byteCodeOffsets);
181: }
182: }
183: }
|