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.classloader;
014
015import java.io.DataInputStream;
016import java.io.IOException;
017
018/**
019 * A java method's try/catch/finally information.
020 */
021public final class ExceptionHandlerMap {
022  //-----------//
023  // Interface //
024  //-----------//
025
026  public int[] getStartPC() {
027    return startPCs;
028  }
029
030  public int[] getEndPC() {
031    return endPCs;
032  }
033
034  public int[] getHandlerPC() {
035    return handlerPCs;
036  }
037
038  public TypeReference[] getExceptionTypes() {
039    return exceptionTypes;
040  }
041
042  public TypeReference getExceptionType(int i) {
043    return exceptionTypes[i];
044  }
045
046  /* we need to adjust the exception handler map for pseudo bytecode
047  * TODO: OSR redesign; make a subclass of ExceptionHandlerMap with this functionality
048  */
049  public void setStartPC(int[] newPCs) {
050    startPCs = newPCs;
051  }
052
053  public void setEndPC(int[] newPCs) {
054    endPCs = newPCs;
055  }
056
057  public void setHandlerPC(int[] newPCs) {
058    handlerPCs = newPCs;
059  }
060
061  //----------------//
062  // Implementation //
063  //----------------//
064
065  /**
066   * bytecode offset at which i-th try block begins
067   * 0-indexed from start of method's bytecodes[]
068   */
069  private int[] startPCs;
070
071  /**
072   * bytecode offset at which i-th try block ends (exclusive)
073   * 0-indexed from start of method's bytecodes[]
074   */
075  private int[] endPCs;
076
077  /**
078   * bytecode offset at which exception handler for i-th try block begins
079   * 0-indexed from start of method's bytecodes[]
080   */
081  private int[] handlerPCs;
082
083  /**
084   * exception type for which i-th handler is to be invoked
085   * - something like "java/lang/IOException".
086   * NOTE: When constructing the ExceptionHandlerMap we replace
087   * 'null' entries (means a finally block that catches everything)
088   * with RVMType.JavaLangThrowableType so we don't have to do anything
089   * special anywhere else in the VM.
090   */
091  private final TypeReference[] exceptionTypes;
092
093  private ExceptionHandlerMap(int[] startPCs, int[] endPCs, int[] handlerPCs, TypeReference[] exceptionTypes) {
094    this.startPCs = startPCs;
095    this.endPCs = endPCs;
096    this.handlerPCs = handlerPCs;
097    this.exceptionTypes = exceptionTypes;
098  }
099
100  static ExceptionHandlerMap readExceptionHandlerMap(DataInputStream input, int[] constantPool) throws IOException {
101    int cnt = input.readUnsignedShort();
102    if (cnt != 0) {
103      int[] startPCs = new int[cnt];
104      int[] endPCs = new int[cnt];
105      int[] handlerPCs = new int[cnt];
106      TypeReference[] exceptionTypes = new TypeReference[cnt];
107      for (int i = 0; i < cnt; ++i) {
108        startPCs[i] = input.readUnsignedShort();
109        endPCs[i] = input.readUnsignedShort();
110        handlerPCs[i] = input.readUnsignedShort();
111        TypeReference et = ClassFileReader.getTypeRef(constantPool, input.readUnsignedShort()); // possibly null
112        if (et == null) {
113          // A finally block...set to java.lang.Throwable to avoid
114          // needing to think about this case anywhere else in the VM.
115          exceptionTypes[i] = TypeReference.JavaLangThrowable;
116        } else {
117          exceptionTypes[i] = et;
118        }
119      }
120      return new ExceptionHandlerMap(startPCs, endPCs, handlerPCs, exceptionTypes);
121    } else {
122      return null;
123    }
124  }
125
126  ExceptionHandlerMap deepCopy() {
127    int n = startPCs.length;
128    int[] copyStartPCs = new int[n];
129    System.arraycopy(this.startPCs, 0, copyStartPCs, 0, n);
130    int[] copyEndPCs = new int[n];
131    System.arraycopy(this.endPCs, 0, copyEndPCs, 0, n);
132    int[] copyHandlerPCs = new int[n];
133    System.arraycopy(this.handlerPCs, 0, copyHandlerPCs, 0, n);
134    TypeReference[] copyExceptionTypes = new TypeReference[n];
135    System.arraycopy(this.exceptionTypes, 0, copyExceptionTypes, 0, n);
136
137    return new ExceptionHandlerMap(copyStartPCs, copyEndPCs, copyHandlerPCs, copyExceptionTypes);
138  }
139}