/*
 * Copyright (c) 2002,2006 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 */
package com.ibm.wala.shrike.shrikeBT;

/**
 * Instructions are immutable objects. It is always legal to take a reference to an instruction and
 * use it in any other context. You never need to copy instructions. It is often a good idea to keep
 * references to frequently used instructions cached in static fields.
 *
 * <p>To generate an Instruction, locate the class for the instruction you want to generate, and
 * invoke the appropriate "make" static method on that class. The Util class has convenience methods
 * for creating some of the more complex instructions using reflection to fill in some of the needed
 * information (e.g., makeGet, makePut, makeInvoke).
 *
 * <p>We simplify the bytecode instruction set a bit using some preprocessing and postprocessing:
 *
 * <p>There is no 'iinc' instruction. 'iinc' instructions are expanded to 'iload; bipush; iadd;
 * istore' during decoding and reassembled during compilation.
 *
 * <p>There are no 'jsr' or 'ret' instructions. Bytecode subroutines are expanded inline during
 * decoding.
 *
 * <p>There are no 'ifeq', 'ifne', 'ifgt', 'ifge', 'iflt', 'ifle' instructions. These instructions
 * are expanded to 'bipush 0; if_icmp' during decoding and reassembled during compilation.
 *
 * <p>There are no 'ifnull' or 'ifnonnull' instructions. These instructions are expanded to
 * 'aconst_null; if_acmp' during decoding and reassembled during compilation.
 *
 * <p>All Java values, including longs and doubles, occupy just one word on the stack. Places where
 * the JVM assumes differently are fixed up during compilation. However, longs and double still take
 * up two local variable slots (this usually doesn't matter to instrumentation).
 *
 * <p>Control transfer instructions refer to target instructions using integers. These integers are
 * usually indices into an array of instructions.
 */
public abstract class Instruction implements Constants, Cloneable, IInstruction {
  public static final int[] noInstructions = new int[0];

  /** Ensure that only this package can subclass Instruction. */
  Instruction(short opcode) {
    this.opcode = opcode;
  }

  final short opcode;

  /** @return true if the instruction can "fall through" to the following instruction */
  @Override
  public boolean isFallThrough() {
    return true;
  }

  /**
   * @return an array containing the labels this instruction can branch to (not including the
   *     following instruction if this instruction 'falls through')
   */
  @Override
  public int[] getBranchTargets() {
    return noInstructions;
  }

  /**
   * @return an Instruction equivalent to this one but with any branch labels updated by looking
   *     them up in the targetMap array
   */
  @Override
  public IInstruction redirectTargets(int[] targetMap) {
    return this;
  }

  /** @return the number of values this instruction pops off the working stack */
  @Override
  public int getPoppedCount() {
    return 0;
  }

  /** @return the opcode selected for this instruction, or -1 if we don't know it yet */
  public final short getOpcode() {
    return opcode;
  }

  /**
   * Computes the type of data pushed onto the stack, or null if none is pushed.
   *
   * @param poppedTypesToCheck the types of the data popped off the stack by this instruction; if
   *     poppedTypes is null, then we don't know the incoming stack types and the result of this
   *     method may be less accurate
   */
  @Override
  public String getPushedType(String[] poppedTypesToCheck) {
    return null;
  }

  /**
   * @return the JVM word size of the value this instruction pushes onto the stack, or 0 if this
   *     instruction doesn't push anything onto the stack.
   */
  @Override
  public byte getPushedWordSize() {
    return 0;
  }

  /**
   * Apply a Visitor to this instruction. We invoke the appropriate Visitor method according to the
   * type of this instruction.
   */
  @Override
  public abstract void visit(IInstruction.Visitor v);

  /** Subclasses must implement toString. */
  @Override
  public abstract String toString();

  /** We're immutable so there's no need to clone any Instruction object. */
  @Override
  public final Object clone() {
    return this;
  }
}
