001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.ir;
014
015import java.util.Enumeration;
016
017import org.jikesrvm.compilers.opt.OptimizingCompilerException;
018
019/**
020 * A container for the chain of exception handlers for a basic block.
021 *
022 *
023 * @see BasicBlock
024 * @see ExceptionHandlerBasicBlock
025 */
026public final class ExceptionHandlerBasicBlockBag {
027
028  /**
029   * The array of ExceptionHandlerBasicBlocks constructed by BC2IR
030   * based on the local set of handlers visible within a single method
031   */
032  private ExceptionHandlerBasicBlock[] local;
033
034  /**
035   * If this is an inlined method, then this points to the enclosing
036   * method's (the caller's) ExcpetionHandlerBasicBlockBag.  If this is
037   * the outermost method, then this is null
038   */
039  private final ExceptionHandlerBasicBlockBag caller;
040
041  /**
042   * only for use by BC2IR; return {@link #caller}
043   * @return the contents of {@link #caller}
044   */
045  public ExceptionHandlerBasicBlockBag getCaller() {
046    return caller;
047  }
048
049  /**
050   * Create an EHBBB
051   * @param l the local array of EHBBs
052   * @param c the enclosing EHBBB
053   */
054  public ExceptionHandlerBasicBlockBag(ExceptionHandlerBasicBlock[] l, ExceptionHandlerBasicBlockBag c) {
055    local = l;
056    caller = c;
057  }
058
059  /**
060   * Takes an element out of the bag. Throws an exception if the block
061   * to remove is not in the bag.
062   *
063   * @param bb the block to remove
064   */
065  public void remove(BasicBlock bb) {
066    for (int i = 0; i < local.length; i++) {
067      if (bb == local[i]) {
068        ExceptionHandlerBasicBlock[] newLocal = new ExceptionHandlerBasicBlock[local.length - 1];
069
070        for (int j = 0; j < i; j++) newLocal[j] = local[j];
071
072        for (int j = i + 1; j < local.length; j++) newLocal[j - 1] = local[j];
073
074        local = newLocal;
075        return;
076      }
077    }
078
079    throw new OptimizingCompilerException("Removing block not present in bag: " + bb);
080  }
081
082  /**
083   * An enumeration of all the exception handler basic blocks
084   * (transitively) in the EHBBB.
085   * @return An enumeration of the exception handler basic blocks in the bag.
086   */
087  public Enumeration<BasicBlock> enumerator() {
088    return new Enumeration<BasicBlock>() {
089      private int cur_idx = 0;
090      private ExceptionHandlerBasicBlockBag cur_bag = null;
091
092      // Initialize enumeration to point to first ehbb (if any)
093      {
094        ExceptionHandlerBasicBlockBag c = ExceptionHandlerBasicBlockBag.this;
095        while (c != null && (c.local == null || c.local.length == 0)) {
096          c = c.caller;
097        }
098        if (c != null) {
099          cur_bag = c;
100        }
101      }
102
103      @Override
104      public boolean hasMoreElements() {
105        return cur_bag != null;
106      }
107
108      @Override
109      public BasicBlock nextElement() {
110        ExceptionHandlerBasicBlock ans;
111        try {
112          ans = cur_bag.local[cur_idx++];
113        } catch (NullPointerException e) {
114          java.util.NoSuchElementException nse = new java.util.NoSuchElementException();
115          nse.initCause(e);
116          throw nse;
117        }
118        // Now advance state to point to next element.
119        if (cur_idx == cur_bag.local.length) {
120          cur_bag = cur_bag.caller;
121          while (cur_bag != null && (cur_bag.local == null || cur_bag.local.length == 0)) {
122            cur_bag = cur_bag.caller;
123          }
124          if (cur_bag != null) {
125            cur_idx = 0; // found the next array, reset idx to first element.
126          }
127        }
128        return ans;
129      }
130    };
131  }
132}
133