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       * <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       * Return an Enumeration of the caught exception types.
128       * Mainly intended for creation of exception tables during
129       * final assembly. Most other clients shouldn't care about this
130       * level of detail.
131       */
132      public Enumeration<TypeOperand> getExceptionTypes() {
133        return new Enumeration<TypeOperand>() {
134          private int idx = 0;
135    
136          @Override
137          public boolean hasMoreElements() {
138            return idx != exceptionTypes.length;
139          }
140    
141          @Override
142          public TypeOperand nextElement() {
143            try {
144              return exceptionTypes[idx++];
145            } catch (ArrayIndexOutOfBoundsException e) {
146              throw new java.util.NoSuchElementException("ExceptionHandlerBasicBlock.getExceptionTypes");
147            }
148          }
149        };
150      }
151    
152      /**
153       * Get how many table entries this EHBB needs.
154       * Really only of interest during final assembly.
155       *
156       * @see org.jikesrvm.compilers.opt.runtimesupport.OptExceptionTable
157       *
158       * @return the number of table entries for this basic block
159       */
160      public int getNumberOfExceptionTableEntries() {
161        return exceptionTypes.length;
162      }
163    
164      /**
165       * Returns the set of registers live before the first instruction of
166       * this basic block
167       *
168       * @return the set of registers live before the first instruction of
169       * this basic block
170       */
171      public LiveSet getLiveSet() {
172        return liveSet;
173      }
174    
175      /**
176       * Set the set of registers live before the first instruction of
177       * this basic block
178       *
179       * @param   liveSet The set of registers live before the first instruction of
180       * this basic block
181       */
182      public void setLiveSet(LiveSet liveSet) {
183        this.liveSet = liveSet;
184      }
185    
186      /**
187       * Return a string representation of the basic block
188       * (augment {@link BasicBlock#toString} with
189       * the exceptions caught by this handler block).
190       *
191       * @return a string representation of the block
192       */
193      @Override
194      public String toString() {
195        String exmsg = " (catches ";
196        for (int i = 0; i < exceptionTypes.length - 1; i++) {
197          exmsg = exmsg + exceptionTypes[i].toString() + ", ";
198        }
199        exmsg = exmsg + exceptionTypes[exceptionTypes.length - 1].toString();
200        exmsg = exmsg + " for";
201        Enumeration<BasicBlock> in = getIn();
202        while (in.hasMoreElements()) {
203          exmsg = exmsg + " " + in.nextElement().toString();
204        }
205        exmsg = exmsg + ")";
206    
207        return super.toString() + exmsg;
208      }
209    }