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