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 static org.jikesrvm.compilers.opt.driver.OptConstants.MAYBE;
016import static org.jikesrvm.compilers.opt.driver.OptConstants.NO;
017import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
018
019import java.util.Enumeration;
020
021import org.jikesrvm.classloader.TypeReference;
022import org.jikesrvm.compilers.opt.ClassLoaderProxy;
023import org.jikesrvm.compilers.opt.inlining.InlineSequence;
024import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
025import org.jikesrvm.compilers.opt.liveness.LiveSet;
026
027/**
028 * A basic block that marks the start of an exception handler.
029 * Exception Handler Basic Block; acronym EHBB.
030 */
031public final class ExceptionHandlerBasicBlock extends BasicBlock {
032
033  /**
034   * The RVMType(s) of the exception(s) caught by this block.
035   */
036  private TypeOperand[] exceptionTypes;
037
038  /**
039   * The liveness information at the beginning of this block.
040   * <p>
041   *  NOTE: If we decide to store this for all blocks, we should move
042   *  this field to BasicBlock (the parent class)
043   */
044  private LiveSet liveSet;
045
046  /**
047   * Creates a new exception handler basic block at the specified location,
048   * which catches the specified type of exception.
049   *
050   * @param loc   Bytecode index to create basic block at
051   * @param position  The inline context for this basic block
052   * @param type  The exception type
053   * @param cfg   The ControlFlowGraph that will contain the basic block
054   */
055  public ExceptionHandlerBasicBlock(int loc, InlineSequence position, TypeOperand type, ControlFlowGraph cfg) {
056    super(loc, position, cfg);
057    exceptionTypes = new TypeOperand[1];
058    exceptionTypes[0] = type;
059    setExceptionHandlerBasicBlock();
060    liveSet = null;
061  }
062
063  /**
064   * Add a new exception type to an extant exception handler block.
065   * Do filtering of duplicates internally for efficiency.
066   * NOTE: this routine is only intended to be called by
067   * {@link org.jikesrvm.compilers.opt.bc2ir.BC2IR}.
068   *
069   * @param et the exception type to be added
070   */
071  public void addCaughtException(TypeOperand et) {
072    for (TypeOperand exceptionType : exceptionTypes) {
073      if (exceptionType.similar(et)) return;
074    }
075    TypeOperand[] newets = new TypeOperand[exceptionTypes.length + 1];
076    for (int i = 0; i < exceptionTypes.length; i++) {
077      newets[i] = exceptionTypes[i];
078    }
079    newets[exceptionTypes.length] = et;
080    exceptionTypes = newets;
081  }
082
083  /**
084   * Return YES/NO/MAYBE values that answer the question is it possible for
085   * this handler block to catch an exception of the type et.
086   *
087   * @param cand the TypeReference of the exception in question.
088   * @return YES, NO, MAYBE
089   */
090  public byte mayCatchException(TypeReference cand) {
091    boolean seenMaybe = false;
092    byte t;
093    for (TypeOperand exceptionType : exceptionTypes) {
094      t = ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand);
095      if (t == YES) return YES;
096      seenMaybe |= (t == MAYBE);
097      t = ClassLoaderProxy.includesType(cand, exceptionType.getTypeRef());
098      if (t == YES) return YES;
099      seenMaybe |= (t == MAYBE);
100    }
101    return seenMaybe ? MAYBE : NO;
102  }
103
104  /**
105   * Return YES/NO/MAYBE values that answer the question is it guarenteed that
106   * this handler block will catch an exception of type <code>cand</code>
107   *
108   * @param cand  the TypeReference of the exception in question.
109   * @return YES, NO, MAYBE
110   */
111  public byte mustCatchException(TypeReference cand) {
112    boolean seenMaybe = false;
113    byte t;
114    for (TypeOperand exceptionType : exceptionTypes) {
115      t = ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand);
116      if (t == YES) return YES;
117      seenMaybe |= (t == MAYBE);
118    }
119    if (seenMaybe) {
120      return MAYBE;
121    } else {
122      return NO;
123    }
124  }
125
126  /**
127   * This method is mainly intended for creation of exception tables during
128   * final assembly. Most other clients shouldn't care about this
129   * level of detail.
130   *
131   * @return an Enumeration of the caught exception types
132   */
133  public Enumeration<TypeOperand> getExceptionTypes() {
134    return new Enumeration<TypeOperand>() {
135      private int idx = 0;
136
137      @Override
138      public boolean hasMoreElements() {
139        return idx != exceptionTypes.length;
140      }
141
142      @Override
143      public TypeOperand nextElement() {
144        try {
145          return exceptionTypes[idx++];
146        } catch (ArrayIndexOutOfBoundsException e) {
147          java.util.NoSuchElementException nse = new java.util.NoSuchElementException("ExceptionHandlerBasicBlock.getExceptionTypes");
148          nse.initCause(e);
149          throw nse;
150        }
151      }
152    };
153  }
154
155  /**
156   * Gets the number of table entries required for this EHBB.
157   * <p>
158   * Really only of interest during final assembly.
159   *
160   * @return the number of table entries for this basic block
161   *
162   * @see org.jikesrvm.compilers.common.ExceptionTable exception table and
163   *   its opt-compiler specific subclasses
164   */
165  public int getNumberOfExceptionTableEntries() {
166    return exceptionTypes.length;
167  }
168
169  /**
170   * Returns the set of registers live before the first instruction of
171   * this basic block
172   *
173   * @return the set of registers live before the first instruction of
174   * this basic block
175   */
176  public LiveSet getLiveSet() {
177    return liveSet;
178  }
179
180  /**
181   * Set the set of registers live before the first instruction of
182   * this basic block
183   *
184   * @param   liveSet The set of registers live before the first instruction of
185   * this basic block
186   */
187  public void setLiveSet(LiveSet liveSet) {
188    this.liveSet = liveSet;
189  }
190
191  /**
192   * Return a string representation of the basic block
193   * (augment {@link BasicBlock#toString} with
194   * the exceptions caught by this handler block).
195   *
196   * @return a string representation of the block
197   */
198  @Override
199  public String toString() {
200    StringBuilder exmsg = new StringBuilder(" (catches ");
201    for (int i = 0; i < exceptionTypes.length - 1; i++) {
202      exmsg.append(exceptionTypes[i]);
203      exmsg.append(", ");
204    }
205    exmsg.append(exceptionTypes[exceptionTypes.length - 1]);
206    exmsg.append(" for");
207    Enumeration<BasicBlock> in = getIn();
208    while (in.hasMoreElements()) {
209      exmsg.append(' ');
210      exmsg.append(in.nextElement());
211    }
212    exmsg.append(')');
213
214    return super.toString() + exmsg;
215  }
216}