/* * 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 java.util.Enumeration; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.OPT_ClassLoaderProxy; import static org.jikesrvm.compilers.opt.OPT_Constants.MAYBE; import static org.jikesrvm.compilers.opt.OPT_Constants.NO; import static org.jikesrvm.compilers.opt.OPT_Constants.YES; import org.jikesrvm.compilers.opt.OPT_LiveSet; /** * A basic block that marks the start of an exception handler. * Exception Handler Basic Block; acronym EHBB. */ public final class OPT_ExceptionHandlerBasicBlock extends OPT_BasicBlock { /** * The VM_Type(s) of the exception(s) caught by this block. */ private OPT_TypeOperand[] exceptionTypes; /** * The liveness information at the beginning of this block * NOTE: If we decide to store this for all blocks, we should move * this field to OPT_BasicBlock (the parent class) */ private OPT_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 OPT_ControlFlowGraph that will contain the basic block */ OPT_ExceptionHandlerBasicBlock(int loc, OPT_InlineSequence position, OPT_TypeOperand type, OPT_ControlFlowGraph cfg) { super(loc, position, cfg); exceptionTypes = new OPT_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 OPT_BC2IR}. * * @param et the exception type to be added */ public void addCaughtException(OPT_TypeOperand et) { for (OPT_TypeOperand exceptionType : exceptionTypes) { if (exceptionType.similar(et)) return; } OPT_TypeOperand[] newets = new OPT_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 VM_TypeReference of the exception in question. * @return YES, NO, MAYBE */ public byte mayCatchException(VM_TypeReference cand) { boolean seenMaybe = false; byte t; for (OPT_TypeOperand exceptionType : exceptionTypes) { t = OPT_ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand); if (t == YES) return YES; seenMaybe |= (t == MAYBE); t = OPT_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 VM_TypeReference of the exception in question. * @return YES, NO, MAYBE */ public byte mustCatchException(VM_TypeReference cand) { boolean seenMaybe = false; byte t; for (OPT_TypeOperand exceptionType : exceptionTypes) { t = OPT_ClassLoaderProxy.includesType(exceptionType.getTypeRef(), cand); if (t == YES) return YES; seenMaybe |= (t == MAYBE); } if (seenMaybe) { return MAYBE; } else { return NO; } } /** * Return an Enumeration of the caught exception types. * Mainly intended for creation of exception tables during * final assembly. Most other clients shouldn't care about this * level of detail. */ public Enumeration<OPT_TypeOperand> getExceptionTypes() { return new Enumeration<OPT_TypeOperand>() { private int idx = 0; public boolean hasMoreElements() { return idx != exceptionTypes.length; } public OPT_TypeOperand nextElement() { try { return exceptionTypes[idx++]; } catch (ArrayIndexOutOfBoundsException e) { throw new java.util.NoSuchElementException("OPT_ExceptionHandlerBasicBlock.getExceptionTypes"); } } }; } /** * Get how many table entires this EHBB needs. * Really only of interest during final assembly. * * @see org.jikesrvm.compilers.opt.VM_OptExceptionTable * * @return the number of table entries for this basic block */ 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 OPT_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(OPT_LiveSet liveSet) { this.liveSet = liveSet; } /** * Return a string representation of the basic block * (augment {@link OPT_BasicBlock#toString} with * the exceptions caught by this handler block). * * @return a string representation of the block */ public String toString() { String exmsg = " (catches "; for (int i = 0; i < exceptionTypes.length - 1; i++) { exmsg = exmsg + exceptionTypes[i].toString() + ", "; } exmsg = exmsg + exceptionTypes[exceptionTypes.length - 1].toString(); exmsg = exmsg + " for"; OPT_BasicBlockEnumeration in = getIn(); while (in.hasMoreElements()) { exmsg = exmsg + " " + in.next().toString(); } exmsg = exmsg + ")"; return super.toString() + exmsg; } }