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 }