1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.harmony.unpack200.bytecode;
18
19 import java.io.DataOutputStream;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import org.apache.commons.compress.harmony.unpack200.Segment;
25
26 public class CodeAttribute extends BCIRenumberedAttribute {
27
28 private static CPUTF8 attributeName;
29
30 public static void setAttributeName(final CPUTF8 attributeName) {
31 CodeAttribute.attributeName = attributeName;
32 }
33
34 public List<Attribute> attributes = new ArrayList<>();
35
36 public List<Integer> byteCodeOffsets = new ArrayList<>();
37 public List<ByteCode> byteCodes = new ArrayList<>();
38 public int codeLength;
39 public List<ExceptionTableEntry> exceptionTable;
40 public int maxLocals;
41
42 public int maxStack;
43
44 public CodeAttribute(final int maxStack, final int maxLocals, final byte[] codePacked, final Segment segment, final OperandManager operandManager,
45 final List<ExceptionTableEntry> exceptionTable) {
46 super(attributeName);
47 this.maxLocals = maxLocals;
48 this.maxStack = maxStack;
49 this.codeLength = 0;
50 this.exceptionTable = exceptionTable;
51 byteCodeOffsets.add(Integer.valueOf(0));
52 int byteCodeIndex = 0;
53 for (int i = 0; i < codePacked.length; i++) {
54 final ByteCode byteCode = ByteCode.getByteCode(codePacked[i] & 0xff);
55
56
57 byteCode.setByteCodeIndex(byteCodeIndex);
58 byteCodeIndex++;
59 byteCode.extractOperands(operandManager, segment, codeLength);
60 byteCodes.add(byteCode);
61 codeLength += byteCode.getLength();
62 final int lastBytecodePosition = byteCodeOffsets.get(byteCodeOffsets.size() - 1).intValue();
63
64
65
66 if (byteCode.hasMultipleByteCodes()) {
67 byteCodeOffsets.add(Integer.valueOf(lastBytecodePosition + 1));
68 byteCodeIndex++;
69 }
70
71
72
73 if (i < codePacked.length - 1) {
74 byteCodeOffsets.add(Integer.valueOf(lastBytecodePosition + byteCode.getLength()));
75 }
76 if (byteCode.getOpcode() == 0xC4) {
77
78
79
80 i++;
81 }
82 }
83
84
85
86
87 for (final ByteCode byteCode : byteCodes) {
88 byteCode.applyByteCodeTargetFixup(this);
89 }
90 }
91
92 public void addAttribute(final Attribute attribute) {
93 attributes.add(attribute);
94 if (attribute instanceof LocalVariableTableAttribute) {
95 ((LocalVariableTableAttribute) attribute).setCodeLength(codeLength);
96 }
97 if (attribute instanceof LocalVariableTypeTableAttribute) {
98 ((LocalVariableTypeTableAttribute) attribute).setCodeLength(codeLength);
99 }
100 }
101
102 @Override
103 protected int getLength() {
104 int attributesSize = 0;
105 for (final Attribute attribute : attributes) {
106 attributesSize += attribute.getLengthIncludingHeader();
107 }
108 return 2 + 2 + 4 + codeLength + 2 + exceptionTable.size() * (2 + 2 + 2 + 2) + 2 + attributesSize;
109 }
110
111 @Override
112 protected ClassFileEntry[] getNestedClassFileEntries() {
113 final List<ClassFileEntry> nestedEntries = new ArrayList<>(attributes.size() + byteCodes.size() + 10);
114 nestedEntries.add(getAttributeName());
115 nestedEntries.addAll(byteCodes);
116 nestedEntries.addAll(attributes);
117
118 for (final ExceptionTableEntry entry : exceptionTable) {
119 final CPClass catchType = entry.getCatchType();
120
121
122
123 if (catchType != null) {
124 nestedEntries.add(catchType);
125 }
126 }
127 return nestedEntries.toArray(NONE);
128 }
129
130 @Override
131 protected int[] getStartPCs() {
132
133 return null;
134 }
135
136 @Override
137 public void renumber(final List<Integer> byteCodeOffsets) {
138 exceptionTable.forEach(entry -> entry.renumber(byteCodeOffsets));
139 }
140
141 @Override
142 protected void resolve(final ClassConstantPool pool) {
143 super.resolve(pool);
144 attributes.forEach(attribute -> attribute.resolve(pool));
145 byteCodes.forEach(byteCode -> byteCode.resolve(pool));
146 exceptionTable.forEach(byteCode -> byteCode.resolve(pool));
147 }
148
149 @Override
150 public String toString() {
151 return "Code: " + getLength() + " bytes";
152 }
153
154 @Override
155 protected void writeBody(final DataOutputStream dos) throws IOException {
156 dos.writeShort(maxStack);
157 dos.writeShort(maxLocals);
158
159 dos.writeInt(codeLength);
160 for (final ByteCode byteCode : byteCodes) {
161 byteCode.write(dos);
162 }
163
164 dos.writeShort(exceptionTable.size());
165 for (final ExceptionTableEntry entry : exceptionTable) {
166 entry.write(dos);
167 }
168
169 dos.writeShort(attributes.size());
170 for (final Attribute attribute : attributes) {
171 attribute.write(dos);
172 }
173 }
174 }