Package org.apache.harmony.pack200.bytecode

Source Code of org.apache.harmony.pack200.bytecode.ByteCode

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.harmony.pack200.bytecode;

import java.io.DataOutputStream;
import java.io.IOException;

import org.apache.harmony.pack200.Segment;
import org.apache.harmony.pack200.SegmentUtils;
import org.apache.harmony.pack200.bytecode.forms.ByteCodeForm;

public class ByteCode extends ClassFileEntry {

  public static ByteCode getByteCode(int opcode) {
    return new ByteCode(0xFF & opcode);
  }

  private final ByteCodeForm byteCodeForm;

  private ClassFileEntry[] nested;
  private int[][] nestedPositions;
  private int[] rewrite;

    private int byteCodeOffset = -1;
    private int byteCodeTarget = -1;

  protected ByteCode(int opcode) {
    this(opcode, ClassFileEntry.NONE);
  }

  protected ByteCode(int opcode, ClassFileEntry[] nested) {
    this.byteCodeForm = ByteCodeForm.get(opcode);
    this.rewrite = byteCodeForm.getRewriteCopy();
    this.nested = nested;
  }

  protected void doWrite(DataOutputStream dos) throws IOException {
    for (int i = 0; i < rewrite.length; i++) {
      dos.writeByte(rewrite[i]);
    }
  }

  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    final ByteCode other = (ByteCode) obj;
    if (getByteCodeForm() != other.getByteCodeForm())
      return false;
    if (!rewrite.equals(other.rewrite))
      return false;
    return true;
  }

  public void extractOperands(OperandManager operandManager, Segment segment) {
    // Given an OperandTable, figure out which operands
    // the receiver needs and stuff them in operands.
    // Later on the operands can be rewritten (But that's
    // later, not now).

    ByteCodeForm currentByteCodeForm = getByteCodeForm();
    currentByteCodeForm.setByteCodeOperands(this, operandManager);
  }

  protected ByteCodeForm getByteCodeForm() {
    return byteCodeForm;
  }

  public int getLength() {
    return rewrite.length;
  }

  public String getName() {
    return getByteCodeForm().getName();
  }

  public ClassFileEntry[] getNestedClassFileEntries() {
    return nested;
  }

  public int getOpcode() {
    return getByteCodeForm().getOpcode();
  }

  public int getOperandType() {
    return getByteCodeForm().getOperandType();
  }

  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + getByteCodeForm().getOpcode();
    // Don't forget to take the operands = rewrite into account
    for (int index = 1; index < rewrite.length; index++) {
      result = result + rewrite[index];
    }
    return result;
  }

  /* (non-Javadoc)
   * @see org.apache.harmony.pack200.bytecode.ClassFileEntry#resolve(org.apache.harmony.pack200.bytecode.ClassConstantPool)
   */
  protected void resolve(ClassConstantPool pool) {
    super.resolve(pool);
    if(nested.length > 0) {
      // Update the bytecode rewrite array so that it points
      // to the elements of the nested array.
      for(int index = 0; index < nested.length; index++) {
        int argLength = getNestedPosition(index)[1];
        switch(argLength) {
       
        case 1:
          setOperandByte(pool.indexOf(nested[index]), getNestedPosition(index)[0]);
          break;
         
        case 2:
          setOperandInt(pool.indexOf(nested[index]), getNestedPosition(index)[0]);
          break;
       
        case 4:
          // TODO: need to handle wides?
          SegmentUtils.debug("Need to handle wides");
          // figure out and if so, handle and put a break here.
          // break;
       
        default:
          SegmentUtils.debug("Unhandled resolve " + this);
        }
      }
    }
  }


  /**
   * Given an array of ints which correspond to bytes in the
   * operand of the bytecode, set the rewrite bytes of the
   * operand to be the appropriate values. All values in
   * operands[] will be masked with 0xFF so they fit into
   * a byte.
   * @param operands int[] rewrite operand bytes
   */
  public void setOperandBytes(int[] operands) {
    int firstOperandIndex = getByteCodeForm().firstOperandIndex();
    int byteCodeFormLength = getByteCodeForm().operandLength();
    if (firstOperandIndex < 1) {
      // No operand rewriting permitted for this bytecode
      throw new Error("Trying to rewrite " + this + " that has no rewrite");
    }
   
    if(byteCodeFormLength != operands.length) {
      throw new Error("Trying to rewrite " + this + " with " + operands.length + " but bytecode has length " + byteCodeForm.operandLength());
    }
   
    for(int index=0; index < byteCodeFormLength; index++) {
      rewrite[index + firstOperandIndex] = operands[index] & 0xFF;
    }
  }
 
  /**
   * Given an int operand, set the rewrite bytes for
   * that position and the one immediately following it
   * to a high-byte, low-byte encoding of the operand.
   *
   * @param operand int to set the rewrite bytes to
   * @param position int position in the operands of the
   *   rewrite bytes. For a rewrite array of {100, -1, -1, -1}
   *  position 0 is the first -1, position 1 is the second -1,
   *  etc.
   */
  public void setOperandInt(int operand, int position) {
    int firstOperandIndex = getByteCodeForm().firstOperandIndex();
    int byteCodeFormLength = getByteCodeForm().getRewrite().length;
    if (firstOperandIndex < 1) {
      // No operand rewriting permitted for this bytecode
      throw new Error("Trying to rewrite " + this + " that has no rewrite");
    }
   
    if(firstOperandIndex + position + 1 > byteCodeFormLength) {
      throw new Error("Trying to rewrite " + this + " with an int at position " + position + " but this won't fit in the rewrite array");
    }
   
      rewrite[firstOperandIndex + position] = (operand & 0xFF00) >> 8;
      rewrite[firstOperandIndex + position + 1] = operand & 0xFF;
  }
 
  /**
   * This is just like setOperandInt, but takes special care when the
   * operand is less than 0 to make sure it's written correctly.
   * @param operand int to set the rewrite bytes to
   * @param position int position of the operands in the rewrite bytes
   */
  public void setOperandSignedInt(int operand, int position) {
      if(operand >= 0) {
          setOperandInt(operand, position);
      } else {
          int twosComplementOperand = 0x10000 + operand;
          setOperandInt(twosComplementOperand, position);
      }
  }

  /**
   * Given an int operand, treat it as a byte and set
   * the rewrite byte for that position to that value.
   * Mask of anything beyond 0xFF.
   *
   * @param operand int to set the rewrite byte to (unsigned)
   * @param position int position in the operands of the
   *   rewrite bytes. For a rewrite array of {100, -1, -1, -1}
   *  position 0 is the first -1, position 1 is the second -1,
   *  etc.
   */
  public void setOperandByte(int operand, int position) {
    int firstOperandIndex = getByteCodeForm().firstOperandIndex();
    int byteCodeFormLength = getByteCodeForm().operandLength();
    if (firstOperandIndex < 1) {
      // No operand rewriting permitted for this bytecode
      throw new Error("Trying to rewrite " + this + " that has no rewrite");
    }
   
    if(firstOperandIndex + position > byteCodeFormLength) {
      throw new Error("Trying to rewrite " + this + " with an byte at position " + position + " but this won't fit in the rewrite array");
    }
   
    rewrite[firstOperandIndex + position] = operand & 0xFF;   
  }
 
 
  public String toString() {
    return getByteCodeForm().getName();
  }
 
  public void setNested(ClassFileEntry[] nested) {
    this.nested = nested;
  }
 
  /**
   * nestedPositions is an array of arrays of ints. Each
   * subarray specifies a position of a nested
   * element (from the nested[] array) and the length of
   * that element.
   *
   * For instance, one might have a nested of:
   *   {CPClass java/lang/Foo, CPFloat 3.14}
   * The nestedPositions would then be:
   *   {{0,2},{2,2}}
   * In other words, when the bytecode is resolved, the
   * CPClass will be resolved to an int and inserted
   * at position 0 and 1 of the rewrite arguments (the first
   * occurrences of -1). The CPFloat will be resolved to
   * an int position and inserted at positions 2 and 3 of
   * the rewrite arguments.
   * 
   * @param nestedPositions
   */
  public void setNestedPositions(int[][] nestedPositions) {
    this.nestedPositions = nestedPositions;
  }
 
  public int[][] getNestedPositions() {
    return nestedPositions;
  }
 
  public int[] getNestedPosition(int index) {
    return getNestedPositions()[index];
  }

    /**
     * This method will answer true if the receiver is
     * a multi-bytecode instruction (such as
     * aload0_putfield_super); otherwise, it will answer
     * false.
     *
     * @return boolean true if multibytecode, false otherwise
     */
  public boolean hasMultipleByteCodes() {
    return getByteCodeForm().hasMultipleByteCodes();
  }

    /**
     * ByteCodes may need to know their position in the
     * code array (in particular, label byte codes need
     * to know where they are in order to calculate their
     * targets). This method lets the CodeAttribute specify
     * where the byte code is.
     *
     * Since there are no aload0+label instructions, this
     * method doesn't worry about multioperation bytecodes.
     *
     * @param byteCodeOffset int position in code array.
     */
    public void setByteCodeIndex(int byteCodeOffset) {
        this.byteCodeOffset = byteCodeOffset;
    }


    public int getByteCodeIndex() {
        return byteCodeOffset;
    }
   
    /**
     * Some ByteCodes (in particular, LabelForm bytecodes)
     * have to keep track of a byteCodeTarget. This is
     * initially an offset in the CodeAttribute array
     * relative to the byteCodeOffset, but later gets fixed
     * up to point to the absolute position in the CodeAttribute
     * array. This method sets the target.
     *
     * @param byteCodeTarget int index in array
     */
    public void setByteCodeTarget(int byteCodeTarget) {
        this.byteCodeTarget = byteCodeTarget;
    }
   
    public int getByteCodeTarget() {
        return byteCodeTarget;
    }
   
    /**
     * Some ByteCodes (in particular, those with the Label
     * form) need to be fixed up after all the bytecodes
     * in the CodeAttribute have been added. (This can't
     * be done beforehand because the CodeAttribute needs
     * to be complete before targets can be assigned.)
     */
    public void applyByteCodeTargetFixup(CodeAttribute codeAttribute) {
        getByteCodeForm().fixUpByteCodeTarget(this, codeAttribute);
    }
}
TOP

Related Classes of org.apache.harmony.pack200.bytecode.ByteCode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.