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}