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; 014 015 import org.jikesrvm.mm.mminterface.Barriers; 016 import org.jikesrvm.runtime.Entrypoints; 017 import org.jikesrvm.runtime.Magic; 018 import org.jikesrvm.scheduler.Synchronization; 019 import org.vmmagic.pragma.Inline; 020 import org.vmmagic.pragma.Interruptible; 021 import org.vmmagic.pragma.NoInline; 022 import org.vmmagic.pragma.Uninterruptible; 023 import org.vmmagic.pragma.UninterruptibleNoWarn; 024 import org.vmmagic.unboxed.Offset; 025 026 /** 027 * Various service utilities. This is a common place for some shared utility routines 028 */ 029 @Uninterruptible 030 public class Services implements SizeConstants { 031 /** 032 * Biggest buffer you would possibly need for {@link org.jikesrvm.scheduler.RVMThread#dump(char[], int)} 033 * Modify this if you modify that method. 034 */ 035 public static final int MAX_DUMP_LEN = 036 10 /* for thread ID */ + 7 + 5 + 5 + 11 + 5 + 10 + 13 + 17 + 10; 037 038 /** Pre-allocate the dump buffer, since dump() might get called inside GC. */ 039 private static final char[] dumpBuffer = new char[MAX_DUMP_LEN]; 040 041 @SuppressWarnings({"unused", "CanBeFinal", "UnusedDeclaration"})// accessed via EntryPoints 042 private static int dumpBufferLock = 0; 043 044 /** Reset at boot time. */ 045 private static Offset dumpBufferLockOffset = Offset.max(); 046 047 /** 048 * A map of hexadecimal digit values to their character representations. 049 * <P> 050 * XXX We currently only use '0' through '9'. The rest are here pending 051 * possibly merging this code with the similar code in Log.java, or breaking 052 * this code out into a separate utility class. 053 */ 054 private static final char [] hexDigitCharacter = 055 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 056 'f' }; 057 058 /** 059 * How many characters we need to have in a buffer for building string 060 * representations of <code>long</code>s, such as {@link #intBuffer}. A 061 * <code>long</code> is a signed 64-bit integer in the range -2^63 to 062 * 2^63+1. The number of digits in the decimal representation of 2^63 is 063 * ceiling(log10(2^63)) == ceiling(63 * log10(2)) == 19. An extra character 064 * may be required for a minus sign (-). So the maximum number of characters 065 * is 20. 066 */ 067 private static final int INT_BUFFER_SIZE = 20; 068 069 /** A buffer for building string representations of <code>long</code>s */ 070 private static final char [] intBuffer = new char[INT_BUFFER_SIZE]; 071 072 /** A lock for {@link #intBuffer} */ 073 @SuppressWarnings({"unused", "CanBeFinal", "UnusedDeclaration"})// accessed via EntryPoints 074 private static int intBufferLock = 0; 075 076 /** The offset of {@link #intBufferLock} in this class's TIB. 077 * This is set properly at boot time, even though it's a 078 * <code>private</code> variable. . */ 079 private static Offset intBufferLockOffset = Offset.max(); 080 081 /** 082 * Called during the boot sequence, any time before we go multi-threaded. We 083 * do this so that we can leave the lockOffsets set to -1 until the VM 084 * actually needs the locking (and is running multi-threaded). 085 */ 086 public static void boot() { 087 dumpBufferLockOffset = Entrypoints.dumpBufferLockField.getOffset(); 088 intBufferLockOffset = Entrypoints.intBufferLockField.getOffset(); 089 } 090 091 public static char[] grabDumpBuffer() { 092 if (!dumpBufferLockOffset.isMax()) { 093 while (!Synchronization.testAndSet(Magic.getJTOC(), dumpBufferLockOffset, 1)) { 094 ; 095 } 096 } 097 return dumpBuffer; 098 } 099 100 public static void releaseDumpBuffer() { 101 if (!dumpBufferLockOffset.isMax()) { 102 Synchronization.fetchAndStore(Magic.getJTOC(), dumpBufferLockOffset, 0); 103 } 104 } 105 106 107 /** Copy a String into a character array. 108 * <p> 109 * This function may be called during GC and may be used in conjunction 110 * with the MMTk {@link org.mmtk.utility.Log} class. It avoids write barriers and allocation. 111 * <p> 112 * XXX This function should probably be moved to a sensible location where 113 * we can use it as a utility. Suggestions welcome. 114 * <P> 115 * 116 * @param dest char array to copy into. 117 * @param destOffset Offset into <code>dest</code> where we start copying 118 * 119 * @return 1 plus the index of the last character written. If we were to 120 * write zero characters (which we won't) then we would return 121 * <code>offset</code>. This is intended to represent the first 122 * unused position in the array <code>dest</code>. However, it also 123 * serves as a pseudo-overflow check: It may have the value 124 * <code>dest.length</code>, if the array <code>dest</code> was 125 * completely filled by the call, or it may have a value greater 126 * than <code>dest.length</code>, if the info needs more than 127 * <code>dest.length - offset</code> characters of space. 128 * 129 * @return -1 if <code>offset</code> is negative. 130 * 131 * the MMTk {@link org.mmtk.utility.Log} class). 132 */ 133 public static int sprintf(char[] dest, int destOffset, String s) { 134 final char[] sArray = java.lang.JikesRVMSupport.getBackingCharArray(s); 135 return sprintf(dest, destOffset, sArray); 136 } 137 138 public static int sprintf(char[] dest, int destOffset, char[] src) { 139 return sprintf(dest, destOffset, src, 0, src.length); 140 } 141 142 /** 143 * Copies characters from <code>src</code> into the destination character 144 * array <code>dest</code>.<p> 145 * 146 * The first character to be copied is at index <code>srcBegin</code>; the 147 * last character to be copied is at index <code>srcEnd-1</code>. (This is 148 * the same convention as followed by java.lang.String#getChars). 149 * 150 * @param dest char array to copy into. 151 * @param destOffset Offset into <code>dest</code> where we start copying 152 * @param src Char array to copy from 153 * @param srcStart index of the first character of <code>src</code> to copy. 154 * @param srcEnd index after the last character of <code>src</code> to copy. 155 */ 156 public static int sprintf(char[] dest, int destOffset, char[] src, int srcStart, int srcEnd) { 157 for (int i = srcStart; i < srcEnd; ++i) { 158 char nextChar = getArrayNoBarrier(src, i); 159 destOffset = sprintf(dest, destOffset, nextChar); 160 } 161 return destOffset; 162 } 163 164 public static int sprintf(char[] dest, int destOffset, char c) { 165 if (destOffset < 0) { 166 // bounds check 167 return -1; 168 } 169 170 if (destOffset < dest.length) { 171 setArrayNoBarrier(dest, destOffset, c); 172 } 173 return destOffset + 1; 174 } 175 176 /** 177 * Copy the printed decimal representation of a long into 178 * a character array. The value is not padded and no 179 * thousands separator is copied. If the value is negative a 180 * leading minus sign (-) is copied. 181 * <p> 182 * This function may be called during GC and may be used in conjunction 183 * with the Log class. It avoids write barriers and allocation. 184 * <p> 185 * XXX This function should probably be moved to a sensible location where 186 * we can use it as a utility. Suggestions welcome. 187 * <p> 188 * XXX This method's implementation is stolen from the {@link org.mmtk.utility.Log} class. 189 * 190 * @param dest char array to copy into. 191 * @param offset Offset into <code>dest</code> where we start copying 192 * 193 * @return 1 plus the index of the last character written. If we were to 194 * write zero characters (which we won't) then we would return 195 * <code>offset</code>. This is intended to represent the first 196 * unused position in the array <code>dest</code>. However, it also 197 * serves as a pseudo-overflow check: It may have the value 198 * <code>dest.length</code>, if the array <code>dest</code> was 199 * completely filled by the call, or it may have a value greater 200 * than <code>dest.length</code>, if the info needs more than 201 * <code>dest.length - offset</code> characters of space. 202 * 203 * @return -1 if <code>offset</code> is negative. 204 */ 205 public static int sprintf(char[] dest, int offset, long l) { 206 boolean negative = l < 0; 207 int nextDigit; 208 char nextChar; 209 int index = INT_BUFFER_SIZE - 1; 210 char[] intBuffer = grabIntBuffer(); 211 212 nextDigit = (int) (l % 10); 213 nextChar = getArrayNoBarrier(hexDigitCharacter, negative ? -nextDigit : nextDigit); 214 setArrayNoBarrier(intBuffer, index--, nextChar); 215 l = l / 10; 216 217 while (l != 0) { 218 nextDigit = (int) (l % 10); 219 nextChar = getArrayNoBarrier(hexDigitCharacter, negative ? -nextDigit : nextDigit); 220 setArrayNoBarrier(intBuffer, index--, nextChar); 221 l = l / 10; 222 } 223 224 if (negative) { 225 setArrayNoBarrier(intBuffer, index--, '-'); 226 } 227 228 int newOffset = sprintf(dest, offset, intBuffer, index + 1, INT_BUFFER_SIZE); 229 releaseIntBuffer(); 230 return newOffset; 231 } 232 233 /** 234 * Get exclusive access to {@link #intBuffer}, the buffer for building 235 * string representations of integers. 236 */ 237 private static char[] grabIntBuffer() { 238 if (!intBufferLockOffset.isMax()) { 239 while (!Synchronization.testAndSet(Magic.getJTOC(), intBufferLockOffset, 1)) { 240 ; 241 } 242 } 243 return intBuffer; 244 } 245 246 /** 247 * Release {@link #intBuffer}, the buffer for building string 248 * representations of integers. 249 */ 250 private static void releaseIntBuffer() { 251 if (!intBufferLockOffset.isMax()) { 252 Synchronization.fetchAndStore(Magic.getJTOC(), intBufferLockOffset, 0); 253 } 254 } 255 256 /** 257 * Utility printing function. 258 * @param i 259 * @param blank 260 */ 261 @Interruptible 262 public static String getHexString(int i, boolean blank) { 263 StringBuilder buf = new StringBuilder(8); 264 for (int j = 0; j < 8; j++, i <<= 4) { 265 int n = i >>> 28; 266 if (blank && (n == 0) && (j != 7)) { 267 buf.append(' '); 268 } else { 269 buf.append(Character.forDigit(n, 16)); 270 blank = false; 271 } 272 } 273 return buf.toString(); 274 } 275 276 @NoInline 277 public static void breakStub() { 278 } 279 280 static void println() { VM.sysWrite("\n"); } 281 282 static void print(String s) { VM.sysWrite(s); } 283 284 static void println(String s) { 285 print(s); 286 println(); 287 } 288 289 static void print(int i) { VM.sysWrite(i); } 290 291 static void println(int i) { 292 print(i); 293 println(); 294 } 295 296 static void print(String s, int i) { 297 print(s); 298 print(i); 299 } 300 301 static void println(String s, int i) { 302 print(s, i); 303 println(); 304 } 305 306 public static void percentage(int numerator, int denominator, String quantity) { 307 print("\t"); 308 if (denominator > 0) { 309 print((int) (((numerator) * 100.0) / (denominator))); 310 } else { 311 print("0"); 312 } 313 print("% of "); 314 println(quantity); 315 } 316 317 static void percentage(long numerator, long denominator, String quantity) { 318 print("\t"); 319 if (denominator > 0L) { 320 print((int) (((numerator) * 100.0) / (denominator))); 321 } else { 322 print("0"); 323 } 324 print("% of "); 325 println(quantity); 326 } 327 328 /** 329 * Sets an element of a object array without possibly losing control. 330 * NB doesn't perform checkstore or array index checking. 331 * 332 * @param dst the destination array 333 * @param index the index of the element to set 334 * @param value the new value for the element 335 */ 336 @UninterruptibleNoWarn("Interruptible code not reachable at runtime") 337 @Inline 338 public static void setArrayUninterruptible(Object[] dst, int index, Object value) { 339 if (VM.runningVM) { 340 if (Barriers.NEEDS_OBJECT_ASTORE_BARRIER) { 341 Barriers.objectArrayWrite(dst, index, value); 342 } else { 343 Magic.setObjectAtOffset(dst, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_ADDRESS), value); 344 } 345 } else { 346 dst[index] = value; 347 } 348 } 349 350 /** 351 * Sets an element of a char array without invoking any write 352 * barrier. This method is called by the Log method, as it will be 353 * used during garbage collection and needs to manipulate character 354 * arrays without causing a write barrier operation. 355 * 356 * @param dst the destination array 357 * @param index the index of the element to set 358 * @param value the new value for the element 359 */ 360 public static void setArrayNoBarrier(char[] dst, int index, char value) { 361 if (VM.runningVM) 362 Magic.setCharAtOffset(dst, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_CHAR), value); 363 else 364 dst[index] = value; 365 } 366 367 /** 368 * Gets an element of an Object array without invoking any read 369 * barrier or performing bounds checks. 370 * 371 * @param src the source array 372 * @param index the natural array index of the element to get 373 * @return the new value of element 374 */ 375 public static Object getArrayNoBarrier(Object[] src, int index) { 376 if (VM.runningVM) 377 return Magic.getObjectAtOffset(src, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_ADDRESS)); 378 else 379 return src[index]; 380 } 381 382 /** 383 * Gets an element of an int array without invoking any read barrier 384 * or performing bounds checks. 385 * 386 * @param src the source array 387 * @param index the natural array index of the element to get 388 * @return the new value of element 389 */ 390 public static int getArrayNoBarrier(int[] src, int index) { 391 if (VM.runningVM) 392 return Magic.getIntAtOffset(src, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_INT)); 393 else 394 return src[index]; 395 } 396 397 /** 398 * Gets an element of a char array without invoking any read barrier 399 * or performing bounds check. 400 * 401 * @param src the source array 402 * @param index the natural array index of the element to get 403 * @return the new value of element 404 */ 405 public static char getArrayNoBarrier(char[] src, int index) { 406 if (VM.runningVM) 407 return Magic.getCharAtOffset(src, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_CHAR)); 408 else 409 return src[index]; 410 } 411 412 /** 413 * Gets an element of a byte array without invoking any read barrier 414 * or bounds check. 415 * 416 * @param src the source array 417 * @param index the natural array index of the element to get 418 * @return the new value of element 419 */ 420 public static byte getArrayNoBarrier(byte[] src, int index) { 421 if (VM.runningVM) 422 return Magic.getByteAtOffset(src, Offset.fromIntZeroExtend(index)); 423 else 424 return src[index]; 425 } 426 427 /** 428 * Gets an element of an array of byte arrays without causing the potential 429 * thread switch point that array accesses normally cause. 430 * 431 * @param src the source array 432 * @param index the index of the element to get 433 * @return the new value of element 434 */ 435 public static byte[] getArrayNoBarrier(byte[][] src, int index) { 436 if (VM.runningVM) 437 return Magic.addressAsByteArray(Magic.objectAsAddress(Magic.getObjectAtOffset(src, Offset.fromIntZeroExtend(index << LOG_BYTES_IN_ADDRESS)))); 438 else 439 return src[index]; 440 } 441 }