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.baseline;
014
015import 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 */
024final 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  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}