/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.compilers.opt.ir;

import org.jikesrvm.compilers.opt.OptimizingCompilerException;

/**
 * A container for the chain of exception handlers for a basic block.
 *
 *
 * @see BasicBlock
 * @see ExceptionHandlerBasicBlock
 */
public final class ExceptionHandlerBasicBlockBag {

  /**
   * The array of ExceptionHandlerBasicBlocks constructed by BC2IR
   * based on the local set of handlers visible within a single method
   */
  private ExceptionHandlerBasicBlock[] local;

  /**
   * If this is an inlined method, then this points to the enclosing
   * method's (the caller's) ExcpetionHandlerBasicBlockBag.  If this is
   * the outermost method, then this is null
   */
  private final ExceptionHandlerBasicBlockBag caller;

  /**
   * only for use by BC2IR; return {@link #caller}
   * @return the contents of {@link #caller}
   */
  public ExceptionHandlerBasicBlockBag getCaller() {
    return caller;
  }

  /**
   * Create an EHBBB
   * @param l the local array of EHBBs
   * @param c the enclosing EHBBB
   */
  public ExceptionHandlerBasicBlockBag(ExceptionHandlerBasicBlock[] l, ExceptionHandlerBasicBlockBag c) {
    local = l;
    caller = c;
  }

  /**
   * take an element out f the bag.  Throw an exception if the block
   * to remove is not in the bag
   */
  public void remove(BasicBlock bb) {
    for (int i = 0; i < local.length; i++) {
      if (bb == local[i]) {
        ExceptionHandlerBasicBlock[] newLocal = new ExceptionHandlerBasicBlock[local.length - 1];

        for (int j = 0; j < i; j++) newLocal[j] = local[j];

        for (int j = i + 1; j < local.length; j++) newLocal[j - 1] = local[j];

        local = newLocal;
        return;
      }
    }

    throw new OptimizingCompilerException("Removing block not present in bag: " + bb);
  }

  /**
   * An enumeration of all the exception handler basic blocks
   * (transitively) in the EHBBB.
   * @return An enumeration of the exception handler basic blocks in the bag.
   */
  public BasicBlockEnumeration enumerator() {
    return new BasicBlockEnumeration() {
      private int cur_idx = 0;
      private ExceptionHandlerBasicBlockBag cur_bag = null;

      // Initialize enumeration to point to first ehbb (if any)
      {
        ExceptionHandlerBasicBlockBag c = ExceptionHandlerBasicBlockBag.this;
        while (c != null && (c.local == null || c.local.length == 0)) { c = c.caller; }
        if (c != null) {
          cur_bag = c;
        }
      }

      public boolean hasMoreElements() { return cur_bag != null; }

      public BasicBlock nextElement() { return next(); }

      public BasicBlock next() {
        ExceptionHandlerBasicBlock ans;
        try {
          ans = cur_bag.local[cur_idx++];
        } catch (NullPointerException e) {
          throw new java.util.NoSuchElementException();
        }
        // Now advance state to point to next element.
        if (cur_idx == cur_bag.local.length) {
          cur_bag = cur_bag.caller;
          while (cur_bag != null && (cur_bag.local == null || cur_bag.local.length == 0)) {
            cur_bag = cur_bag.caller;
          }
          if (cur_bag != null) {
            cur_idx = 0; // found the next array, reset idx to first element.
          }
        }
        return ans;
      }
    };
  }
}

