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