/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.ir;
import static org.jikesrvm.compilers.opt.driver.OptConstants.MAYBE;
import static org.jikesrvm.compilers.opt.driver.OptConstants.NO;
import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
import java.util.Enumeration;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.ClassLoaderProxy;
import org.jikesrvm.compilers.opt.inlining.InlineSequence;
import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
import org.jikesrvm.compilers.opt.liveness.LiveSet;
/**
* A basic block that marks the start of an exception handler.
* Exception Handler Basic Block; acronym EHBB.
*/
public final class ExceptionHandlerBasicBlock extends BasicBlock {
/**
* The RVMType(s) of the exception(s) caught by this block.
*/
private TypeOperand[] exceptionTypes;
/**
* The liveness information at the beginning of this block.
* <p>
* NOTE: If we decide to store this for all blocks, we should move
* this field to BasicBlock (the parent class)
*/
private LiveSet liveSet;
/**
* Creates a new exception handler basic block at the specified location,
* which catches the specified type of exception.
*
* @param loc Bytecode index to create basic block at
* @param position The inline context for this basic block
* @param type The exception type
* @param cfg The ControlFlowGraph that will contain the basic block
*/
public ExceptionHandlerBasicBlock(int loc, InlineSequence position, TypeOperand type, ControlFlowGraph cfg) {
super(loc, position, cfg);
exceptionTypes = new TypeOperand[1];
exceptionTypes[0] = type;
setExceptionHandlerBasicBlock();
liveSet = null;
}
/**
* Add a new exception type to an extant exception handler block.
* Do filtering of duplicates internally for efficiency.
* NOTE: this routine is only intended to be called by
* {@link org.jikesrvm.compilers.opt.bc2ir.BC2IR}.
*
* @param et the exception type to be added
*/
public void addCaughtException(TypeOperand et) {
for (TypeOperand exceptionType : exceptionTypes) {
if (exceptionType.similar(et)) return;
}
TypeOperand[] newets = new TypeOperand[exceptionTypes.length + 1];
for (int i = 0; i < exceptionTypes.length; i++) {
newets[i] = exceptionTypes[i];
}
newets[exceptionTypes.length] = et;
exceptionTypes = newets;
}
/**
* Return YES/NO/MAYBE values that answer the question is it possible for
* this handler block to catch an exception of the type et.
*
* @param cand the TypeReference of the exception in question.
* @return YES, NO, MAYBE
*/
public byte mayCatchException(TypeReference cand) {
boolean seenMaybe = false;
byte t;
for (TypeOperand exceptionType : exceptionTypes) {
t = ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand);
if (t == YES) return YES;
seenMaybe |= (t == MAYBE);
t = ClassLoaderProxy.includesType(cand, exceptionType.getTypeRef());
if (t == YES) return YES;
seenMaybe |= (t == MAYBE);
}
return seenMaybe ? MAYBE : NO;
}
/**
* Return YES/NO/MAYBE values that answer the question is it guarenteed that
* this handler block will catch an exception of type <code>cand</code>
*
* @param cand the TypeReference of the exception in question.
* @return YES, NO, MAYBE
*/
public byte mustCatchException(TypeReference cand) {
boolean seenMaybe = false;
byte t;
for (TypeOperand exceptionType : exceptionTypes) {
t = ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand);
if (t == YES) return YES;
seenMaybe |= (t == MAYBE);
}
if (seenMaybe) {
return MAYBE;
} else {
return NO;
}
}
/**
* This method is mainly intended for creation of exception tables during
* final assembly. Most other clients shouldn't care about this
* level of detail.
*
* @return an Enumeration of the caught exception types
*/
public Enumeration<TypeOperand> getExceptionTypes() {
return new Enumeration<TypeOperand>() {
private int idx = 0;
@Override
public boolean hasMoreElements() {
return idx != exceptionTypes.length;
}
@Override
public TypeOperand nextElement() {
try {
return exceptionTypes[idx++];
} catch (ArrayIndexOutOfBoundsException e) {
java.util.NoSuchElementException nse = new java.util.NoSuchElementException("ExceptionHandlerBasicBlock.getExceptionTypes");
nse.initCause(e);
throw nse;
}
}
};
}
/**
* Gets the number of table entries required for this EHBB.
* <p>
* Really only of interest during final assembly.
*
* @return the number of table entries for this basic block
*
* @see org.jikesrvm.compilers.common.ExceptionTable exception table and
* its opt-compiler specific subclasses
*/
public int getNumberOfExceptionTableEntries() {
return exceptionTypes.length;
}
/**
* Returns the set of registers live before the first instruction of
* this basic block
*
* @return the set of registers live before the first instruction of
* this basic block
*/
public LiveSet getLiveSet() {
return liveSet;
}
/**
* Set the set of registers live before the first instruction of
* this basic block
*
* @param liveSet The set of registers live before the first instruction of
* this basic block
*/
public void setLiveSet(LiveSet liveSet) {
this.liveSet = liveSet;
}
/**
* Return a string representation of the basic block
* (augment {@link BasicBlock#toString} with
* the exceptions caught by this handler block).
*
* @return a string representation of the block
*/
@Override
public String toString() {
StringBuilder exmsg = new StringBuilder(" (catches ");
for (int i = 0; i < exceptionTypes.length - 1; i++) {
exmsg.append(exceptionTypes[i]);
exmsg.append(", ");
}
exmsg.append(exceptionTypes[exceptionTypes.length - 1]);
exmsg.append(" for");
Enumeration<BasicBlock> in = getIn();
while (in.hasMoreElements()) {
exmsg.append(' ');
exmsg.append(in.nextElement());
}
exmsg.append(')');
return super.toString() + exmsg;
}
}