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.mmtk.utility.deque; 014 015 import org.mmtk.policy.RawPageSpace; 016 017 import org.mmtk.vm.VM; 018 019 import org.vmmagic.pragma.*; 020 import org.vmmagic.unboxed.*; 021 022 /** 023 * This supports <i>unsynchronized</i> enqueuing and dequeuing of buffers 024 * for shared use. The data can be added to and removed from either end 025 * of the deque. This class is based upon the SharedQueue class. The sorting 026 * routines were modified from code written by Narendran Sachindran and 027 * Matthew Hertz for GCTk. 028 */ 029 @Uninterruptible public abstract class SortSharedDeque extends SharedDeque { 030 031 032 private static final int BYTES_PUSHED = BYTES_IN_ADDRESS * 5; 033 private static final int MAX_STACK_SIZE = BYTES_PUSHED * 64; 034 private static final Offset INSERTION_SORT_LIMIT = Offset.fromIntSignExtend(80); 035 036 /*********************************************************************** 037 * 038 * Class variables 039 */ 040 041 /** 042 * Constructor 043 * 044 * @param rps The space from which the instance should obtain buffers. 045 */ 046 public SortSharedDeque(String name, RawPageSpace rps, int arity) { 047 super(name, rps, arity); 048 stackBase = AddressArray.create(MAX_STACK_SIZE); 049 stackLoc = 0; 050 } 051 052 /*********************************************************************** 053 * 054 * Sorting methods, utilities, and instance variables 055 */ 056 057 058 /** 059 * Return the sorting key for the object passed as a parameter. 060 * 061 * @param obj The address of the object whose key is wanted 062 * @return The value of the sorting key for this object 063 */ 064 protected abstract Word getKey(Address obj); 065 066 private static final Word mask16 = Word.fromIntZeroExtend(0xffff0000); 067 private static final Word mask8 = Word.fromIntZeroExtend(0x0000ff00); 068 private static final Word mask4 = Word.fromIntZeroExtend(0x000000f0); 069 private static final Word mask2 = Word.fromIntZeroExtend(0x0000000c); 070 private static final Word mask1 = Word.fromIntZeroExtend(0x00000002); 071 072 /** 073 * Find the highest bit that is set in a longword and return a mask 074 * with only that bit set. 075 * 076 * @param addr Value for which the mask needs to be found 077 * @return The highest bit set in the parameter 078 */ 079 private static Word getBitMask(Word addr) { 080 int shift = 0; 081 if (!addr.and(mask16).isZero()) { 082 addr = addr.rshl(16); 083 shift += 16; 084 } 085 if (!addr.and(mask8).isZero()) { 086 addr = addr.rshl(8); 087 shift += 8; 088 } 089 if (!addr.and(mask4).isZero()) { 090 addr = addr.rshl(4); 091 shift += 4; 092 } 093 if (!addr.and(mask2).isZero()) { 094 addr = addr.rshl(2); 095 shift += 2; 096 } 097 if (!addr.and(mask1).isZero()) { 098 shift += 1; 099 } 100 return (Word.one().lsh(shift)); 101 } 102 103 /** 104 * Perform insertion sort within an intra-block address range. 105 * 106 * @param begin Start address of the range to be sorted 107 * @param end End address of the range to be sorted 108 */ 109 private void insertionSort(Address begin, Address end) { 110 Address rPtr = begin.minus(BYTES_IN_ADDRESS); 111 Address lPtr; 112 113 while (rPtr.GE(end)) { 114 Address rSlot = rPtr.loadAddress(); 115 Word rKey = getKey(rSlot); 116 lPtr = rPtr.plus(BYTES_IN_ADDRESS); 117 while (lPtr.LE(begin)) { 118 Address lSlot = lPtr.loadAddress(); 119 Word lKey = getKey(lSlot); 120 if (lKey.GT(rKey)) { 121 lPtr.minus(BYTES_IN_ADDRESS).store(lSlot); 122 lPtr = lPtr.plus(BYTES_IN_ADDRESS); 123 } else { 124 break; 125 } 126 } 127 lPtr.minus(BYTES_IN_ADDRESS).store(rSlot); 128 rPtr = rPtr.minus(BYTES_IN_ADDRESS); 129 } 130 } 131 132 /** 133 * Sort objects using radix exchange sort. An explicit stack is 134 * maintained to avoid using recursion. 135 */ 136 public void sort() { 137 Address startPtr, startLink, endPtr, endLink; 138 Word bitMask; 139 if (!head.EQ(HEAD_INITIAL_VALUE)) { 140 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(tail.NE(TAIL_INITIAL_VALUE)); 141 /* Obtain the bitmask for the first iteration and save the start & 142 end pointers and the bitmask on the stack */ 143 initStack(); 144 startPtr = popStack(); 145 while (!startPtr.isZero()) { 146 startLink = popStack(); 147 endPtr = popStack(); 148 endLink = popStack(); 149 bitMask = (popStack()).toWord(); 150 if (startLink.NE(endLink)) { 151 partition(startPtr, startLink, endPtr, endLink, bitMask); 152 } else if (startPtr.GT(endPtr)) { 153 /* Use insertionSort for a limited number of objects within 154 a single block */ 155 if (startPtr.diff(endPtr).sLT(INSERTION_SORT_LIMIT)) { 156 insertionSort(startPtr, endPtr); 157 } else { 158 partition(startPtr, startLink, endPtr, endLink, bitMask); 159 } 160 } 161 // Get the next set of data to sort 162 startPtr = popStack(); 163 } 164 } 165 checkIfSorted(); 166 } 167 168 /** 169 * Partition the slots in an address range based on the value in 170 * a particular bit. Place the start & end addresses of the two 171 * partitions & a bitmask per partition (which indicates the highest 172 * bit position at which the max & min of a partition differ) on the 173 * stack. This works just like the partition in quick sort, except 174 * that a bit value is being compared here 175 * 176 * @param startAddr The start address of the range to be sorted 177 * @param startLinkAddr The address where the start block has its next field 178 * @param endAddr The end address of the range to be sorted 179 * @param endLinkAddr The address where the end block has its next field 180 * @param bitMask The mask in which the bit to be commpared is set 181 */ 182 private void partition(Address startAddr, Address startLinkAddr, 183 Address endAddr, Address endLinkAddr, 184 Word bitMask) { 185 Address travPtr = endAddr; 186 Address travLink = endLinkAddr; 187 Address stopPtr = startAddr; 188 Address stopLink = startLinkAddr; 189 Address travSlot, stopSlot; 190 Word travKey, stopKey; 191 Word lmax = Word.zero(), rmax = Word.zero(); 192 Word lmin = Word.max(), rmin = Word.max(); 193 194 while (true) { 195 /* Compute the address range within the current block to compute. */ 196 Address endOfBlock = travLink; 197 198 /* Move the left pointer until the right pointer is reached 199 or an address with a 0 value in the bit position is found. */ 200 while (true) { 201 travSlot = travPtr.loadAddress(); 202 travKey = getKey(travSlot); 203 204 /* If we reach the end. */ 205 if (travPtr.EQ(stopPtr)) 206 break; 207 /* If we found a 0 in bit position, break. */ 208 if (travKey.and(bitMask).isZero()) 209 break; 210 if (travKey.GT(rmax)) 211 rmax = travKey; 212 if (travKey.LT(rmin)) 213 rmin = travKey; 214 /* Move to the next entry. */ 215 travPtr = travPtr.plus(BYTES_IN_ADDRESS); 216 /* If at end of remset block, move to next block */ 217 if (travPtr.EQ(endOfBlock)) { 218 travLink = getPrev(travPtr); 219 endOfBlock = travLink; 220 travPtr = bufferStart(endOfBlock); 221 } 222 } 223 224 /* Store the end of the block. */ 225 endOfBlock = bufferStart(stopPtr); 226 /* Move the right pointer until the left pointer is reached 227 or an address with a 1 value in the bit position is found. */ 228 while (true) { 229 stopSlot = stopPtr.loadAddress(); 230 stopKey = getKey(stopSlot); 231 /* Found a 1 in bit position, break. */ 232 if (!stopKey.and(bitMask).isZero()) 233 break; 234 if (stopKey.GT(lmax)) 235 lmax = stopKey; 236 if (stopKey.LT(lmin)) 237 lmin = stopKey; 238 if (stopPtr.EQ(travPtr)) 239 break; 240 /* Move to the next entry, which may be in the next block. */ 241 if (stopPtr.EQ(endOfBlock)) { 242 stopLink = getNext(stopLink); 243 stopPtr = stopLink; 244 endOfBlock = bufferStart(stopPtr); 245 } 246 stopPtr = stopPtr.minus(BYTES_IN_ADDRESS); 247 } 248 if (stopPtr.EQ(travPtr)) 249 break; 250 /* interchange the values pointed to by the left and right pointers */ 251 travPtr.store(stopSlot); 252 stopPtr.store(travSlot); 253 } 254 255 /* If max value is not equal to the min value in the right partition, 256 (not all slots are identical) push the right partition on to the stack */ 257 if (rmax.GT(rmin)) { 258 if (travPtr.EQ(bufferStart(travPtr))) { 259 stopLink = getNext(travLink); 260 stopPtr = stopLink; 261 } else { 262 stopLink = travLink; 263 stopPtr = travPtr; 264 } 265 pushOnStack(getBitMask(rmax.xor(rmin)).toAddress()); 266 pushOnStack(endLinkAddr); 267 pushOnStack(endAddr); 268 pushOnStack(stopLink); 269 pushOnStack(stopPtr.minus(BYTES_IN_ADDRESS)); 270 } 271 /* if max value is not equal to the min value in the left partition, 272 (not all slots are identical) push the left partition on to the stack */ 273 if (lmax.GT(lmin)) { 274 pushOnStack(getBitMask(lmax.xor(lmin)).toAddress()); 275 pushOnStack(travLink); 276 pushOnStack(travPtr); 277 pushOnStack(startLinkAddr); 278 pushOnStack(startAddr); 279 } 280 } 281 282 /************************************************************************* 283 * 284 * Sorting Stack management routines 285 */ 286 287 /** 288 * 289 */ 290 private int stackLoc; 291 private AddressArray stackBase; 292 293 /* 294 * Allocate memory for the stack and initialize it with the first range 295 * to partition 296 */ 297 private void initStack() { 298 stackLoc = 0; 299 300 Address endOfBlock = tail; 301 Address startPtr = bufferStart(endOfBlock); 302 Word min = Word.max(); 303 Word max = Word.zero(); 304 // Find the max. and min addresses in the object buffer 305 while (endOfBlock.NE(HEAD_INITIAL_VALUE)) { 306 startPtr = bufferStart(endOfBlock); 307 while (startPtr.LT(endOfBlock)) { 308 Address startSlot = startPtr.loadAddress(); 309 Word startKey = getKey(startSlot); 310 if (startKey.GT(max)) 311 max = startKey; 312 if (startKey.LT(min)) 313 min = startKey; 314 startPtr = startPtr.plus(BYTES_IN_ADDRESS); 315 } 316 endOfBlock = getPrev(startPtr); 317 } 318 319 // If max and min are different (not all elements are equal), push the 320 // start, end and bitmask values on the stack 321 if (max.GT(min)) { 322 pushOnStack(getBitMask(max.xor(min)).toAddress()); 323 pushOnStack(tail); 324 pushOnStack(bufferStart(tail)); 325 pushOnStack(startPtr); 326 pushOnStack(startPtr.minus(BYTES_IN_ADDRESS)); 327 } 328 } 329 330 /** 331 * Push an address on to the stack 332 * 333 * @param val The address to be pushed 334 */ 335 private void pushOnStack(Address val) { 336 stackBase.set(stackLoc, val); 337 stackLoc++; 338 } 339 340 /** 341 * Pop an address from the stack 342 * 343 * @return The address at the top of the stack, or 0 if stack is empty 344 */ 345 private Address popStack() { 346 if (stackLoc == 0) 347 return Address.zero(); 348 stackLoc--; 349 return stackBase.get(stackLoc); 350 } 351 352 /** 353 * Debug routine, used to check if the object buffer is sorted correctly in 354 * decreasing final reference deletion time 355 */ 356 private void checkIfSorted() { 357 if (VM.VERIFY_ASSERTIONS) { 358 Address buf, end; 359 Word prevKey = Word.max(); 360 end = tail; 361 buf = bufferStart(end); 362 while (buf.NE(HEAD_INITIAL_VALUE)) { 363 // iterate through the block 364 while (buf.LT(end)) { 365 Address slot = buf.loadAddress(); 366 Word key = getKey(slot); 367 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(key.LE(prevKey)); 368 prevKey = key; 369 buf = buf.plus(BYTES_IN_ADDRESS); 370 } 371 end = getPrev(end); 372 buf = bufferStart(end); 373 } 374 } 375 } 376 }