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; 016import org.jikesrvm.architecture.ArchConstants; 017import org.jikesrvm.classloader.RVMArray; 018import org.jikesrvm.classloader.RVMMethod; 019import org.jikesrvm.classloader.NormalMethod; 020import org.jikesrvm.classloader.TypeReference; 021import org.jikesrvm.scheduler.SpinLock; 022import org.vmmagic.pragma.Interruptible; 023import org.vmmagic.pragma.Uninterruptible; 024import org.vmmagic.unboxed.Offset; 025 026/** 027 * class that provides stack (and local var) map for a baseline compiled method 028 * GC uses the methods provided here 029 */ 030@Uninterruptible 031public final class ReferenceMaps { 032 033 public static final byte JSR_MASK = -128; // byte = x'80' 034 public static final byte JSR_INDEX_MASK = 0x7F; 035 036 public static final int STARTINDEX = 0; 037 public static final int NOMORE = 0; 038 /** Kinds of merge operation when merging delta maps into table maps */ 039 private enum MergeOperation { 040 OR, NAND, COPY 041 } 042 043 /** Serializes JSR processing */ 044 public static final SpinLock jsrLock = new SpinLock(); // for serialization of JSR processing 045 046 /** Number of bits in each map element */ 047 private static final int BITS_PER_MAP_ELEMENT = 8; 048 private byte[] referenceMaps; 049 private int[] MCSites; 050 /** Number of bits in each map */ 051 private final int bitsPerMap; 052 /** Number of maps */ 053 private int mapCount; 054 private JSRInfo jsrInfo; 055 /** identify which block a byte is part of */ 056 final short[] byteToBlockMap; 057 058 /** 059 * @return size of individual maps 060 */ 061 private int bytesPerMap() { 062 return ((bitsPerMap + 7) / 8) + 1; 063 } 064 065 ReferenceMaps(BaselineCompiledMethod cm, int[] stackHeights, byte[] localTypes) { 066 067 NormalMethod method = (NormalMethod) cm.getMethod(); 068 // save input information and compute related data 069 this.bitsPerMap = (method.getLocalWords() + method.getOperandWords() + 1); // +1 for jsr bit 070 071 // this.startLocal0Offset = BaselineCompilerImpl.getStartLocalOffset(method); 072 073 if (VM.TraceStkMaps) { 074 VM.sysWrite("ReferenceMaps constructor. Method name is:"); 075 VM.sysWrite(method.getName()); 076 VM.sysWrite(" -Class name is :"); 077 VM.sysWrite(method.getDeclaringClass().getDescriptor()); 078 VM.sysWrite("\n"); 079 VM.sysWrite(" bytesPerMap = ", bytesPerMap()); 080 VM.sysWrite(" - bitsPerMap = ", bitsPerMap); 081// VM.sysWriteln(" - startLocal0Offset = ", startLocal0Offset); 082 } 083 084 // define the basic blocks 085 BuildBB buildBB = new BuildBB(method); 086 byteToBlockMap = buildBB.byteToBlockMap; 087 088 BuildReferenceMaps buildRefMaps = new BuildReferenceMaps(); 089 buildRefMaps.buildReferenceMaps(method, stackHeights, localTypes, this, buildBB); 090 091 if (VM.ReferenceMapsBitStatistics) { 092 showReferenceMapStatistics(method); 093 } 094 } 095 096 /** 097 * Given a machine code instruction offset, return an index to 098 * identify the stack map closest to the offset ( but not beyond).<p> 099 * 100 * Usage note: "machCodeOffset" must point to the instruction *following* 101 * the actual instruction 102 * whose stack map is sought. This allows us to properly handle the case where 103 * the only address we have to work with is a return address (i.e. from a stackframe) 104 * or an exception address (i.e. from a null pointer dereference, array bounds check, 105 * or divide by zero) on a machine architecture with variable length instructions. 106 * In such situations we'd have no idea how far to back up the instruction pointer 107 * to point to the "call site" or "exception site".<p> 108 * 109 * If the located site is within the scope of a jsr subroutine 110 * the index value returned is a negative number. 111 * 112 * @param machCodeOffset offset into machine code (see above for constraints) 113 * @param method the method that contains the gc point 114 * @return index of the appropriate stack map 115 */ 116 public int locateGCPoint(Offset machCodeOffset, RVMMethod method) { 117 118 machCodeOffset = machCodeOffset.minus(1 << ArchConstants.getLogInstructionWidth()); // this assumes that machCodeOffset points 119 // to "next" instruction eg bal type instruction 120 121 if (VM.TraceStkMaps) { 122 VM.sysWrite("ReferenceMaps-locateGCPoint for machine code offset = "); 123 VM.sysWrite(machCodeOffset); 124 VM.sysWrite(" --- in method = "); 125 VM.sysWrite(method.getName()); 126 VM.sysWrite("\n"); 127 } 128 129 // Scan the list of machine code addresses to find the 130 // closest site offset BEFORE the input machine code index ( offset in the code) 131 Offset distance = Offset.zero(); 132 int index = 0; 133 // get the first possible location 134 for (int i = 0; i < mapCount; i++) { 135 // get an initial non zero distance 136 distance = machCodeOffset.minus(MCSites[i]); 137 if (distance.sGE(Offset.zero())) { 138 index = i; 139 break; 140 } 141 } 142 // scan to find any better location i.e. closer to the site 143 for (int i = index + 1; i < mapCount; i++) { 144 Offset dist = machCodeOffset.minus(MCSites[i]); 145 if (dist.sLT(Offset.zero())) continue; 146 if (dist.sLE(distance)) { 147 index = i; 148 distance = dist; 149 } 150 } 151 152 if (VM.TraceStkMaps) { 153 showInfo(); 154 VM.sysWrite(" ReferenceMaps-locateGCPoint located index = "); 155 VM.sysWrite(index); 156 VM.sysWrite(" byte = "); 157 VM.sysWrite(referenceMaps[index]); 158 VM.sysWrite("\n"); 159 if (index - 1 >= 0) { 160 VM.sysWrite(" MCSites[index-1] = "); 161 VM.sysWrite(machCodeOffset.minus(MCSites[index - 1])); 162 VM.sysWrite("\n"); 163 } 164 VM.sysWrite(" MCSites[index ] = "); 165 VM.sysWrite(machCodeOffset.minus(MCSites[index])); 166 VM.sysWrite("\n"); 167 if (index + 1 < MCSites.length) { 168 VM.sysWrite(" MCSites[index+1] = "); 169 VM.sysWrite(machCodeOffset.minus(MCSites[index + 1])); 170 VM.sysWrite("\n"); 171 } 172 } 173 174 // test for a site within a jsr subroutine 175 if ((0x000000FF & (referenceMaps[index * bytesPerMap()] & JSR_MASK)) == 176 (0x000000FF & JSR_MASK)) { // test for jsr map 177 index = -index; // indicate site within a jsr to caller 178 if (VM.TraceStkMaps) { 179 VM.sysWrite(" ReferenceMaps-locateGCPoint jsr mapid = "); 180 VM.sysWrite(-index); 181 VM.sysWrite("\n"); 182 } 183 } 184 185 if (VM.TraceStkMaps) { 186 VM.sysWrite(" ReferenceMaps-locateGCPoint machine offset = "); 187 VM.sysWrite(machCodeOffset); 188 VM.sysWrite(" - return map index = "); 189 VM.sysWrite(index); 190 VM.sysWrite("\n"); 191 } 192 193 return index; 194 } 195 196 /** 197 * @param index offset in the reference stack frame, 198 * @param siteindex index that indicates the callsite (siteindex), 199 * @return return the offset where the next reference can be found, 200 * {@link #NOMORE} when no more pointers can be found 201 */ 202 public int getNextRefIndex(int index, int siteindex) { 203 if (VM.TraceStkMaps) { 204 VM.sysWrite("ReferenceMaps-getNextRef-inputs index = "); 205 VM.sysWrite(index); 206 VM.sysWrite(" -siteindex = "); 207 VM.sysWrite(siteindex); 208 VM.sysWrite("\n"); 209 } 210 211 // use index to locate the gc point of interest 212 if (bytesPerMap() == 0) return 0; // no map ie no refs 213 int mapindex = siteindex * bytesPerMap(); 214 215 int bitnum; 216 if (index == STARTINDEX) { 217 // this is the initial scan for the map 218 int mapByteNum = mapindex; 219 int startbitnumb = 1; // start search from beginning 220 bitnum = scanForNextRef(startbitnumb, mapByteNum, bitsPerMap, referenceMaps); 221 222 if (VM.TraceStkMaps) { 223 VM.sysWriteln("ReferenceMaps-getNextRef-initial call bitnum = ", bitnum); 224 } 225 } else { 226 // get bitnum and determine mapword to restart scan 227 bitnum = index + 1; // +1 for jsr bit 228 229 if (VM.TraceStkMaps) { 230 VM.sysWriteln("ReferenceMaps-getnextref- not initial- entry index,bitnum = ", index, " ", bitnum); 231 } 232 233 // scan forward from current position to next ref 234 bitnum = scanForNextRef(bitnum + 1, mapindex, (bitsPerMap - (bitnum - 1)), referenceMaps); 235 236 if (VM.TraceStkMaps) { 237 VM.sysWriteln("ReferenceMaps-getnextref- not initial- scan returned bitnum = ", bitnum); 238 } 239 } 240 241 if (bitnum == NOMORE) { 242 if (VM.TraceStkMaps) VM.sysWriteln(" NOMORE"); 243 return NOMORE; 244 } else { 245 int ans = bitnum - 1; //-1 for jsr bit 246 if (VM.TraceStkMaps) VM.sysWriteln(" result = ", ans); 247 return ans; 248 } 249 } 250 251 /** 252 * Given an offset in the jsr reference map, 253 * return the offset where the next returnAddress can be found.<p> 254 255 * NOTE: There is only one JSR map for the entire method because it has to 256 * be constructed at GC time and would normally require additional 257 * storage. 258 * <p> 259 * To avoid this, the space for one map is pre-allocated and the map 260 * is built in that space. When multiple threads exist and if GC runs 261 * in multiple threads concurrently, then the MethodMap must be locked 262 * when a JSR map is being scanned. This should be a low probability 263 * event. 264 * 265 * @param index offset in the JSR reference map, 266 * @return The offset where the next reference can be found or 267 * <code>NOMORE</code> when no more pointers can be found 268 * 269 */ 270 public int getNextJSRRefIndex(int index) { 271 // user index to locate the gc point of interest 272 if (bytesPerMap() == 0) return 0; // no map ie no refs 273 int mapword = jsrInfo.mergedReferenceMap; 274 275 int bitnum; 276 if (index == STARTINDEX) { 277 // this is the initial scan for the map 278 int startbitnumb = 1; // start search from beginning 279 bitnum = scanForNextRef(startbitnumb, mapword, bitsPerMap, jsrInfo.unusualReferenceMaps); 280 if (VM.TraceStkMaps) { 281 VM.sysWrite("ReferenceMaps-getJSRNextRef-initial call - startbitnum =", startbitnumb); 282 VM.sysWrite(" mapword = ", mapword); 283 VM.sysWrite(" bitspermap = ", bitsPerMap); 284 VM.sysWrite(" bitnum = ", bitnum); 285 } 286 } else { 287 // get bitnum and determine mapword to restart scan 288 bitnum = index; // get the bit number from last time 289 290 // scan forward from current position to next ref 291 if (VM.TraceStkMaps) { 292 VM.sysWrite("ReferenceMaps.getJSRnextref - not initial- starting (index,bitnum) = "); 293 VM.sysWrite(index); 294 VM.sysWrite(", "); 295 VM.sysWrite(bitnum); 296 } 297 298 bitnum = scanForNextRef(bitnum + 1, mapword, (bitsPerMap - (bitnum - 1)), jsrInfo.unusualReferenceMaps); 299 } 300 301 if (bitnum == NOMORE) { 302 if (VM.TraceStkMaps) VM.sysWriteln(" NOMORE"); 303 return NOMORE; 304 } else { 305 int ans = bitnum; 306 if (VM.TraceStkMaps) VM.sysWriteln(" result = ", ans); 307 return ans; 308 } 309 } 310 311 /** 312 * Given an offset in the jsr returnAddress map, 313 * return the offset where the next returnAddress can be found.<p> 314 * 315 * NOTE: there is only one jsr returnAddress map for the entire method because it has to be 316 * be constructed a GC time and would normally require additional storage. 317 * To avoid this, the space for one map is pre-allocated and the map 318 * is built in that space. When multiple threads exist and if GC runs 319 * in multiple threads concurrently, then the MethodMap must be locked 320 * when a jsr map is being scanned. 321 * This should be a low probability event.<p> 322 * 323 * NOTE: return addresses are handled separately from references because they point 324 * inside an object ( internal pointers) 325 * 326 * @param index offset in the JSR returnAddress map, 327 * @return The offset where the next reference can be found or 328 * <code>NOMORE</code> when no more pointers can be found 329 */ 330 public int getNextJSRReturnAddrIndex(int index) { 331 // use the preallocated map to locate the current point of interest 332 int mapword = jsrInfo.mergedReturnAddressMap; 333 if (bytesPerMap() == 0) { 334 if (VM.TraceStkMaps) { 335 VM.sysWriteln("ReferenceMaps-getJSRNextReturnAddr-initial call no returnaddresses"); 336 } 337 return 0; // no map ie no refs 338 } 339 340 int bitnum; 341 if (index == STARTINDEX) { 342 // this is the initial scan for the map 343 int startbitnumb = 1; // start search from beginning 344 bitnum = scanForNextRef(startbitnumb, mapword, bitsPerMap, jsrInfo.unusualReferenceMaps); 345 if (VM.TraceStkMaps) { 346 VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-initial call startbitnum, mapword, bitspermap = "); 347 VM.sysWrite(startbitnumb); 348 VM.sysWrite(" , "); 349 VM.sysWrite(mapword); 350 VM.sysWrite(" , "); 351 VM.sysWrite(bitsPerMap); 352 VM.sysWrite(" \n "); 353 VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-initial call return bitnum = "); 354 VM.sysWrite(bitnum); 355 VM.sysWrite("\n"); 356 } 357 } else { 358 // get bitnum and determine mapword to restart scan 359 bitnum = index; // get the bit number 360 if (VM.TraceStkMaps) { 361 VM.sysWriteln("ReferenceMaps-getJSRnextReturnAddr- not initial- starting index, starting bitnum = ", 362 index, 363 " ", 364 bitnum); 365 } 366 367 // scan forward from current position to next ref 368 bitnum = scanForNextRef(bitnum + 1, mapword, (bitsPerMap - (bitnum - 1)), jsrInfo.unusualReferenceMaps); 369 370 if (VM.TraceStkMaps) { 371 VM.sysWriteln("ReferenceMaps-getJSRnextref- not initial- scan returned bitnum = ", bitnum); 372 } 373 } 374 375 if (bitnum == NOMORE) { 376 if (VM.TraceStkMaps) VM.sysWriteln(" NOMORE"); 377 return NOMORE; 378 } else { 379 int ans = bitnum; 380 if (VM.TraceStkMaps) VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-return = ", ans); 381 return ans; 382 } 383 } 384 385 public int getStackDepth(int mapid) { 386 return bytesPerMap(); 387 } 388 389 @Interruptible 390 public int size() { 391 int size = TypeReference.ReferenceMaps.peekType().asClass().getInstanceSize(); 392 if (MCSites != null) size += RVMArray.IntArray.getInstanceSize(MCSites.length); 393 if (referenceMaps != null) size += RVMArray.ByteArray.getInstanceSize(referenceMaps.length); 394 if (jsrInfo != null && jsrInfo.unusualReferenceMaps != null) { 395 size += RVMArray.JavaLangObjectArray.getInstanceSize(jsrInfo.unusualReferenceMaps.length); 396 } 397 return size; 398 } 399 400 @Interruptible 401 public void startNewMaps(int gcPointCount, int jsrCount, int parameterWords) { 402 // normal map information 403 mapCount = 0; 404 MCSites = new int[gcPointCount]; 405 referenceMaps = new byte[gcPointCount * bytesPerMap()]; 406 407 if (VM.TraceStkMaps) { 408 VM.sysWrite("ReferenceMaps-startNewMaps- gcPointCount = "); 409 VM.sysWrite(gcPointCount); 410 VM.sysWrite(" -jsrCount = "); 411 VM.sysWrite(jsrCount); 412 VM.sysWrite("\n"); 413 } 414 415 if (jsrCount > 0) { 416 417 jsrInfo = new JSRInfo(2 * jsrCount); 418 419 // reserve a map for merging maps 420 jsrInfo.tempIndex = getNextMapElement(); 421 422 // reserve map words for merged reference map 423 jsrInfo.mergedReferenceMap = getNextMapElement(); 424 425 // reserve map words for merged return address map 426 jsrInfo.mergedReturnAddressMap = getNextMapElement(); 427 428 //reserve maps for the jsrInfo.extraUnusualMapObject 429 // the reference map 430 int mapstart = getNextMapElement(); 431 jsrInfo.extraUnusualMap.setReferenceMapIndex(mapstart); 432 433 //the set of non reference stores 434 mapstart = getNextMapElement(); 435 jsrInfo.extraUnusualMap.setNonReferenceMapIndex(mapstart); 436 437 // the return address map 438 mapstart = getNextMapElement(); 439 jsrInfo.extraUnusualMap.setReturnAddressMapIndex(mapstart); 440 441 } 442 443 } 444 445 /** 446 * Given the information about a GC point, record the information in the proper tables. 447 * @param byteindex the index in the bytecode of this site 448 * @param byteMap a byte array that describes the contents of the local variables and the java stack 449 * @param BBLastPtr the last offset of a byte that contains information about the map 450 * @param replacemap whether this map is a replacement for a currently 451 * existing map 452 */ 453 @Interruptible 454 public void recordStkMap(int byteindex, byte[] byteMap, int BBLastPtr, boolean replacemap) { 455 456 int mapNum = 0; 457 458 if (VM.TraceStkMaps) { 459 VM.sysWrite(" ReferenceMaps-recordStkMap bytecode offset = "); 460 VM.sysWrite(byteindex); 461 VM.sysWrite("\n"); 462 VM.sysWrite(" input byte map = "); 463 for (int j = 0; j <= BBLastPtr; j++) { 464 VM.sysWrite(byteMap[j]); 465 } 466 VM.sysWrite("\n"); 467 if (replacemap) { 468 VM.sysWrite(" ReferenceMaps-recordStkMap- replacing map at byteindex = "); 469 VM.sysWrite(byteindex); 470 VM.sysWrite("\n"); 471 } 472 } 473 474 if (replacemap) { 475 // replace a map that already exists in the table 476 // locate the site 477 for (mapNum = 0; mapNum < mapCount; mapNum++) { 478 if (MCSites[mapNum] == byteindex) { 479 // location found -clear out old map 480 int start = mapNum * bytesPerMap(); // get starting byte in map 481 for (int i = start; i < start + bytesPerMap(); i++) { 482 referenceMaps[i] = 0; 483 } 484 if (VM.TraceStkMaps) { 485 VM.sysWrite(" ReferenceMaps-recordStkMap replacing map number = ", mapNum); 486 VM.sysWriteln(" for machinecode index = ", MCSites[mapNum]); 487 } 488 break; 489 } 490 } 491 } else { 492 // add a map to the table - its a new site 493 // allocate a new site 494 mapNum = mapCount++; 495 // fill in basic information 496 MCSites[mapNum] = byteindex; // gen and save bytecode offset 497 if (BBLastPtr == -1) return; // empty map for this gc point 498 } 499 500 if (VM.TraceStkMaps) { 501 VM.sysWrite(" ReferenceMaps-recordStkMap map id = "); 502 VM.sysWrite(mapNum); 503 VM.sysWrite("\n"); 504 } 505 506 // convert Boolean array into array of bits ie create the map 507 int mapslot = mapNum * bytesPerMap(); 508 int len = (BBLastPtr + 1); // get last ptr in map 509 int offset = 0; // offset from origin 510 int convertLength; //to start in the map 511 int word = mapslot; 512 513 // convert first byte of map 514 // get correct length for first map byte - smaller of bits in first byte or size of map 515 if (len < (BITS_PER_MAP_ELEMENT - 1)) { 516 convertLength = len; 517 } else { 518 convertLength = BITS_PER_MAP_ELEMENT - 1; 519 } 520 byte firstByte = convertMapElement(byteMap, offset, convertLength, BuildReferenceMaps.REFERENCE); 521 referenceMaps[word] = (byte) ((0x000000ff & firstByte) >>> 1); // shift for jsr bit ie set it to 0 522 523 if (VM.TraceStkMaps) { 524 VM.sysWrite(" ReferenceMaps-recordStkMap convert first map bytes- byte number = "); 525 VM.sysWrite(word); 526 VM.sysWrite(" byte value in map = "); 527 VM.sysWrite(referenceMaps[word]); 528 VM.sysWrite(" - before shift = "); 529 VM.sysWrite(firstByte); 530 VM.sysWrite("\n"); 531 } 532 533 // update indexes for additional bytes 534 word++; // next byte in bit map 535 len -= (BITS_PER_MAP_ELEMENT - 1); // remaining count 536 offset += (BITS_PER_MAP_ELEMENT - 1); // offset into input array 537 538 // convert remaining byte array to bit array - 539 while (len > 0) { 540 // map takes multiple bytes -convert 1 at a time 541 if (len <= (BITS_PER_MAP_ELEMENT - 1)) { 542 convertLength = len; 543 } else { 544 convertLength = BITS_PER_MAP_ELEMENT; 545 } 546 // map takes multiple bytes -convert 1 at a time 547 referenceMaps[word] = convertMapElement(byteMap, offset, convertLength, BuildReferenceMaps.REFERENCE); 548 549 if (VM.TraceStkMaps) { 550 VM.sysWriteln(" ReferenceMaps-recordStkMap convert another map byte- byte number = ", 551 word, 552 " byte value = ", 553 referenceMaps[word]); 554 } 555 556 len -= BITS_PER_MAP_ELEMENT; // update remaining words 557 offset += BITS_PER_MAP_ELEMENT; // and offset 558 word++; 559 } // end of while 560 561 // update stats 562 if (VM.ReferenceMapsStatistics) { 563 if (!replacemap) { 564 } 565 } 566 } 567 568 /** 569 * Record a map for a point within a JSR Subroutine. This requires setting up one 570 * of the unusual maps. 571 * @param byteindex index into the byte code array of the point for the map 572 * @param currReferenceMap map of references and return addresses that were set 573 * within the JSR Subroutine 574 * @param BBLastPtr map runs from -1 to BBLastPtr inclusively 575 * @param returnAddrIndex Index in the stack where the return address 576 * for the jsr routine (in which this gcpoint is located) 577 * can be found 578 * @param replacemap {@code false} if this is the first time this map point has been 579 * recorded. 580 */ 581 @Interruptible 582 public void recordJSRSubroutineMap(int byteindex, byte[] currReferenceMap, int BBLastPtr, int returnAddrIndex, 583 boolean replacemap) { 584 int mapNum = 0; 585 int unusualMapIndex = 0; 586 int internalReturnIndex; 587 UnusualMaps jsrSiteMap; 588 589 if (replacemap) { 590 // update an already existing map 591 // locate existing site in table 592 jsrSiteMap = null; 593 findJSRSiteMap: 594 for (mapNum = 0; mapNum < mapCount; mapNum++) { 595 if (MCSites[mapNum] == byteindex) { 596 // GC site found - get index in unusual map table and the unusual Map 597 unusualMapIndex = JSR_INDEX_MASK & referenceMaps[mapNum * bytesPerMap()]; 598 internalReturnIndex = returnAddrIndex - 1; //-1 for jsrbit 599 if (unusualMapIndex == JSR_INDEX_MASK) { 600 // greater than 127 jsrInfo.unusualMaps- sequential scan of locate others unusual map 601 for (unusualMapIndex = JSR_INDEX_MASK; unusualMapIndex < jsrInfo.numberUnusualMaps; unusualMapIndex++) { 602 if (jsrInfo.unusualMaps[unusualMapIndex].getReturnAddressIndex() == internalReturnIndex) { 603 jsrSiteMap = jsrInfo.unusualMaps[unusualMapIndex]; 604 break findJSRSiteMap; 605 } 606 } 607 VM.sysFail(" can't find unusual map !!!!!!! - should never occur"); 608 } else { 609 jsrSiteMap = jsrInfo.unusualMaps[unusualMapIndex]; 610 break; 611 } 612 } 613 } 614 } else { 615 // new map, add to end of table 616 mapNum = mapCount++; // get slot and update count 617 MCSites[mapNum] = byteindex; // gen and save bytecode offset 618 619 // generate an UnusualMap for the site 620 jsrSiteMap = new UnusualMaps(); 621 622 // add unusual map to UnusualMap table (table may need to be expanded) 623 unusualMapIndex = addUnusualMap(jsrSiteMap); 624 625 // set back pointer i.e. pointer from unusual maps back into referencemaps 626 jsrSiteMap.setNormalMapIndex(mapNum); 627 628 // setup index in reference maps 629 if (unusualMapIndex > JSR_INDEX_MASK) { 630 unusualMapIndex = JSR_INDEX_MASK; 631 } 632 referenceMaps[mapNum * bytesPerMap()] = (byte) ((byte) unusualMapIndex | JSR_MASK); 633 634 // setup new unusual Map 635 internalReturnIndex = returnAddrIndex - 1 + 2; // -1 for jsrbit +2 to convert to our index 636 jsrSiteMap.setReturnAddressIndex(internalReturnIndex); 637 638 if (VM.TraceStkMaps) { 639 VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- input map = "); 640 for (int i = 0; i < BBLastPtr + 1; i++) { 641 VM.sysWrite(currReferenceMap[i]); 642 } 643 VM.sysWrite("\n"); 644 VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- mapNum = "); 645 VM.sysWrite(mapNum); 646 VM.sysWrite(" - byteindex = "); 647 VM.sysWrite(byteindex); 648 VM.sysWrite(" - return address index = "); 649 VM.sysWrite(internalReturnIndex); 650 VM.sysWrite(" - reference map byte = "); 651 VM.sysWrite(referenceMaps[mapNum * bytesPerMap()]); 652 VM.sysWrite("\n"); 653 } 654 } // end else clause - add new map 655 656 // for new maps, setup maps in UnusualMap, for existing map replace them 657 658 // setup Reference Map 659 int refindex = 660 scanByteArray(currReferenceMap, 661 BBLastPtr, 662 BuildReferenceMaps.SET_TO_REFERENCE, 663 jsrSiteMap.getReferenceMapIndex(), 664 true); 665 jsrSiteMap.setReferenceMapIndex(refindex); 666 667 if (VM.TraceStkMaps) { 668 VM.sysWrite(" - reference map index = "); 669 VM.sysWrite(refindex); 670 VM.sysWrite(" - reference map = "); 671 for (int i = refindex; i < refindex + bytesPerMap(); i++) { 672 VM.sysWrite(jsrInfo.unusualReferenceMaps[i]); 673 } 674 VM.sysWrite("\n"); 675 } 676 677 // setup NONReference Map 678 int nonrefindex = 679 scanByteArray(currReferenceMap, 680 BBLastPtr, 681 BuildReferenceMaps.SET_TO_NONREFERENCE, 682 jsrSiteMap.getNonReferenceMapIndex(), 683 true); 684 jsrSiteMap.setNonReferenceMapIndex(nonrefindex); 685 686 if (VM.TraceStkMaps) { 687 VM.sysWrite(" - NONreference map index = "); 688 VM.sysWrite(nonrefindex); 689 VM.sysWrite(" - NON reference map = "); 690 for (int i = nonrefindex; i < nonrefindex + bytesPerMap(); i++) { 691 VM.sysWrite(jsrInfo.unusualReferenceMaps[i]); 692 } 693 VM.sysWrite("\n"); 694 } 695 696 // setup returnAddress Map 697 int addrindex = 698 scanByteArray(currReferenceMap, 699 BBLastPtr, 700 BuildReferenceMaps.RETURN_ADDRESS, 701 jsrSiteMap.getReturnAddressMapIndex(), 702 false); 703 jsrSiteMap.setReturnAddressMapIndex(addrindex); 704 705 if (VM.TraceStkMaps) { 706 VM.sysWrite(" - returnAddress map index = "); 707 VM.sysWrite(addrindex); 708 VM.sysWrite(" - return Address map = "); 709 for (int i = addrindex; i < addrindex + bytesPerMap(); i++) { 710 VM.sysWrite(jsrInfo.unusualReferenceMaps[i]); 711 } 712 VM.sysWrite("\n"); 713 } 714 715 if (VM.TraceStkMaps) { 716 VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- unusualmap index = "); 717 VM.sysWrite(unusualMapIndex); 718 VM.sysWrite("\n"); 719 } 720 721 // update stats 722 if (VM.ReferenceMapsStatistics) { 723 if (!replacemap) { 724 } 725 } 726 } 727 728 /** 729 * Add an UnusualMap to the array of unusual maps, expand the array 730 * and referencemap array if necessary 731 * 732 * @param jsrSiteMap unusualMap to be added to array 733 * @return number of the added map in the array 734 */ 735 @Interruptible 736 private int addUnusualMap(UnusualMaps jsrSiteMap) { 737 if (jsrInfo.unusualMaps == null) { 738 // start up code 739 jsrInfo.unusualMaps = new UnusualMaps[5]; 740 jsrInfo.numberUnusualMaps = 0; 741 } 742 // add to array and bump count 743 jsrInfo.unusualMaps[jsrInfo.numberUnusualMaps] = jsrSiteMap; 744 int returnnumber = jsrInfo.numberUnusualMaps; 745 jsrInfo.numberUnusualMaps++; 746 747 // do we need to extend the maps 748 if (jsrInfo.numberUnusualMaps == jsrInfo.unusualMaps.length) { 749 // array is full, expand arrays for jsrInfo.unusualMaps and unusual referencemaps 750 UnusualMaps[] temp = new UnusualMaps[jsrInfo.numberUnusualMaps + 5]; 751 for (int i = 0; i < jsrInfo.numberUnusualMaps; i++) { 752 temp[i] = jsrInfo.unusualMaps[i]; 753 } 754 jsrInfo.unusualMaps = temp; 755 756 byte[] temp2 = new byte[jsrInfo.unusualReferenceMaps.length + (5 * bytesPerMap() * 3)]; 757 for (int i = 0; i < jsrInfo.unusualReferenceMaps.length; i++) { 758 temp2[i] = jsrInfo.unusualReferenceMaps[i]; 759 } 760 jsrInfo.unusualReferenceMaps = temp2; 761 } 762 return returnnumber; 763 } 764 765 /** 766 * Setup a map within a JSR Subroutine. This requires using up one 767 * of the unusual maps. This routine is called when the caller gets a 768 * negative mapindex value return from {@link #locateGCPoint}. This routine 769 * searches the map tables and uses its stack frameAddress input to build 770 * reference and returnAddress maps. The caller uses the getNext... 771 * routines to scan these maps for offsets in the frame of the 772 * related references.<p> 773 * 774 * Steps for this routine: 775 * <ol> 776 * <li>use the mapid to get index of the Unusual Map 777 * <li>from the unusual map and the frame - get the location of the jsr invoker 778 * <li>from the invoker address and the code base address - get the machine code offset 779 * from the machine code offset locate the map for that instruction 780 * <li>if the invoker was itself in a jsr- merge the delta maps of each jsr and 781 * compute the new total delta maps 782 * <li>else the invoker was not already in a jsr merge the unusual map differences 783 * with the invoker map 784 * </ol> 785 * 786 * @param mapid Index of map of instruction where map is required 787 * ( this value was returned by locateGCpoint) 788 * 789 * @return the index of the JSR invoker 790 */ 791 public int setupJSRSubroutineMap(int mapid) { 792 793 // first clear the maps in the jsrInfo.extraUnusualMap 794 int j = jsrInfo.extraUnusualMap.getReferenceMapIndex(); 795 int k = jsrInfo.extraUnusualMap.getNonReferenceMapIndex(); 796 int l = jsrInfo.extraUnusualMap.getReturnAddressMapIndex(); 797 for (int i = 0; i < bytesPerMap(); i++) { 798 jsrInfo.unusualReferenceMaps[j + i] = 0; 799 jsrInfo.unusualReferenceMaps[k + i] = 0; 800 jsrInfo.unusualReferenceMaps[l + i] = 0; 801 } 802 803 // use the mapid to get index of the Unusual Map 804 // 805 if (VM.TraceStkMaps) { 806 VM.sysWriteln("ReferenceMaps-setupJSRSubroutineMap- mapid = ", mapid, " - mapid = ", -mapid); 807 VM.sysWriteln(" -referenceMaps[(- mapid) * bytesPerMap] = ", referenceMaps[(-mapid) * bytesPerMap()]); 808 VM.sysWriteln(" unusual mapid index = ", referenceMaps[(-mapid) * bytesPerMap()] & JSR_INDEX_MASK); 809 } 810 811 int unusualMapid = (referenceMaps[(-mapid) * bytesPerMap()] & JSR_INDEX_MASK); 812 813 // if jsr map is > 127 go search for the right one 814 if (unusualMapid == JSR_INDEX_MASK) { 815 unusualMapid = findUnusualMap(-mapid); 816 } 817 818 UnusualMaps unusualMap = jsrInfo.unusualMaps[unusualMapid]; 819 unusualMapcopy(unusualMap); // deep copy unusual map into the extra map 820 821 // from the unusual map and the frame - get the location of the jsr invoker 822 // 823 return unusualMap.getReturnAddressIndex(); 824 } 825 826 public int getNextJSRAddressIndex(Offset nextMachineCodeOffset, NormalMethod m) { 827 int jsrMapid = locateGCPoint(nextMachineCodeOffset, m); 828 829 if (jsrMapid >= 0) { 830 finalMergeMaps((jsrMapid * bytesPerMap()), jsrInfo.extraUnusualMap); 831 832 if (VM.TraceStkMaps) { 833 VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- afterfinalMerge jsrInfo.extraUnusualMap = "); 834 jsrInfo.extraUnusualMap.showInfo(); 835 VM.sysWriteln(); 836 VM.sysWriteln(" jsrInfo.mergedReferenceMap Index = ", jsrInfo.mergedReferenceMap); 837 VM.sysWrite(" jsrInfo.mergedReferenceMap = "); 838 jsrInfo.showAnUnusualMap(jsrInfo.mergedReferenceMap, bytesPerMap()); 839 VM.sysWriteln(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap]); 840 VM.sysWriteln(" jsrInfo.mergedReturnAddressMap Index = ", jsrInfo.mergedReturnAddressMap); 841 VM.sysWriteln(" jsrInfo.mergedReturnAddressMap = ", 842 jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap]); 843 showInfo(); 844 jsrInfo.showUnusualMapInfo(bytesPerMap()); 845 } 846 return 0; 847 } 848 849 jsrMapid = -jsrMapid; 850 851 if (VM.TraceStkMaps) { 852 VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- outer MapIndex = ", 853 jsrMapid, 854 " unusualMapIndex = ", 855 referenceMaps[jsrMapid]); 856 } 857 858 // merge unusual maps- occurs in nested jsr conditions 859 // merge each nested delta into the maps of the extraUnusualmap 860 int unusualMapIndex = JSR_INDEX_MASK & referenceMaps[jsrMapid * bytesPerMap()]; 861 if (unusualMapIndex == JSR_INDEX_MASK) { 862 unusualMapIndex = findUnusualMap(jsrMapid); 863 } 864 jsrInfo.extraUnusualMap = combineDeltaMaps(unusualMapIndex); 865 866 // Locate the next JSR from the current 867 // 868 UnusualMaps thisMap = jsrInfo.unusualMaps[unusualMapIndex]; 869 if (VM.TraceStkMaps) { 870 VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- nested jsrs jsrInfo.extraUnusualMap = "); 871 jsrInfo.extraUnusualMap.showInfo(); 872 VM.sysWriteln(); 873 VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- nested jsrs thisMap = "); 874 thisMap.showInfo(); 875 VM.sysWriteln(); 876 } 877 return thisMap.getReturnAddressIndex(); 878 } 879 880 /** 881 * Called when all the recording for this map is complete. Can now 882 * sort or perform other cleanups 883 */ 884 public void recordingComplete() { 885 } 886 887 /** 888 * After code is generated, translate the bytecode indices 889 * recorded in MCSites array into real machine code offsets. 890 * 891 * @param b2m map of byte code index to machine code offsets 892 */ 893 public void translateByte2Machine(int[] b2m) { 894 for (int i = 0; i < MCSites.length; i++) { 895 MCSites[i] = b2m[MCSites[i]] << ArchConstants.getLogInstructionWidth(); 896 } 897 } 898 899 /** 900 * Convert a portion of an array word of Bytes into a bitmap of references. 901 * 902 * @param curBBMap a byte array that describes the contents of the local variables and the java stack 903 * @param offset a starting offset in the array 904 * @param len length of the scan, max is {@link #BITS_PER_MAP_ELEMENT} 905 * @param reftype the type of byte to scan for 906 * @return a bitword 907 */ 908 private byte convertMapElement(byte[] curBBMap, int offset, int len, byte reftype) { 909 byte bitmap = 0; 910 byte mask = JSR_MASK; // starting bit mask 911 for (int i = offset; i < offset + len; i++) { 912 if (curBBMap[i] == reftype) { 913 bitmap = (byte) (bitmap | mask); // add bit to mask 914 } 915 mask = (byte) ((0x000000ff & mask) >>> 1); // shift for next byte and bit 916 } 917 return bitmap; 918 } 919 920 /** 921 * @return next free word in referencemaps for GC call sites 922 */ 923 @Interruptible 924 private int getNextMapElement() { 925 if (jsrInfo.unusualReferenceMaps == null) { 926 // start up code 927 jsrInfo.unusualReferenceMaps = new byte[((6 * 3) + 1) * bytesPerMap()]; // 3 maps per unusual map 928 } 929 930 if (jsrInfo.freeMapSlot >= jsrInfo.unusualReferenceMaps.length) { 931 // map is full - get new array, twice the size 932 byte[] newArray = new byte[jsrInfo.unusualReferenceMaps.length << 1]; 933 // copy array from old to new 934 for (int i = 0; i < jsrInfo.unusualReferenceMaps.length; i++) { 935 newArray[i] = jsrInfo.unusualReferenceMaps[i]; 936 } 937 // replace old array with the new 938 jsrInfo.unusualReferenceMaps = newArray; // replace array 939 } 940 941 int allocate = jsrInfo.freeMapSlot; 942 jsrInfo.freeMapSlot = jsrInfo.freeMapSlot + bytesPerMap(); 943 return allocate; 944 } 945 946 /** 947 * given a index in the local area (biased : local0 has index 1) 948 * this routine determines the correspondig offset in the stack 949 */ 950 /* public int convertIndexToOffset(int index) { 951 if (index == 0) return NOMORE; //invalid 952 953 // convert from top of local words 954 int offset = startLocal0Offset - (index <<LOG_BYTES_IN_ADDRESS); // no jsrbit here 955 if (VM.TraceStkMaps) { 956 VM.sysWriteln("convertIndexToOffset- input index = ", index, " offset = ", offset); 957 } 958 return offset; 959 } 960 */ 961 962 /** 963 * Scans the map for the next reference. 964 * 965 * @param bitnum starting bitnumber in a map (inclusive) 966 * @param wordnum index of the corresponding byte, 967 * @param remaining remaining number of bits in the map, 968 * @param map map to search 969 * @return TODO document me 970 */ 971 private int scanForNextRef(int bitnum, int wordnum, int remaining, byte[] map) { 972 int retbit, count = 0; 973 974 // adjust bitnum and wordnum to bit within word 975 while (bitnum > BITS_PER_MAP_ELEMENT) { 976 wordnum++; 977 bitnum -= BITS_PER_MAP_ELEMENT; 978 count += BITS_PER_MAP_ELEMENT; 979 } 980 981 // determine remaining bits in this byte - first byte of scan 982 int remain = (BITS_PER_MAP_ELEMENT + 1) - bitnum; // remaining bits in this word 983 if (remain >= remaining) { 984 // last word in this map 985 retbit = scanByte(bitnum, wordnum, remaining, map); 986 if (retbit == 0) return 0; 987 return (retbit + count); 988 } 989 // search at least the rest of this byte 990 int startbit = bitnum; // start at this bit 991 retbit = scanByte(startbit, wordnum, remain, map); 992 if (retbit != 0) return (retbit + count); 993 994 // search additional bytes of map 995 startbit = 1; // start from beginning from now on 996 remaining -= remain; // remaing bits in map 997 count += BITS_PER_MAP_ELEMENT; // remember you did the first byte 998 while (remaining > BITS_PER_MAP_ELEMENT) { 999 wordnum++; // bump to next word 1000 remaining -= BITS_PER_MAP_ELEMENT; // search this wordd 1001 retbit = scanByte(startbit, wordnum, BITS_PER_MAP_ELEMENT, map); 1002 if (retbit != 0) return (retbit + count); 1003 count += BITS_PER_MAP_ELEMENT; 1004 } // end while 1005 1006 // scan last byte of map 1007 wordnum++; 1008 retbit = scanByte(startbit, wordnum, remaining, map); // last word 1009 if (retbit != 0) return (retbit + count); 1010 return 0; 1011 } 1012 1013 /** 1014 * Scans for a reference in a byte. 1015 * 1016 * @param bitnum bitnumber in the map 1017 * @param bytenum index of the corresponding map byte 1018 * @param toscan the remaining number of bits in the byte, 1019 * @param map the map 1020 * @return next ref in the byte or zero if not found 1021 */ 1022 private int scanByte(int bitnum, int bytenum, int toscan, byte[] map) { 1023 int count = 0, mask; 1024 1025 if (VM.TraceStkMaps) { 1026 VM.sysWrite(" scanByte- inputs bitnum = ", bitnum); 1027 VM.sysWrite(" bytenum = ", bytenum); 1028 VM.sysWriteln(" toscan = ", toscan); 1029 VM.sysWriteln(" stackmap byte = ", map[bytenum]); 1030 } 1031 1032 // convert bitnum to mask 1033 mask = (1 << (BITS_PER_MAP_ELEMENT - bitnum)); // generate mask 1034 1035 // scan rest of word 1036 while (toscan > 0) { 1037 if ((mask & map[bytenum]) == 0) { 1038 // this bit not a ref 1039 mask = mask >>> 1; // move mask bit 1040 count++; // inc count of bits checked 1041 toscan--; // decrement remaining count 1042 } else { 1043 // ref bit found 1044 if (VM.TraceStkMaps) { 1045 VM.sysWriteln(" scanByte- return bit number = ", bitnum + count); 1046 } 1047 return bitnum + count; 1048 } 1049 } // end while 1050 return 0; // no more refs 1051 } 1052 1053 /** 1054 * Scans the byte array to look for the type of information that was requested. Builds a 1055 * bit array in the stack maps with the information. 1056 * 1057 * @param byteMap bytearray where each byte describes the corresponding word on a stack 1058 * @param BBLastPtr length of the byte array 1059 * @param refType type of information that is to be scanned 1060 * @param mapslot slot where map should be stored, 0 for next free slot 1061 * @param skipOneBit should a bit in the bitarray be skipped? Necessary for setRef and 1062 * setNonRef maps so so they are properly merged with jsr base maps. 1063 * @return index of the map in the reference map 1064 */ 1065 @Interruptible 1066 int scanByteArray(byte[] byteMap, int BBLastPtr, byte refType, int mapslot, boolean skipOneBit) { 1067 skipOneBit = false; 1068 1069 if (BBLastPtr == -1) return -1; // no map for this jsr 1070 1071 // get a place to hold the map if necessary 1072 if (mapslot == 0) { 1073 mapslot = getNextMapElement(); // get first word of map 1074 } 1075 1076 // initialize search variables 1077 int len = (BBLastPtr + 1); // get length of map 1078 int offset = 0; // offset from origin 1079 int word = mapslot; // first word of map 1080 1081 // map may take multiple words -convert 1 at a time 1082 while (len > 0) { 1083 boolean doSkip = (offset == 0 && skipOneBit); // skip a bit if first word and skipOneBit is set 1084 int bitsToDo = doSkip ? BITS_PER_MAP_ELEMENT - 1 : BITS_PER_MAP_ELEMENT; 1085 if (len < bitsToDo) { 1086 bitsToDo = len; 1087 } 1088 1089 byte result = convertMapElement(byteMap, offset, bitsToDo, refType); 1090 if (doSkip) { 1091 result = 1092 (byte) ((0x000000ff & result) >>> 1093 1); // shift right to skip high bit for jsr to be consistent with normal maps 1094 } 1095 jsrInfo.unusualReferenceMaps[word] = result; 1096 1097 len -= bitsToDo; // update remaining words 1098 offset += bitsToDo; // and offset 1099 word++; // get next word 1100 } 1101 return mapslot; 1102 } 1103 1104 1105 /** 1106 * Makes a deep copy of {@code from} into {@code jsrInfo.extraUnusualMap} 1107 * @param from the map to copy from 1108 */ 1109 private void unusualMapcopy(UnusualMaps from) { 1110 jsrInfo.extraUnusualMap.setReturnAddressIndex(from.getReturnAddressIndex()); 1111 copyBitMap(jsrInfo.extraUnusualMap.getReferenceMapIndex(), from.getReferenceMapIndex()); 1112 copyBitMap(jsrInfo.extraUnusualMap.getNonReferenceMapIndex(), from.getNonReferenceMapIndex()); 1113 copyBitMap(jsrInfo.extraUnusualMap.getReturnAddressMapIndex(), from.getReturnAddressMapIndex()); 1114 } 1115 1116 /** 1117 * Copies a bit map into the extra unusualmap. 1118 * @param extramapindex the index of the map in the jsrInfo.extraUnusualMap ie the "to" map 1119 * @param index he index of the map to copy ie the "from" map 1120 */ 1121 private void copyBitMap(int extramapindex, int index) { 1122 if (VM.TraceStkMaps) { 1123 VM.sysWriteln(" copyBitMap from map index = ", 1124 index, 1125 " copyBitMap from value = ", 1126 jsrInfo.unusualReferenceMaps[index]); 1127 } 1128 1129 // copy the map over to the extra map 1130 for (int i = 0; i < bytesPerMap(); i++) { 1131 jsrInfo.unusualReferenceMaps[extramapindex + i] = jsrInfo.unusualReferenceMaps[index + i]; 1132 } 1133 1134 if (VM.TraceStkMaps) { 1135 VM.sysWriteln(" extraUnusualBitMap index = ", 1136 extramapindex, 1137 " extraunusualBitMap value = ", 1138 jsrInfo.unusualReferenceMaps[extramapindex]); 1139 } 1140 } 1141 1142 /** 1143 * 1144 * m 1145 * NOTE: while the routine is written to combine 2 jsrInfo.unusualMaps in general 1146 * in reality the target map is always the same ( the jsrInfo.extraUnusualMap) 1147 */ 1148 1149 /** 1150 * Merges unusual maps (occurs in nested jsr conditions) by merging each nested 1151 * delta map ( as represented by the jsrMapid of the location site) into the 1152 * jsrInfo.extraUnusualMap where the deltas are accumulated 1153 * 1154 * @param jsrUnusualMapid the delta map's id 1155 * @return merged map 1156 */ 1157 private UnusualMaps combineDeltaMaps(int jsrUnusualMapid) { 1158 //get the delta unusualMap 1159 UnusualMaps deltaMap = jsrInfo.unusualMaps[jsrUnusualMapid]; 1160 1161 // get the map indicies of the inner jsr map 1162 int reftargetindex = jsrInfo.extraUnusualMap.getReferenceMapIndex(); 1163 int nreftargetindex = jsrInfo.extraUnusualMap.getNonReferenceMapIndex(); 1164 int addrtargetindex = jsrInfo.extraUnusualMap.getReturnAddressMapIndex(); 1165 1166 // get the map indices of the outer jsr map 1167 int refdeltaindex = deltaMap.getReferenceMapIndex(); 1168 int nrefdeltaindex = deltaMap.getNonReferenceMapIndex(); 1169 int addrdeltaindex = deltaMap.getReturnAddressMapIndex(); 1170 1171 if (VM.TraceStkMaps) { 1172 // display original maps 1173 VM.sysWriteln("combineDeltaMaps- original ref map id = ", reftargetindex); 1174 VM.sysWrite("combineDeltaMaps- original ref map = "); 1175 for (int i = 0; i < bytesPerMap(); i++) { 1176 VM.sysWrite(jsrInfo.unusualReferenceMaps[reftargetindex + i]); 1177 } 1178 VM.sysWriteln(); 1179 VM.sysWriteln("combineDeltaMaps- original nref map id = ", nreftargetindex); 1180 VM.sysWrite("combineDeltaMaps original nref map = "); 1181 for (int i = 0; i < bytesPerMap(); i++) { 1182 VM.sysWrite(jsrInfo.unusualReferenceMaps[nreftargetindex + i]); 1183 } 1184 VM.sysWriteln(); 1185 VM.sysWriteln("combineDeltaMaps- original retaddr map id = ", addrtargetindex); 1186 VM.sysWrite("combineDeltaMaps original retaddr map = "); 1187 for (int i = 0; i < bytesPerMap(); i++) { 1188 VM.sysWrite(jsrInfo.unusualReferenceMaps[addrtargetindex + i]); 1189 } 1190 VM.sysWriteln(); 1191 1192 VM.sysWriteln("combineDeltaMaps- delta ref map id = ", refdeltaindex); 1193 VM.sysWrite("combineDeltaMaps- original delta ref map = "); 1194 for (int i = 0; i < bytesPerMap(); i++) { 1195 VM.sysWrite(jsrInfo.unusualReferenceMaps[refdeltaindex + i]); 1196 } 1197 VM.sysWriteln(); 1198 VM.sysWriteln("combineDeltaMaps- delta nref map id = ", nrefdeltaindex); 1199 VM.sysWrite("combineDeltaMaps original delta nref map = "); 1200 for (int i = 0; i < bytesPerMap(); i++) { 1201 VM.sysWrite(jsrInfo.unusualReferenceMaps[nrefdeltaindex + i]); 1202 } 1203 VM.sysWriteln(); 1204 VM.sysWriteln("combineDeltaMaps- delta retaddr map id = ", addrdeltaindex); 1205 VM.sysWrite("combineDeltaMaps original delta retaddr map = "); 1206 for (int i = 0; i < bytesPerMap(); i++) { 1207 VM.sysWrite(jsrInfo.unusualReferenceMaps[addrdeltaindex + i]); 1208 } 1209 VM.sysWriteln(); 1210 1211 // display indices 1212 VM.sysWriteln("combineDeltaMaps- ref target mapid = ", reftargetindex); 1213 VM.sysWriteln(" ref delta mapid = ", refdeltaindex); 1214 VM.sysWriteln("combineDeltaMaps- NONref target mapid = ", nreftargetindex); 1215 VM.sysWriteln(" NONref delta mapid = ", nrefdeltaindex); 1216 VM.sysWriteln("combineDeltaMaps- retaddr target mapid = ", addrtargetindex); 1217 VM.sysWriteln(" retaddr delta mapid = ", addrdeltaindex); 1218 VM.sysWriteln(" jsrInfo.tempIndex = ", jsrInfo.tempIndex); 1219 } 1220 1221 // merge the reference maps 1222 mergeMap(jsrInfo.tempIndex, reftargetindex, MergeOperation.COPY); // save refs made in inner jsr sub(s) 1223 mergeMap(reftargetindex, refdeltaindex, MergeOperation.OR); // get refs from outer loop 1224 mergeMap(reftargetindex, nreftargetindex, MergeOperation.NAND); // turn off non refs made in inner jsr sub(s) 1225 mergeMap(reftargetindex, addrtargetindex, MergeOperation.NAND); // then the return adresses 1226 mergeMap(reftargetindex, jsrInfo.tempIndex, MergeOperation.OR); // OR inrefs made in inner jsr sub(s) 1227 1228 // merge the non reference maps 1229 mergeMap(jsrInfo.tempIndex, nreftargetindex, MergeOperation.COPY); // save nonrefs made in inner loop(s) 1230 mergeMap(nreftargetindex, nrefdeltaindex, MergeOperation.OR); // get nrefs from outer loop 1231 mergeMap(nreftargetindex, reftargetindex, MergeOperation.NAND); // turn off refs made in inner jsr sub(s) 1232 mergeMap(nreftargetindex, addrtargetindex, MergeOperation.NAND); // then the return adresses 1233 mergeMap(nreftargetindex, jsrInfo.tempIndex, MergeOperation.OR); // OR in non refs made in inner jsr sub(s) 1234 1235 // merge return address maps 1236 mergeMap(addrtargetindex, addrdeltaindex, MergeOperation.OR); 1237 1238 if (VM.TraceStkMaps) { 1239 //display final maps 1240 VM.sysWrite("setupjsrmap-combineDeltaMaps- merged ref map = "); 1241 for (int i = 0; i < bytesPerMap(); i++) { 1242 VM.sysWrite(jsrInfo.unusualReferenceMaps[reftargetindex + i]); 1243 } 1244 VM.sysWriteln(); 1245 VM.sysWrite("setupjsrmap-combineDeltaMaps- merged nonref map = "); 1246 for (int i = 0; i < bytesPerMap(); i++) { 1247 VM.sysWrite(jsrInfo.unusualReferenceMaps[nreftargetindex + i]); 1248 } 1249 VM.sysWriteln(); 1250 VM.sysWrite("setupjsrmap-combineDeltaMaps- merged retaddr map = "); 1251 for (int i = 0; i < bytesPerMap(); i++) { 1252 VM.sysWrite(jsrInfo.unusualReferenceMaps[addrtargetindex + i]); 1253 } 1254 VM.sysWriteln(); 1255 } 1256 1257 return jsrInfo.extraUnusualMap; 1258 } 1259 1260 /** 1261 * Merges a delta map into a target map. 1262 * 1263 * @param targetindex the delta map's index in the reference map table 1264 * @param deltaindex the target map's index in the reference map tbale 1265 * @param Op the merge operation to use 1266 */ 1267 private void mergeMap(int targetindex, int deltaindex, MergeOperation Op) { 1268 int i; 1269 // Merge the maps 1270 if (Op == MergeOperation.COPY) { 1271 for (i = 0; i < bytesPerMap(); i++) { 1272 jsrInfo.unusualReferenceMaps[targetindex + i] = jsrInfo.unusualReferenceMaps[deltaindex + i]; 1273 } 1274 } 1275 if (Op == MergeOperation.OR) { 1276 for (i = 0; i < bytesPerMap(); i++) { 1277 jsrInfo.unusualReferenceMaps[targetindex + i] = 1278 (byte) (jsrInfo.unusualReferenceMaps[targetindex + i] | jsrInfo.unusualReferenceMaps[deltaindex + i]); 1279 } 1280 } 1281 if (Op == MergeOperation.NAND) { 1282 for (i = 0; i < bytesPerMap(); i++) { 1283 short temp = (byte) (~(jsrInfo.unusualReferenceMaps[deltaindex + i])); 1284 jsrInfo.unusualReferenceMaps[targetindex + i] = (byte) (jsrInfo.unusualReferenceMaps[targetindex + i] & temp); 1285 } 1286 } 1287 } 1288 1289 /** 1290 * This method will merge the jsr invoker's base map with changes 1291 * due to *all* nested jsr subroutines.<p> 1292 * 1293 * The nested jsr subroutine maps were merged into a single delta 1294 * map prior to the calling of this method. We therefore know that 1295 * the base map can never be due to a subroutine (since all 1296 * subroutines have been merged), and therefore that there are no 1297 * return address maps due to the invoker (since return addresses 1298 * are only due to the subroutine maps). 1299 * 1300 * @param jsrBaseMapIndex The map index for the invoker 1301 * @param deltaMap The map for the invoked subroutine/s (all nested 1302 * subroutine maps are guaranteed to have been combined prior to 1303 * calling this) 1304 */ 1305 private void finalMergeMaps(int jsrBaseMapIndex, UnusualMaps deltaMap) { 1306 int i; 1307 1308 /* clear out the destination (merged) maps */ 1309 for (i = 0; i < bytesPerMap(); i++) { 1310 jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i] = 0; 1311 jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i] = 0; 1312 } 1313 1314 /* get the indices of the maps for the combined subroutine map */ 1315 int refMapIndex = deltaMap.getReferenceMapIndex(); 1316 int nonRefMapIndex = deltaMap.getNonReferenceMapIndex(); 1317 int returnAddressMapIndex = deltaMap.getReturnAddressMapIndex(); 1318 1319 /* merge the subroutine delta map into the invoker (base) map */ 1320 for (i = 0; i < bytesPerMap(); i++) { 1321 /* first establish the change in the maps due to the combined subroutines */ 1322 byte deltaRef = jsrInfo.unusualReferenceMaps[refMapIndex + i]; 1323 byte deltaNonRef = jsrInfo.unusualReferenceMaps[nonRefMapIndex + i]; 1324 byte deltaRtnAddr = jsrInfo.unusualReferenceMaps[returnAddressMapIndex + i]; 1325 byte deltaAny = (byte) (deltaRef | deltaNonRef | deltaRtnAddr); 1326 1327 /* There is no merging to be done for the return address map 1328 * since the invoker cannot have any return addressses since it 1329 * is guaranteed not to be a subroutine (and only subroutines 1330 * can generate return address map entries) */ 1331 jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i] = deltaRtnAddr; 1332 1333 /* Get the base reference map (the high bit is used to denote jsr) */ 1334 byte thisBase = referenceMaps[jsrBaseMapIndex + i]; 1335 byte nextBase = (i + 1 < bytesPerMap()) ? referenceMaps[jsrBaseMapIndex + i + 1] : 0; 1336 byte baseRef = (byte) ((thisBase << 1) | ((0xff & nextBase) >>> 7)); 1337 1338 /* Merge the reference maps */ 1339 byte mergedRef = (byte) (deltaRef | (baseRef & ~deltaAny)); 1340 jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i] = mergedRef; 1341 1342 /* 1343 VM.sysWrite(" **** thisBase = "); VM.sysWrite(thisBase); 1344 VM.sysWrite(" nextBase = "); VM.sysWrite(nextBase); 1345 VM.sysWrite(" deltaRef = "); VM.sysWrite(deltaRef); 1346 VM.sysWrite(" deltaNonRef = "); VM.sysWrite(deltaNonRef); 1347 VM.sysWrite(" base = "); VM.sysWrite(base); 1348 VM.sysWrite(" newRef = "); VM.sysWrite(newRef); 1349 VM.sysWrite("\n"); 1350 */ 1351 } 1352 1353 if (VM.TraceStkMaps) { 1354 //Note: this displays each byte as a word ... only look at low order byte 1355 VM.sysWrite("finalmergemaps-jsr total set2ref delta map = "); 1356 for (i = 0; i < bytesPerMap(); i++) { 1357 VM.sysWrite(jsrInfo.unusualReferenceMaps[refMapIndex + i]); 1358 } 1359 VM.sysWrite("\n"); 1360 1361 VM.sysWrite(" -jsr total set2nonref delta map = "); 1362 for (i = 0; i < bytesPerMap(); i++) { 1363 VM.sysWrite(jsrInfo.unusualReferenceMaps[nonRefMapIndex + i]); 1364 } 1365 VM.sysWrite("\n"); 1366 1367 VM.sysWrite(" -jsr base map = "); 1368 for (i = 0; i < bytesPerMap(); i++) { 1369 // ORIGINAL VM.sysWrite( jsrInfo.unusualReferenceMaps[jsrBaseMapIndex + i]); 1370 VM.sysWrite(referenceMaps[jsrBaseMapIndex + i]); 1371 } 1372 VM.sysWrite("\n"); 1373 1374 VM.sysWrite(" -combined merged ref map = "); 1375 for (i = 0; i < bytesPerMap(); i++) { 1376 VM.sysWrite(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i]); 1377 } 1378 VM.sysWrite("\n"); 1379 1380 VM.sysWrite(" -combined merged return address map = "); 1381 for (i = 0; i < bytesPerMap(); i++) { 1382 VM.sysWrite(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i]); 1383 } 1384 VM.sysWrite("\n"); 1385 } 1386 } 1387 1388 /** 1389 * This routine is used to clean out the MethodMap of structures that 1390 * were allocated from temporary storage. Temporary storage is freed up 1391 * between stack frames as the GC scans the stack. 1392 */ 1393 public void cleanupPointers() { 1394 if (VM.TraceStkMaps) VM.sysWrite("ReferenceMaps- cleanupPointers\n"); 1395 } 1396 1397 /** 1398 * This routine is used to find an Unusual map with an index 1399 * greater than 127 1400 * 1401 */ 1402 1403 /** 1404 * Finds an unsual map with an index greater than 127. It returns the index 1405 * by doing a sequential scan and looking for the mapid in the normal map 1406 * directory. 1407 * 1408 * @param mapid the map's id 1409 * @return the map's index 1410 */ 1411 int findUnusualMap(int mapid) { 1412 int i; 1413 // Greater than 127 map sites- can't use direct index. 1414 // Do sequential scan for rest of maps. It's slow but should almost never 1415 // happen. 1416 1417 for (i = JSR_INDEX_MASK; i < jsrInfo.numberUnusualMaps; i++) { 1418 if (jsrInfo.unusualMaps[i].getNormalMapIndex() == mapid) { 1419 break; 1420 } 1421 } 1422 if (i >= jsrInfo.numberUnusualMaps) { 1423 VM.sysFail(" can't find jsr map - PANIC !!!!"); 1424 } 1425 return i; 1426 } 1427 1428 /** 1429 * Shows the basic information for each of the maps. 1430 * This is for testing use. 1431 */ 1432 public void showInfo() { 1433 VM.sysWriteln("showInfo- reference maps"); 1434 if (MCSites == null) { 1435 VM.sysWrite(" no MCSites array - assume using cached data - can't do showInfo()"); 1436 return; 1437 } 1438 1439 VM.sysWrite(" MCSites.length = ", MCSites.length); 1440 VM.sysWrite(" mapCount = ", mapCount); 1441// VM.sysWriteln(" startLocal0Offset = ", startLocal0Offset); 1442 1443 for (int i = 0; i < mapCount; i++) { 1444 VM.sysWrite("mapid = ", i); 1445 VM.sysWrite(" - machine code offset ", MCSites[i]); 1446 VM.sysWrite(" -reference Map = "); 1447 for (int j = 0; j < bytesPerMap(); j++) { 1448 VM.sysWriteHex(referenceMaps[(i * bytesPerMap()) + j]); 1449 } 1450 VM.sysWriteln(); 1451 } 1452 } 1453 1454 /** 1455 * Show the basic information for a single map. This is for testing 1456 * use. 1457 * 1458 * @param MCSiteIndex index of the machine code site 1459 */ 1460 public void showAMap(int MCSiteIndex) { 1461 VM.sysWriteln("show the map for MCSite index= ", MCSiteIndex); 1462 VM.sysWrite("machine code offset = ", MCSites[MCSiteIndex]); 1463 VM.sysWrite(" reference Map = "); 1464 for (int i = 0; i < bytesPerMap(); i++) { 1465 VM.sysWrite(referenceMaps[(MCSiteIndex * bytesPerMap()) + i]); 1466 } 1467 VM.sysWriteln(); 1468 } 1469 1470 /** 1471 * Show the offsets for all the maps. This is for test use. 1472 */ 1473 public void showOffsets() { 1474 VM.sysWrite("in showOffset- #maps = "); 1475 VM.sysWrite(mapCount); 1476 VM.sysWrite("\n"); 1477 int i, tindex = 0; 1478 1479 if (mapCount == 0) { 1480 VM.sysWrite(" no maps for method"); 1481 return; 1482 } 1483 for (i = 0; i < mapCount; i++) { 1484 tindex = getNextRefIndex(tindex, i); 1485 VM.sysWrite("initial offset = "); 1486 VM.sysWrite(tindex); 1487 VM.sysWrite(" for map "); 1488 VM.sysWrite(i); 1489 VM.sysWrite("\n"); 1490 while (tindex != 0) { 1491 tindex = getNextRefIndex(tindex, i); 1492 VM.sysWrite("next offset = "); 1493 VM.sysWrite(tindex); 1494 if (tindex == 0) VM.sysWrite("---------------- end of map"); 1495 } 1496 } 1497 } 1498 1499 @Interruptible 1500 public int showReferenceMapStatistics(RVMMethod method) { 1501 int index = 0; 1502 int totalCount = 0; 1503 int count; 1504 1505 VM.sysWrite("-- Number of refs for method = "); 1506 VM.sysWrite(method.getDeclaringClass().getDescriptor()); 1507 VM.sysWrite("."); 1508 VM.sysWrite(method.getName()); 1509 VM.sysWrite("---------------------------\n"); 1510 1511 for (int i = 0; i < mapCount; i++) { 1512 byte mapindex = referenceMaps[i * bytesPerMap()]; 1513 if (mapindex < 0) { 1514 // check for non jsr map 1515 VM.sysWrite(" -----skipping jsr map------- \n "); 1516 continue; 1517 } 1518 index = getNextRefIndex(index, i); 1519 count = 0; 1520 while (index != 0) { 1521 totalCount++; 1522 count++; 1523 index = getNextRefIndex(index, i); 1524 // display number of refs at each site - very noisy 1525 if (index == 0) { 1526 VM.sysWriteln(" -----map machine code offset = ", MCSites[i], " number of refs in this map = ", count); 1527 } 1528 } 1529 } 1530 VM.sysWrite("----- Total number of refs in method = "); 1531 VM.sysWrite(totalCount); 1532 VM.sysWrite(" total number of maps in method = "); 1533 VM.sysWrite(mapCount); 1534 VM.sysWrite("\n"); 1535 1536 return totalCount; 1537 } 1538 1539 /* Interface for general queries such as given a GC point, if a stack slot 1540 * or a local variable is a reference. 1541 */ 1542 1543 /** 1544 * Query if a local variable has a reference type value 1545 * @param method The method we're asking about. 1546 * @param mcoff The machine code offset of the instruction *following* the 1547 * actual instruction. 1548 * @param lidx the local index 1549 * @return {@code true}, if it is a reference type. {@code false}, otherwise 1550 */ 1551 public boolean isLocalRefType(RVMMethod method, Offset mcoff, int lidx) { 1552 int bytenum, bitnum; 1553 byte[] maps; 1554 1555 if (bytesPerMap() == 0) return false; // no map ie no refs 1556 int mapid = locateGCPoint(mcoff, method); 1557 1558 if (mapid >= 0) { 1559 // normal case 1560 bytenum = mapid * bytesPerMap(); 1561 bitnum = lidx + 1 + 1; // 1 for being 1 based +1 for jsr bit 1562 maps = referenceMaps; 1563 } else { 1564 // in JSR 1565 bytenum = jsrInfo.mergedReferenceMap; 1566 bitnum = lidx + 1; // 1 for being 1 based 1567 maps = jsrInfo.unusualReferenceMaps; 1568 } 1569 1570 // adjust bitnum and wordnum to bit within word 1571 while (bitnum > BITS_PER_MAP_ELEMENT) { 1572 bytenum++; 1573 bitnum -= BITS_PER_MAP_ELEMENT; 1574 } 1575 1576 int mask = (1 << (BITS_PER_MAP_ELEMENT - bitnum)); // generate mask 1577 1578 return ((mask & maps[bytenum]) != 0); 1579 } 1580}