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.common;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.Services;
017    import org.jikesrvm.classloader.DynamicTypeCheck;
018    import org.jikesrvm.classloader.RVMType;
019    import org.jikesrvm.objectmodel.TIB;
020    import org.vmmagic.pragma.Unpreemptible;
021    import org.vmmagic.unboxed.Offset;
022    
023    /**
024     * Encoding of try ranges in the final machinecode and the
025     * corresponding exception type and catch block start.
026     */
027    public abstract class ExceptionTable {
028    
029      /**
030       * An eTable array encodes the exception tables using 4 ints for each
031       */
032      protected static final int TRY_START = 0;
033      protected static final int TRY_END = 1;
034      protected static final int CATCH_START = 2;
035      protected static final int EX_TYPE = 3;
036    
037      /**
038       * Return the machine code offset for the catch block that will handle
039       * the argument exceptionType,or -1 if no such catch block exists.
040       *
041       * @param eTable the encoded exception table to search
042       * @param instructionOffset the offset of the instruction after the PEI.
043       * @param exceptionType the type of exception that was raised
044       * @return the machine code offset of the catch block.
045       */
046      @Unpreemptible
047      public static int findCatchBlockForInstruction(int[] eTable, Offset instructionOffset, RVMType exceptionType) {
048        for (int i = 0, n = eTable.length; i < n; i += 4) {
049          // note that instructionOffset points to the instruction after the PEI
050          // so the range check here must be "offset >  beg && offset <= end"
051          // and not                         "offset >= beg && offset <  end"
052          //
053          // offset starts are sorted by starting point
054          if (instructionOffset.sGT(Offset.fromIntSignExtend(eTable[i + TRY_START])) &&
055              instructionOffset.sLE(Offset.fromIntSignExtend(eTable[i + TRY_END]))) {
056            RVMType lhs = RVMType.getType(eTable[i + EX_TYPE]);
057            if (lhs == exceptionType) {
058              return eTable[i + CATCH_START];
059            } else if (lhs.isInitialized()) {
060              TIB rhsTIB = exceptionType.getTypeInformationBlock();
061              if (DynamicTypeCheck.instanceOfClass(lhs.asClass(), rhsTIB)) {
062                return eTable[i + CATCH_START];
063              }
064            }
065          }
066        }
067        return -1;
068      }
069    
070      /**
071       * Print an encoded exception table.
072       * @param eTable the encoded exception table to print.
073       */
074      public static void printExceptionTable(int[] eTable) {
075        int length = eTable.length;
076        VM.sysWriteln("Exception Table:");
077        VM.sysWriteln("    trystart   tryend    catch    type");
078        for (int i = 0; i < length; i += 4) {
079          VM.sysWriteln("    " +
080                        Services.getHexString(eTable[i + TRY_START], true) +
081                        " " +
082                        Services.getHexString(eTable[i + TRY_END], true) +
083                        " " +
084                        Services.getHexString(eTable[i + CATCH_START], true) +
085                        "    " +
086                        RVMType.getType(eTable[i + EX_TYPE]));
087        }
088      }
089    }
090    
091    
092