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.baseline;
014    
015    import org.jikesrvm.VM;
016    
017    /**
018     * This class is used during the building of reference/non-reference maps for
019     * a method.  Once a JSR/RET combination has been processed, other JSR may
020     * be encountered that "jump" to the same subroutine. To calculate the maps
021     * of the instruction that is immediately after the JSR, we need the maps at
022     * the time of the JSR and the maps at the time of the RET.
023     */
024    final class JSRSubroutineInfo {
025      public int subroutineByteCodeStart;
026      public byte[] startReferenceMap;
027      int localsTop;
028      public byte[] endReferenceMap;
029      public int endReferenceTop;
030    
031      // for statistics
032      private static int JSRRoutineCount;
033      private static int JSRMismatchCount;  // count of jsr's that have different starting maps
034      private static int JSRRoutinesWithMismatch;
035      private boolean hasMismatch;
036    
037      public JSRSubroutineInfo(int subroutineByteCodeStart, byte[] startReferenceMap, int localsTop) {
038        this.subroutineByteCodeStart = subroutineByteCodeStart;
039        this.startReferenceMap = new byte[localsTop + 1];
040        for (int i = 0; i <= localsTop; i++) {
041          this.startReferenceMap[i] = startReferenceMap[i];
042        }
043        this.localsTop = localsTop;
044    
045        if (VM.ReferenceMapsStatistics) {
046          JSRRoutineCount++;
047        }
048      }
049    
050      public void newStartMaps(byte[] startReferenceMap) {
051        if (VM.ReferenceMapsStatistics) {
052          for (int i = 0; i <= localsTop; i++) {
053            if (this.startReferenceMap[i] != startReferenceMap[i]) {
054              if (!hasMismatch) {
055                hasMismatch = true;
056                JSRRoutinesWithMismatch++;
057              }
058              JSRMismatchCount++;
059              break;
060            }
061          }
062        }
063    
064        for (int i = 0; i <= localsTop; i++) {
065          this.startReferenceMap[i] = startReferenceMap[i];
066        }
067      }
068    
069      public void newEndMaps(byte[] endReferenceMap, int endReferenceTop) {
070        this.endReferenceMap = new byte[endReferenceTop + 1];
071        for (int i = 0; i <= endReferenceTop; i++) {
072          this.endReferenceMap[i] = endReferenceMap[i];
073        }
074        this.endReferenceTop = endReferenceTop;
075      }
076    
077      public byte[] computeResultingMaps(int mapLength) {
078    
079        byte[] newReferenceMap = new byte[mapLength];
080    
081        // If there is no ending map, then the JSR Subroutine must have ended in
082        // a return statement. Just return null
083        if (endReferenceMap == null) {
084          return null;
085        }
086    
087        // When there is no starting non reference map, then the JSR instruction is
088        // not within another  JSR subroutine
089        for (int i = 0; i <= localsTop; i++) {
090          if (endReferenceMap[i] == BuildReferenceMaps.NOT_SET) {
091            newReferenceMap[i] = startReferenceMap[i];
092          } else {
093            newReferenceMap[i] = endReferenceMap[i];
094          }
095        }
096    
097        // Copy over the operand stack.
098        for (int i = localsTop + 1; i <= endReferenceTop; i++) {
099          newReferenceMap[i] = endReferenceMap[i];
100        }
101    
102        return newReferenceMap;
103      }
104    
105      /**
106       * Prints out statistics about JSR subroutines and their starting maps
107       */
108      public static void printStatistics() {
109        VM.sysWrite("Number of JSR Subroutines processed: ");
110        VM.sysWrite(JSRRoutineCount);
111        VM.sysWrite("\n");
112        VM.sysWrite("Number of JSR Subroutines that started with a mismatched map: ");
113        VM.sysWrite(JSRRoutinesWithMismatch);
114        VM.sysWrite("\n");
115        VM.sysWrite("Total number of mismatch starts encountered :");
116        VM.sysWrite(JSRMismatchCount);
117      }
118    }