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.common;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.classloader.DynamicTypeCheck;
017import org.jikesrvm.classloader.RVMType;
018import org.jikesrvm.objectmodel.TIB;
019import org.jikesrvm.util.Services;
020import org.vmmagic.pragma.Uninterruptible;
021import org.vmmagic.pragma.Unpreemptible;
022import org.vmmagic.unboxed.Offset;
023
024/**
025 * Encoding of try ranges in the final machinecode and the
026 * corresponding exception type and catch block start.
027 */
028public abstract class ExceptionTable {
029
030  /**
031   * An eTable array encodes the exception tables using 4 ints for each
032   */
033  protected static final int TRY_START = 0;
034  protected static final int TRY_END = 1;
035  protected static final int CATCH_START = 2;
036  protected static final int EX_TYPE = 3;
037
038  /**
039   * Return the machine code offset for the catch block that will handle
040   * the argument exceptionType,or -1 if no such catch block exists.
041   *
042   * @param eTable the encoded exception table to search
043   * @param instructionOffset the offset of the instruction after the PEI.
044   * @param exceptionType the type of exception that was raised
045   * @return the machine code offset of the catch block.
046   */
047  @Unpreemptible
048  public static int findCatchBlockForInstruction(int[] eTable, Offset instructionOffset, RVMType exceptionType) {
049    for (int i = 0, n = eTable.length; i < n; i += 4) {
050      // note that instructionOffset points to the instruction after the PEI
051      // so the range check here must be "offset >  beg && offset <= end"
052      // and not                         "offset >= beg && offset <  end"
053      //
054      // offset starts are sorted by starting point
055      if (instructionOffset.sGT(Offset.fromIntSignExtend(eTable[i + TRY_START])) &&
056          instructionOffset.sLE(Offset.fromIntSignExtend(eTable[i + TRY_END]))) {
057        RVMType lhs = RVMType.getType(eTable[i + EX_TYPE]);
058        if (lhs == exceptionType) {
059          return eTable[i + CATCH_START];
060        } else if (lhs.isInitialized()) {
061          TIB rhsTIB = exceptionType.getTypeInformationBlock();
062          if (DynamicTypeCheck.instanceOfClass(lhs.asClass(), rhsTIB)) {
063            return eTable[i + CATCH_START];
064          }
065        }
066      }
067    }
068    return -1;
069  }
070
071  /**
072   * Print an encoded exception table.
073   * @param eTable the encoded exception table to print.
074   */
075  public static void printExceptionTable(int[] eTable) {
076    writeExceptionTableHeader();
077    int length = eTable.length;
078    for (int i = 0; i < length; i += 4) {
079      printNicelyFormattedAndInterruptible(eTable, i);
080    }
081  }
082
083  @Uninterruptible
084  private static void writeExceptionTableHeader() {
085    VM.sysWriteln("Exception Table:");
086    VM.sysWriteln("    trystart   tryend    catch    type");
087  }
088
089  private static void printNicelyFormattedAndInterruptible(int[] eTable, int i) {
090    VM.sysWriteln("    " +
091                  Services.getHexString(eTable[i + TRY_START], true) +
092                  " " +
093                  Services.getHexString(eTable[i + TRY_END], true) +
094                  " " +
095                  Services.getHexString(eTable[i + CATCH_START], true) +
096                  "    " +
097                  RVMType.getType(eTable[i + EX_TYPE]));
098  }
099
100
101  /**
102   * Prints an exception table.
103   * <p>
104   * This method does the same thing as {@link #printExceptionTable(int[])} but
105   * with less nicely formatted output because of the constraints imposed by
106   * the requirements for uninterruptible code.
107   *
108   * @param eTable the exception table to print
109   */
110  @Uninterruptible
111  public static void printExceptionTableUninterruptible(int[] eTable) {
112    writeExceptionTableHeader();
113    int length = eTable.length;
114    for (int i = 0; i < length; i += 4) {
115      printLessNicelyFormattedAndUninterruptible(eTable, i);
116    }
117  }
118
119  @Uninterruptible
120  private static void printLessNicelyFormattedAndUninterruptible(int[] eTable,
121      int i) {
122    VM.sysWrite("    ");
123    VM.sysWriteHex(eTable[i + TRY_START]);
124    VM.sysWrite(" ");
125    VM.sysWriteHex(eTable[i + TRY_END]);
126    VM.sysWrite(" ");
127    VM.sysWriteHex(eTable[i + CATCH_START]);
128    VM.sysWrite("    ");
129    VM.sysWrite(RVMType.getType(eTable[i + EX_TYPE]).getDescriptor());
130    VM.sysWriteln();
131  }
132}
133
134
135