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