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
24 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
25 import org.apache.commons.compress.harmony.unpack200.Segment;
26 import org.apache.commons.compress.harmony.unpack200.bytecode.forms.ByteCodeForm;
27
28
29
30
31 public class ByteCode extends ClassFileEntry {
32
33 private static ByteCode[] noArgByteCodes = new ByteCode[255];
34
35 public static ByteCode getByteCode(final int opcode) {
36 final int byteOpcode = 0xFF & opcode;
37 if (ByteCodeForm.get(byteOpcode).hasNoOperand()) {
38 if (null == noArgByteCodes[byteOpcode]) {
39 noArgByteCodes[byteOpcode] = new ByteCode(byteOpcode);
40 }
41 return noArgByteCodes[byteOpcode];
42 }
43 return new ByteCode(byteOpcode);
44 }
45
46 private final ByteCodeForm byteCodeForm;
47
48 private ClassFileEntry[] nested;
49 private int[][] nestedPositions;
50 private int[] rewrite;
51
52 private int byteCodeOffset = -1;
53 private int[] byteCodeTargets;
54
55 protected ByteCode(final int opcode) {
56 this(opcode, NONE);
57 }
58
59 protected ByteCode(final int opcode, final ClassFileEntry[] nested) {
60 this.byteCodeForm = ByteCodeForm.get(opcode);
61 this.rewrite = byteCodeForm.getRewriteCopy();
62 this.nested = nested;
63 }
64
65
66
67
68
69
70
71 public void applyByteCodeTargetFixup(final CodeAttribute codeAttribute) {
72 getByteCodeForm().fixUpByteCodeTargets(this, codeAttribute);
73 }
74
75 @Override
76 protected void doWrite(final DataOutputStream dos) throws IOException {
77 for (final int element : rewrite) {
78 dos.writeByte(element);
79 }
80 }
81
82 @Override
83 public boolean equals(final Object obj) {
84 return this == obj;
85 }
86
87 public void extractOperands(final OperandManager operandManager, final Segment segment, final int codeLength) throws Pack200Exception {
88
89
90
91
92 getByteCodeForm().setByteCodeOperands(this, operandManager, codeLength);
93 }
94
95 protected ByteCodeForm getByteCodeForm() {
96 return byteCodeForm;
97 }
98
99 public int getByteCodeIndex() {
100 return byteCodeOffset;
101 }
102
103 public int[] getByteCodeTargets() {
104 return byteCodeTargets;
105 }
106
107 public int getLength() {
108 return rewrite.length;
109 }
110
111 public String getName() {
112 return getByteCodeForm().getName();
113 }
114
115 @Override
116 public ClassFileEntry[] getNestedClassFileEntries() {
117 return nested;
118 }
119
120 public int[] getNestedPosition(final int index) {
121 return getNestedPositions()[index];
122 }
123
124 public int[][] getNestedPositions() {
125 return nestedPositions;
126 }
127
128 public int getOpcode() {
129 return getByteCodeForm().getOpcode();
130 }
131
132
133
134
135
136
137
138
139
140 public int[] getRewrite() {
141 return rewrite;
142 }
143
144 @Override
145 public int hashCode() {
146 return objectHashCode();
147 }
148
149
150
151
152
153
154 public boolean hasMultipleByteCodes() {
155 return getByteCodeForm().hasMultipleByteCodes();
156 }
157
158 public boolean nestedMustStartClassPool() {
159 return byteCodeForm.nestedMustStartClassPool();
160 }
161
162
163
164
165
166
167
168 @Override
169 protected void resolve(final ClassConstantPool pool) {
170 super.resolve(pool);
171 if (nested.length > 0) {
172
173
174 for (int index = 0; index < nested.length; index++) {
175 final int argLength = getNestedPosition(index)[1];
176 switch (argLength) {
177
178 case 1:
179 setOperandByte(pool.indexOf(nested[index]), getNestedPosition(index)[0]);
180 break;
181
182 case 2:
183 setOperand2Bytes(pool.indexOf(nested[index]), getNestedPosition(index)[0]);
184 break;
185
186 default:
187 throw new Error("Unhandled resolve " + this);
188 }
189 }
190 }
191 }
192
193
194
195
196
197
198
199
200
201 public void setByteCodeIndex(final int byteCodeOffset) {
202 this.byteCodeOffset = byteCodeOffset;
203 }
204
205
206
207
208
209
210
211 public void setByteCodeTargets(final int[] byteCodeTargets) {
212 this.byteCodeTargets = byteCodeTargets;
213 }
214
215 public void setNested(final ClassFileEntry[] nested) {
216 this.nested = nested;
217 }
218
219
220
221
222
223
224
225
226
227
228
229 public void setNestedPositions(final int[][] nestedPositions) {
230 this.nestedPositions = nestedPositions;
231 }
232
233
234
235
236
237
238
239
240 public void setOperand2Bytes(final int operand, final int position) {
241 final int firstOperandIndex = getByteCodeForm().firstOperandIndex();
242 final int byteCodeFormLength = getByteCodeForm().getRewrite().length;
243 if (firstOperandIndex < 1) {
244
245 throw new Error("Trying to rewrite " + this + " that has no rewrite");
246 }
247
248 if (firstOperandIndex + position + 1 > byteCodeFormLength) {
249 throw new Error("Trying to rewrite " + this + " with an int at position " + position + " but this won't fit in the rewrite array");
250 }
251
252 rewrite[firstOperandIndex + position] = (operand & 0xFF00) >> 8;
253 rewrite[firstOperandIndex + position + 1] = operand & 0xFF;
254 }
255
256
257
258
259
260
261
262
263 public void setOperandByte(final int operand, final int position) {
264 final int firstOperandIndex = getByteCodeForm().firstOperandIndex();
265 final int byteCodeFormLength = getByteCodeForm().operandLength();
266 if (firstOperandIndex < 1) {
267
268 throw new Error("Trying to rewrite " + this + " that has no rewrite");
269 }
270
271 if (firstOperandIndex + position > byteCodeFormLength) {
272 throw new Error("Trying to rewrite " + this + " with an byte at position " + position + " but this won't fit in the rewrite array");
273 }
274
275 rewrite[firstOperandIndex + position] = operand & 0xFF;
276 }
277
278
279
280
281
282
283
284 public void setOperandBytes(final int[] operands) {
285 final int firstOperandIndex = getByteCodeForm().firstOperandIndex();
286 final int byteCodeFormLength = getByteCodeForm().operandLength();
287 if (firstOperandIndex < 1) {
288
289 throw new Error("Trying to rewrite " + this + " that has no rewrite");
290 }
291
292 if (byteCodeFormLength != operands.length) {
293 throw new Error("Trying to rewrite " + this + " with " + operands.length + " but bytecode has length " + byteCodeForm.operandLength());
294 }
295
296 for (int index = 0; index < byteCodeFormLength; index++) {
297 rewrite[index + firstOperandIndex] = operands[index] & 0xFF;
298 }
299 }
300
301
302
303
304
305
306
307 public void setOperandSigned2Bytes(final int operand, final int position) {
308 if (operand >= 0) {
309 setOperand2Bytes(operand, position);
310 } else {
311 final int twosComplementOperand = 0x10000 + operand;
312 setOperand2Bytes(twosComplementOperand, position);
313 }
314 }
315
316
317
318
319
320
321
322
323 public void setRewrite(final int[] rewrite) {
324 this.rewrite = rewrite;
325 }
326
327 @Override
328 public String toString() {
329 return getByteCodeForm().getName();
330 }
331 }