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