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}