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:
022: import org.apache.harmony.pack200.Segment;
023: import org.apache.harmony.pack200.SegmentUtils;
024: import org.apache.harmony.pack200.bytecode.forms.ByteCodeForm;
025:
026: public class ByteCode extends ClassFileEntry {
027:
028: public static ByteCode getByteCode(int opcode) {
029: return new ByteCode(0xFF & opcode);
030: }
031:
032: private final ByteCodeForm byteCodeForm;
033:
034: private ClassFileEntry[] nested;
035: private int[][] nestedPositions;
036: private int[] rewrite;
037:
038: private int byteCodeOffset = -1;
039: private int[] byteCodeTargets = null;
040:
041: protected ByteCode(int opcode) {
042: this (opcode, ClassFileEntry.NONE);
043: }
044:
045: protected ByteCode(int opcode, ClassFileEntry[] nested) {
046: this .byteCodeForm = ByteCodeForm.get(opcode);
047: this .rewrite = byteCodeForm.getRewriteCopy();
048: this .nested = nested;
049: }
050:
051: protected void doWrite(DataOutputStream dos) throws IOException {
052: for (int i = 0; i < rewrite.length; i++) {
053: dos.writeByte(rewrite[i]);
054: }
055: }
056:
057: public boolean equals(Object obj) {
058: if (this == obj)
059: return true;
060: if (obj == null)
061: return false;
062: if (getClass() != obj.getClass())
063: return false;
064: final ByteCode other = (ByteCode) obj;
065: if (getByteCodeForm() != other.getByteCodeForm())
066: return false;
067: if (!rewrite.equals(other.rewrite))
068: return false;
069: return true;
070: }
071:
072: public void extractOperands(OperandManager operandManager,
073: Segment segment, int codeLength) {
074: // Given an OperandTable, figure out which operands
075: // the receiver needs and stuff them in operands.
076: // Later on the operands can be rewritten (But that's
077: // later, not now).
078: ByteCodeForm currentByteCodeForm = getByteCodeForm();
079: currentByteCodeForm.setByteCodeOperands(this , operandManager,
080: codeLength);
081: }
082:
083: protected ByteCodeForm getByteCodeForm() {
084: return byteCodeForm;
085: }
086:
087: public int getLength() {
088: return rewrite.length;
089: }
090:
091: public String getName() {
092: return getByteCodeForm().getName();
093: }
094:
095: public ClassFileEntry[] getNestedClassFileEntries() {
096: return nested;
097: }
098:
099: public int getOpcode() {
100: return getByteCodeForm().getOpcode();
101: }
102:
103: public int getOperandType() {
104: return getByteCodeForm().getOperandType();
105: }
106:
107: public int hashCode() {
108: final int prime = 31;
109: int result = 1;
110: result = prime * result + getByteCodeForm().getOpcode();
111: // Don't forget to take the operands = rewrite into account
112: for (int index = 1; index < rewrite.length; index++) {
113: result = result + rewrite[index];
114: }
115: return result;
116: }
117:
118: /* (non-Javadoc)
119: * @see org.apache.harmony.pack200.bytecode.ClassFileEntry#resolve(org.apache.harmony.pack200.bytecode.ClassConstantPool)
120: */
121: protected void resolve(ClassConstantPool pool) {
122: super .resolve(pool);
123: if (nested.length > 0) {
124: // Update the bytecode rewrite array so that it points
125: // to the elements of the nested array.
126: for (int index = 0; index < nested.length; index++) {
127: int argLength = getNestedPosition(index)[1];
128: switch (argLength) {
129:
130: case 1:
131: setOperandByte(pool.indexOf(nested[index]),
132: getNestedPosition(index)[0]);
133: break;
134:
135: case 2:
136: setOperand2Bytes(pool.indexOf(nested[index]),
137: getNestedPosition(index)[0]);
138: break;
139:
140: case 4:
141: // TODO: need to handle wides?
142: SegmentUtils.debug("Need to handle wides");
143: throw new Error("Instruction argument not handled");
144: // figure out and if so, handle and put a break here.
145: // break;
146:
147: default:
148: SegmentUtils.debug("Unhandled resolve " + this );
149: }
150: }
151: }
152: }
153:
154: /**
155: * Given an array of ints which correspond to bytes in the
156: * operand of the bytecode, set the rewrite bytes of the
157: * operand to be the appropriate values. All values in
158: * operands[] will be masked with 0xFF so they fit into
159: * a byte.
160: * @param operands int[] rewrite operand bytes
161: */
162: public void setOperandBytes(int[] operands) {
163: int firstOperandIndex = getByteCodeForm().firstOperandIndex();
164: int byteCodeFormLength = getByteCodeForm().operandLength();
165: if (firstOperandIndex < 1) {
166: // No operand rewriting permitted for this bytecode
167: throw new Error("Trying to rewrite " + this
168: + " that has no rewrite");
169: }
170:
171: if (byteCodeFormLength != operands.length) {
172: throw new Error("Trying to rewrite " + this + " with "
173: + operands.length + " but bytecode has length "
174: + byteCodeForm.operandLength());
175: }
176:
177: for (int index = 0; index < byteCodeFormLength; index++) {
178: rewrite[index + firstOperandIndex] = operands[index] & 0xFF;
179: }
180: }
181:
182: /**
183: * Given an int operand, set the rewrite bytes for
184: * that position and the one immediately following it
185: * to a high-byte, low-byte encoding of the operand.
186: *
187: * @param operand int to set the rewrite bytes to
188: * @param position int position in the operands of the
189: * rewrite bytes. For a rewrite array of {100, -1, -1, -1}
190: * position 0 is the first -1, position 1 is the second -1,
191: * etc.
192: */
193: public void setOperand2Bytes(int operand, int position) {
194: int firstOperandIndex = getByteCodeForm().firstOperandIndex();
195: int byteCodeFormLength = getByteCodeForm().getRewrite().length;
196: if (firstOperandIndex < 1) {
197: // No operand rewriting permitted for this bytecode
198: throw new Error("Trying to rewrite " + this
199: + " that has no rewrite");
200: }
201:
202: if (firstOperandIndex + position + 1 > byteCodeFormLength) {
203: throw new Error("Trying to rewrite " + this
204: + " with an int at position " + position
205: + " but this won't fit in the rewrite array");
206: }
207:
208: rewrite[firstOperandIndex + position] = (operand & 0xFF00) >> 8;
209: rewrite[firstOperandIndex + position + 1] = operand & 0xFF;
210: }
211:
212: /**
213: * This is just like setOperandInt, but takes special care when the
214: * operand is less than 0 to make sure it's written correctly.
215: * @param operand int to set the rewrite bytes to
216: * @param position int position of the operands in the rewrite bytes
217: */
218: public void setOperandSigned2Bytes(int operand, int position) {
219: if (operand >= 0) {
220: setOperand2Bytes(operand, position);
221: } else {
222: int twosComplementOperand = 0x10000 + operand;
223: setOperand2Bytes(twosComplementOperand, position);
224: }
225: }
226:
227: /**
228: * Given an int operand, treat it as a byte and set
229: * the rewrite byte for that position to that value.
230: * Mask of anything beyond 0xFF.
231: *
232: * @param operand int to set the rewrite byte to (unsigned)
233: * @param position int position in the operands of the
234: * rewrite bytes. For a rewrite array of {100, -1, -1, -1}
235: * position 0 is the first -1, position 1 is the second -1,
236: * etc.
237: */
238: public void setOperandByte(int operand, int position) {
239: int firstOperandIndex = getByteCodeForm().firstOperandIndex();
240: int byteCodeFormLength = getByteCodeForm().operandLength();
241: if (firstOperandIndex < 1) {
242: // No operand rewriting permitted for this bytecode
243: throw new Error("Trying to rewrite " + this
244: + " that has no rewrite");
245: }
246:
247: if (firstOperandIndex + position > byteCodeFormLength) {
248: throw new Error("Trying to rewrite " + this
249: + " with an byte at position " + position
250: + " but this won't fit in the rewrite array");
251: }
252:
253: rewrite[firstOperandIndex + position] = operand & 0xFF;
254: }
255:
256: public String toString() {
257: return getByteCodeForm().getName();
258: }
259:
260: public void setNested(ClassFileEntry[] nested) {
261: this .nested = nested;
262: }
263:
264: /**
265: * nestedPositions is an array of arrays of ints. Each
266: * subarray specifies a position of a nested
267: * element (from the nested[] array) and the length of
268: * that element.
269: *
270: * For instance, one might have a nested of:
271: * {CPClass java/lang/Foo, CPFloat 3.14}
272: * The nestedPositions would then be:
273: * {{0,2},{2,2}}
274: * In other words, when the bytecode is resolved, the
275: * CPClass will be resolved to an int and inserted
276: * at position 0 and 1 of the rewrite arguments (the first
277: * occurrences of -1). The CPFloat will be resolved to
278: * an int position and inserted at positions 2 and 3 of
279: * the rewrite arguments.
280: *
281: * @param nestedPositions
282: */
283: public void setNestedPositions(int[][] nestedPositions) {
284: this .nestedPositions = nestedPositions;
285: }
286:
287: public int[][] getNestedPositions() {
288: return nestedPositions;
289: }
290:
291: public int[] getNestedPosition(int index) {
292: return getNestedPositions()[index];
293: }
294:
295: /**
296: * This method will answer true if the receiver is
297: * a multi-bytecode instruction (such as
298: * aload0_putfield_super); otherwise, it will answer
299: * false.
300: *
301: * @return boolean true if multibytecode, false otherwise
302: */
303: public boolean hasMultipleByteCodes() {
304: return getByteCodeForm().hasMultipleByteCodes();
305: }
306:
307: /**
308: * ByteCodes may need to know their position in the
309: * code array (in particular, label byte codes need
310: * to know where they are in order to calculate their
311: * targets). This method lets the CodeAttribute specify
312: * where the byte code is.
313: *
314: * Since there are no aload0+label instructions, this
315: * method doesn't worry about multioperation bytecodes.
316: *
317: * @param byteCodeOffset int position in code array.
318: */
319: public void setByteCodeIndex(int byteCodeOffset) {
320: this .byteCodeOffset = byteCodeOffset;
321: }
322:
323: public int getByteCodeIndex() {
324: return byteCodeOffset;
325: }
326:
327: /**
328: * Some ByteCodes (in particular, those with labels)
329: * have to keep track of byteCodeTargets. These are
330: * initially offsets in the CodeAttribute array
331: * relative to the byteCodeOffset, but later get fixed
332: * up to point to the absolute position in the CodeAttribute
333: * array. This method sets the targets.
334: *
335: * @param byteCodeTarget int index in array
336: */
337: public void setByteCodeTargets(int[] byteCodeTargets) {
338: this .byteCodeTargets = byteCodeTargets;
339: }
340:
341: public int[] getByteCodeTargets() {
342: return byteCodeTargets;
343: }
344:
345: /**
346: * Some ByteCodes (in particular, those with labels
347: * need to be fixed up after all the bytecodes in the
348: * CodeAttribute have been added. (This can't
349: * be done beforehand because the CodeAttribute needs
350: * to be complete before targets can be assigned.)
351: */
352: public void applyByteCodeTargetFixup(CodeAttribute codeAttribute) {
353: getByteCodeForm().fixUpByteCodeTargets(this , codeAttribute);
354: }
355:
356: /**
357: * Some bytecodes (the ones with variable lengths) can't
358: * have a static rewrite array - they need the ability to
359: * update the array. This method permits that.
360: *
361: * Note that this should not be called from bytecodes
362: * which have a static rewrite; use the table in ByteCodeForm
363: * instead to specify those rewrites.
364: *
365: * @param rewrite
366: */
367: public void setRewrite(int[] rewrite) {
368: this .rewrite = rewrite;
369: }
370:
371: /**
372: * Some bytecodes (the ones with variable lengths) can't
373: * have a static rewrite array - they need the ability to
374: * update the array. This method permits their associated
375: * bytecode formst to query their rewrite array.
376: *
377: * Note that this should not be called from bytecodes
378: * which have a static rewrite; use the table in ByteCodeForm
379: * instead to specify those rewrites.
380: */
381: public int[] getRewrite() {
382: return rewrite;
383: }
384: }
|