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.osr; 014 015 import java.util.ArrayList; 016 import java.util.Arrays; 017 import java.util.Comparator; 018 import java.util.LinkedList; 019 import org.jikesrvm.ArchitectureSpecificOpt.OptGCMapIteratorConstants; 020 import org.jikesrvm.VM; 021 import org.jikesrvm.compilers.opt.inlining.CallSiteTree; 022 import org.jikesrvm.compilers.opt.ir.Instruction; 023 import org.vmmagic.pragma.Inline; 024 import org.vmmagic.unboxed.Offset; 025 026 /** 027 * EncodedOSRMap provides the similar function as GC map 028 * in OptMachineCodeMap. 029 * <p> 030 * In OptCompiledMethod, an instance of this class will represent 031 * all OSR map info for that method. 032 */ 033 public final class EncodedOSRMap implements OptGCMapIteratorConstants, OSRConstants { 034 035 /** osr info entries */ 036 private final long[] mapEntries; 037 038 /** the last entry index. */ 039 private final int lastEntry; 040 041 /** the OSR map */ 042 private final int[] osrMaps; 043 044 /** map used when there are no OSR instructions */ 045 private static final EncodedOSRMap emptyMap = new EncodedOSRMap(); 046 047 @Inline 048 public static boolean registerIsSet(int map, int regnum) { 049 int bitpos = getRegBitPosition(regnum); 050 return (map & (NEXT_BIT >>> bitpos)) > 0; 051 } 052 053 /** 054 * mark a register as reference type 055 */ 056 private static int setRegister(int map, int regnum) { 057 int bitpos = getRegBitPosition(regnum); 058 map |= (NEXT_BIT >>> bitpos); 059 return map; 060 } 061 062 /** 063 * get register bit position 064 */ 065 @Inline 066 private static int getRegBitPosition(int regnum) { 067 return regnum - FIRST_GCMAP_REG + 1; 068 } 069 070 /** Constructor to build empty map */ 071 private EncodedOSRMap() { 072 this.mapEntries = null; 073 this.osrMaps = null; 074 this.lastEntry = -1; 075 } 076 077 /** Constructor that builds EncodedOSRMap from variable map */ 078 private EncodedOSRMap(VariableMap varMap) { 079 int entries = varMap.getNumberOfElements(); 080 081 this.lastEntry = entries - 1; 082 083 if (VM.VerifyAssertions) VM._assert(entries > 0); 084 this.mapEntries = new long[entries]; 085 ArrayList<Integer> tempOsrMaps = new ArrayList<Integer>(); 086 translateMap(tempOsrMaps, varMap.list); 087 this.osrMaps = new int[tempOsrMaps.size()]; 088 for (int i=0; i < tempOsrMaps.size(); i++) { 089 this.osrMaps[i] = tempOsrMaps.get(i); 090 } 091 092 //if (VM.TraceOnStackReplacement) { 093 // printMap(); 094 //} 095 } 096 097 /** 098 * Encode the given variable map returning the canonical empty map if the map 099 * is empty 100 */ 101 public static EncodedOSRMap makeMap(VariableMap varMap) { 102 if (varMap.getNumberOfElements() > 0) { 103 return new EncodedOSRMap(varMap); 104 } else { 105 return emptyMap; 106 } 107 } 108 109 /** 110 * Translates a list of OSR_MapElement to encoding, 111 * we can not trust the osrlist is in the increasing order of 112 * machine code offset. Sort it first. 113 */ 114 private void translateMap(ArrayList<Integer> tempOsrMaps, LinkedList<VariableMapElement> osrlist) { 115 116 /* sort the list, use the mc offset of the index instruction 117 * as the key. 118 */ 119 int n = osrlist.size(); 120 121 VariableMapElement[] osrarray = new VariableMapElement[n]; 122 for (int i = 0; i < n; i++) { 123 osrarray[i] = osrlist.get(i); 124 } 125 126 /* ideally, the osrList should be in sorted order by MC offset, 127 * but I got once it is not in the order. To work correctly, 128 * sort it first. 129 * 130 * TODO: figure out why LiveAnalysis does not give correct order? 131 */ 132 if (n > 1) { 133 Arrays.sort(osrarray, 134 new Comparator<VariableMapElement>() { 135 @Override 136 public int compare(VariableMapElement a, VariableMapElement b) { 137 return a.osr.getmcOffset() - b.osr.getmcOffset(); 138 } 139 }); 140 } 141 CallSiteTree inliningTree = new CallSiteTree(); 142 for (int i = 0; i < n; i++) { 143 Instruction instr = osrarray[i].osr; 144 // add lining element, move sanity later 145 if (instr.position != null) { 146 inliningTree.addLocation(instr.position); 147 } 148 } 149 150 for (int i = 0; i < n; i++) { 151 152 VariableMapElement elm = osrarray[i]; 153 Instruction instr = elm.osr; 154 155 int iei = inliningTree.find(instr.position).encodedOffset; 156 setIEIndex(i, iei); 157 158 // get osr map 159 LinkedList<MethodVariables> mVarList = elm.mvars; 160 int osrMapIndex = generateOsrMaps(tempOsrMaps, mVarList); 161 162 // use this offset, and adjust on extractState 163 int mcOffset = instr.getmcOffset(); 164 setMCOffset(i, mcOffset); 165 setOSRMapIndex(i, osrMapIndex); 166 setBCIndex(i, instr.getBytecodeIndex()); 167 } 168 } 169 170 /** 171 * Generate value in the Osr map, 172 * return the index of the first integer in the map. 173 * <p> 174 * An OSR Map has following structure: 175 * <pre> 176 * | regmap || mid, mpc, (n1, n2) ... || 177 * || mid, mpc, (n1, n2) ... || 178 * </pre> 179 * Regmap indicates the value of which register is a reference, 180 * the execution state extractor can convert the value to an 181 * object to avoid confusing GC. 182 * The MSB of regmap indicates next mid is valid. 183 * <p> 184 * The MSB of mid indicates if the next mid item will be 185 * available. 186 * <p> 187 * The MSB of mpc indicates if the next is a valid pair 188 */ 189 private int generateOsrMaps(ArrayList<Integer> tempOsrMaps, LinkedList<MethodVariables> mVarList) { 190 191 int regmap = (!mVarList.isEmpty()) ? NEXT_BIT : 0; 192 tempOsrMaps.add(regmap); 193 int mapIndex = tempOsrMaps.size()-1; 194 195 // from inner to outer 196 for (int i = 0, m = mVarList.size(); i < m; i++) { 197 MethodVariables mVar = mVarList.get(i); 198 _generateMapForOneMethodVariable(tempOsrMaps, mapIndex, mVar, (i == (m - 1))); 199 } 200 201 return mapIndex; 202 } 203 204 /** 205 * Generate value in the Osr map 206 * @param tempOsrMaps the maps under construction 207 * @param regMapIndex used to patch the register map 208 * @param mVar the method variables 209 * @param lastMid 210 */ 211 private void _generateMapForOneMethodVariable(ArrayList<Integer> tempOsrMaps, int regMapIndex, MethodVariables mVar, boolean lastMid) { 212 // Is this the last method in the inlined chain? 213 int mid = lastMid ? mVar.methId : (mVar.methId | NEXT_BIT); 214 tempOsrMaps.add(mid); 215 216 LinkedList<LocalRegPair> tupleList = mVar.tupleList; 217 int m = tupleList.size(); 218 219 // Is this method has variables? 220 int bci = (m == 0) ? mVar.bcIndex : (mVar.bcIndex | NEXT_BIT); 221 tempOsrMaps.add(bci); 222 223 // append each element 224 for (int j = 0; j < m; j++) { 225 LocalRegPair tuple = tupleList.get(j); 226 227 boolean isLast = (j == m - 1); 228 229 processTuple(tempOsrMaps, tuple, isLast); 230 // mark the reg ref map 231 if (((tuple.typeCode == ClassTypeCode) || (tuple.typeCode == ArrayTypeCode)) && (tuple.valueType == PHYREG)) { 232 tempOsrMaps.set(regMapIndex, setRegister(tempOsrMaps.get(regMapIndex), tuple.value.toInt())); 233 } 234 } 235 } 236 237 /** 238 * Process on 32-bit tuple. 239 * <p> 240 * tuple, maps the local to register, spill 241 * isLast, indicates to set NEXT_BIT 242 */ 243 private void processTuple(ArrayList<Integer> tempOsrMaps, LocalRegPair tuple, boolean isLast) { 244 245 int first = (tuple.num << NUM_SHIFT) & NUM_MASK; 246 247 if (!isLast) { 248 first |= NEXT_BIT; 249 } 250 251 first |= (tuple.kind ? 1 : 0) << KIND_SHIFT; 252 253 first |= (tuple.valueType << VTYPE_SHIFT); 254 255 switch (tuple.typeCode) { 256 case BooleanTypeCode: 257 case ByteTypeCode: 258 case CharTypeCode: 259 case ShortTypeCode: 260 case IntTypeCode: 261 first |= (INT << TCODE_SHIFT); 262 break; 263 case FloatTypeCode: 264 first |= (FLOAT << TCODE_SHIFT); 265 break; 266 case DoubleTypeCode: 267 first |= (DOUBLE << TCODE_SHIFT); 268 break; 269 case LongTypeCode: 270 if (VM.BuildFor32Addr || (tuple.valueType == LCONST)) { 271 // split in two integer parts for OSR map 272 // process the first half part, 273 // it is not the last. 274 first |= NEXT_BIT; 275 first |= (HIGH_64BIT << TCODE_SHIFT); 276 277 // add first word 278 tempOsrMaps.add(first); 279 // add the second word 280 281 if (VM.BuildFor64Addr) { 282 tempOsrMaps.add(tuple.value.rshl(32).toInt()); 283 } else { 284 tempOsrMaps.add(tuple.value.toInt()); 285 tuple = tuple._otherHalf; 286 } 287 // process the second half part, 288 // it may be the last, and it is not the first half. 289 first = (tuple.num << NUM_SHIFT) & NUM_MASK; 290 291 if (!isLast) first |= NEXT_BIT; 292 293 first |= (tuple.kind ? 1 : 0) << KIND_SHIFT; 294 first |= (tuple.valueType << VTYPE_SHIFT); 295 } 296 first |= (LONG << TCODE_SHIFT); 297 break; 298 case ReturnAddressTypeCode: 299 300 if (false) { 301 VM.sysWrite("returnaddress type for "); 302 if (tuple.kind == LOCAL) { 303 VM.sysWrite("L" + tuple.num); 304 } else { 305 VM.sysWrite("S" + tuple.num); 306 } 307 VM.sysWrite("\n"); 308 } 309 310 first |= (RET_ADDR << TCODE_SHIFT); 311 break; 312 case WordTypeCode: 313 if (VM.BuildFor64Addr && (tuple.valueType == ICONST)) {//KV:TODO 314 //split in two integer parts for OSR map 315 // process the first half part, 316 // it is not the last. */ 317 first |= NEXT_BIT; 318 first |= (HIGH_64BIT << TCODE_SHIFT); 319 320 // add first word 321 tempOsrMaps.add(first); 322 // add the second word 323 tempOsrMaps.add(tuple.value.rshl(32).toInt()); 324 325 // process the second half part, 326 // it may be the last, and it is not the first half. 327 first = (tuple.num << NUM_SHIFT) & NUM_MASK; 328 if (!isLast) first |= NEXT_BIT; 329 first |= (tuple.kind ? 1 : 0) << KIND_SHIFT; 330 first |= (tuple.valueType << VTYPE_SHIFT); 331 } 332 first |= (WORD << TCODE_SHIFT); 333 break; 334 case ClassTypeCode: 335 case ArrayTypeCode: 336 first |= (REF << TCODE_SHIFT); 337 break; 338 } 339 340 // add first word 341 tempOsrMaps.add(first); 342 // add the second word 343 tempOsrMaps.add(tuple.value.toInt()); 344 } 345 346 //////////////////////////////////// 347 // INTERFACE 348 /////////////////////////////////// 349 /** 350 * Does the OSR map exist for a machine instruction offset 351 */ 352 public boolean hasOSRMap(Offset mcOffset) { 353 int entry = findOSREntry(mcOffset); 354 return (entry != NO_OSR_ENTRY); 355 } 356 357 /* WARNING: 358 * It is the caller's reposibility to make sure there are OSR 359 * entry exist for a machine instruction offset. 360 */ 361 /** 362 * Get bytecode index for a given instruction offset in bytes. 363 */ 364 public int getBytecodeIndexForMCOffset(Offset mcOffset) { 365 int entry = findOSREntry(mcOffset); 366 return getBCIndex(entry); 367 } 368 369 /* TODO! 370 * get inline encoding index for the machine instruction offset 371 */ 372 public int getInlineEncodingForMCOffset(Offset mcOffset) { 373 return -1; 374 } 375 376 /** 377 * get register's reference map for the machine instruction offset 378 */ 379 public int getRegisterMapForMCOffset(Offset mcOffset) { 380 int entry = findOSREntry(mcOffset); 381 int mapIndex = getOSRMapIndex(entry); 382 return osrMaps[mapIndex]; 383 } 384 385 /** 386 * given a MC offset, return an iterator over the 387 * elements of this map. 388 * NOTE: the map index is gotten from 'findOSRMapIndex'. 389 * This has to be changed.... 390 */ 391 public OSRMapIterator getOsrMapIteratorForMCOffset(Offset mcOffset) { 392 int entry = findOSREntry(mcOffset); 393 int mapIndex = getOSRMapIndex(entry); 394 return new OSRMapIterator(osrMaps, mapIndex); 395 } 396 397 ///////////////////////////////// 398 // private functions 399 //////////////////////////////// 400 /** 401 * Do a binary search, find the entry for the machine code offset. 402 * Return -1 if no entry was found. 403 */ 404 private int findOSREntry(Offset mcOffset) { 405 406 int l = 0; 407 int r = lastEntry; 408 409 while (l <= r) { 410 int m = (l + r) >> 1; 411 Offset offset = Offset.fromIntSignExtend(getMCOffset(m)); 412 if (offset.EQ(mcOffset)) { 413 return m; 414 } else if (offset.sLT(mcOffset)) { 415 l = m + 1; 416 } else { 417 r = m - 1; 418 } 419 } 420 421 /* this is the place should not be reached, dump OSR content */ 422 if (VM.TraceOnStackReplacement) { 423 VM.sysWrite("cannot find map entry for ", mcOffset, "\n"); 424 this.printMap(); 425 } 426 427 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 428 429 return NO_OSR_ENTRY; 430 } 431 432 private int getMCOffset(int entry) { 433 return (int) ((mapEntries[entry] & OFFSET_MASK) >>> OFFSET_SHIFT); 434 } 435 436 private int getOSRMapIndex(int entry) { 437 return (int) ((mapEntries[entry] & OSRI_MASK) >>> OSRI_SHIFT); 438 } 439 440 private int getBCIndex(int entry) { 441 return (int) ((mapEntries[entry] & BCI_MASK) >>> BCI_SHIFT); 442 } 443 444 @SuppressWarnings("unused") 445 // Here for completeness (RJG ??) 446 private int getIEIndex(int entry) { 447 return (int) ((mapEntries[entry] & IEI_MASK) >>> IEI_SHIFT); 448 } 449 450 private void setMCOffset(int entry, int offset) { 451 mapEntries[entry] = (mapEntries[entry] & ~OFFSET_MASK) | (((long) offset) << OFFSET_SHIFT); 452 } 453 454 private void setOSRMapIndex(int entry, int index) { 455 mapEntries[entry] = (mapEntries[entry] & ~OSRI_MASK) | (((long) index) << OSRI_SHIFT); 456 } 457 458 private void setBCIndex(int entry, int index) { 459 mapEntries[entry] = (mapEntries[entry] & ~BCI_MASK) | (((long) index) << BCI_SHIFT); 460 } 461 462 private void setIEIndex(int entry, int index) { 463 mapEntries[entry] = (mapEntries[entry] & ~IEI_MASK) | (((long) index) << IEI_SHIFT); 464 } 465 466 /** 467 * print the encoded map for debugging. 468 */ 469 public void printMap() { 470 if (lastEntry > 0) { 471 VM.sysWrite("On-stack-replacement maps:\n"); 472 } 473 for (int i = 0; i <= lastEntry; i++) { 474 VM.sysWrite("Entry " + i + " : "); 475 int mapIndex = getOSRMapIndex(i); 476 VM.sysWrite(" mapIndex " + mapIndex + ", "); 477 int mcOffset = getMCOffset(i); 478 VM.sysWrite(" mc " + mcOffset + ", "); 479 int bcIndex = getBCIndex(i); 480 VM.sysWriteln("bc " + bcIndex); 481 482 /* 483 for (int j=0; j<osrMaps.length; j++) { 484 VM.sysWriteHex(osrMaps[j]);VM.sysWrite(" "); 485 } 486 VM.sysWrite("\n"); 487 */ 488 489 // register map 490 int regmap = osrMaps[mapIndex] & ~NEXT_BIT; 491 VM.sysWrite("regmap: " + Integer.toBinaryString(regmap)); 492 493 OSRMapIterator iterator = new OSRMapIterator(osrMaps, mapIndex); 494 495 while (iterator.hasMore()) { 496 VM.sysWrite("(" + iterator.getValueType() + "," + iterator.getValue() + ")"); 497 iterator.moveToNext(); 498 } 499 VM.sysWrite("\n"); 500 } 501 } 502 503 public int[] getMCIndexes() { 504 int[] indexes = new int[mapEntries.length]; 505 for (int i = 0, n = mapEntries.length; i < n; i++) { 506 indexes[i] = getMCOffset(i); 507 } 508 509 return indexes; 510 } 511 }