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; 014 015 import org.mmtk.vm.VM; 016 017 import org.vmmagic.unboxed.*; 018 import org.vmmagic.pragma.*; 019 020 /** 021 * Error and trace logging. 022 */ 023 @Uninterruptible 024 public class Log implements Constants { 025 026 /**************************************************************************** 027 * 028 * Class variables 029 */ 030 031 /** 032 * characters in the write buffer for the caller's message. This 033 * does not include characters reserved for the overflow message.<p> 034 * 035 * This needs to be large because Jikes RVM's implementation of Lock.java 036 * logs a lot of information when there is potential GC deadlock. 037 */ 038 private static final int MESSAGE_BUFFER_SIZE = 3000; 039 040 /** message added when the write buffer has overflown */ 041 private static final String OVERFLOW_MESSAGE = "... WARNING: Text truncated.\n"; 042 043 private static final char OVERFLOW_MESSAGE_FIRST_CHAR = OVERFLOW_MESSAGE.charAt(0); 044 045 /** characters in the overflow message, including the (optional) final 046 * newline */ 047 private static final int OVERFLOW_SIZE = OVERFLOW_MESSAGE.length(); 048 049 /** 050 * characters in buffer for building string representations of 051 * longs. A long is a signed 64-bit integer in the range -2^63 to 052 * 2^63+1. The number of digits in the decimal representation of 053 * 2^63 is ceiling(log10(2^63)) == ceiling(63 * log10(2)) == 19. An 054 * extra character may be required for a minus sign (-). So the 055 * maximum number of characters is 20. 056 */ 057 private static final int TEMP_BUFFER_SIZE = 20; 058 059 /** string that prefixes numbers logged in hexadecimal */ 060 private static final String HEX_PREFIX = "0x"; 061 062 /** 063 * log2 of number of bits represented by a single hexidemimal digit 064 */ 065 private static final int LOG_BITS_IN_HEX_DIGIT = 2; 066 067 /** 068 * log2 of number of digits in the unsigned hexadecimal 069 * representation of a byte 070 */ 071 private static final int LOG_HEX_DIGITS_IN_BYTE = LOG_BITS_IN_BYTE - LOG_BITS_IN_HEX_DIGIT; 072 073 /** 074 * map of hexadecimal digit values to their character representations 075 */ 076 private static final char [] hexDigitCharacter = 077 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 078 079 /** new line character. Emitted by writeln methods. */ 080 private static final char NEW_LINE_CHAR = '\n'; 081 082 /** log instance used at build time. */ 083 private static Log log = new Log(); 084 085 /**************************************************************************** 086 * 087 * Instance variables 088 */ 089 090 /** buffer to store written message until flushing */ 091 private char [] buffer = new char[MESSAGE_BUFFER_SIZE + OVERFLOW_SIZE]; 092 093 /** location of next character to be written */ 094 private int bufferIndex = 0; 095 096 /** <code>true</code> if the buffer has overflown */ 097 private boolean overflow = false; 098 099 /** The last character that was written by #addToBuffer(char). This is 100 used to check whether we want to newline-terminate the text. */ 101 private char overflowLastChar = '\0'; 102 103 /** <code>true</code> if a thread id will be prepended */ 104 private boolean threadIdFlag = false; 105 106 /** buffer for building string representations of longs */ 107 private char[] tempBuffer = new char[TEMP_BUFFER_SIZE]; 108 109 /** constructor */ 110 public Log() { 111 for (int i = 0; i < OVERFLOW_SIZE; i++) { 112 buffer[MESSAGE_BUFFER_SIZE + i] = OVERFLOW_MESSAGE.charAt(i); 113 } 114 } 115 116 /** 117 * writes a boolean. Either "true" or "false" is logged. 118 * 119 * @param b boolean value to be logged. 120 */ 121 public static void write(boolean b) { 122 write(b ? "true" : "false"); 123 } 124 125 /** 126 * writes a character 127 * 128 * @param c character to be logged 129 */ 130 public static void write(char c) { 131 add(c); 132 } 133 134 /** 135 * writes a long, in decimal. The value is not padded and no 136 * thousands separator is logged. If the value is negative a 137 * leading minus sign (-) is logged. 138 * 139 * 140 * @param l long value to be logged 141 */ 142 public static void write(long l) { 143 boolean negative = l < 0; 144 int nextDigit; 145 char nextChar; 146 int index = TEMP_BUFFER_SIZE - 1; 147 char[] intBuffer = getIntBuffer(); 148 149 nextDigit = (int) (l % 10); 150 nextChar = hexDigitCharacter[negative ? - nextDigit : nextDigit]; 151 intBuffer[index--] = nextChar; 152 l = l / 10; 153 154 while (l != 0) { 155 nextDigit = (int) (l % 10); 156 nextChar = hexDigitCharacter[negative ? - nextDigit : nextDigit]; 157 intBuffer[index--] = nextChar; 158 l = l / 10; 159 } 160 161 if (negative) { 162 intBuffer[index--] = '-'; 163 } 164 165 for (index++; index < TEMP_BUFFER_SIZE; index++) { 166 add(intBuffer[index]); 167 } 168 } 169 170 /** 171 * writes a <code>double</code>. Two digits after the decimal point 172 * are always logged. The value is not padded and no thousands 173 * separator is used. If the value is negative a leading 174 * hyphen-minus (-) is logged. The decimal point is a full stop 175 * (.). 176 * 177 * @param d the double to be logged 178 */ 179 public static void write(double d) { write(d, 2); } 180 181 /** 182 * writes a <code>double</code>. The number of digits after the 183 * decimal point is determined by <code>postDecimalDigits</code>. 184 * The value is not padded and not thousands separator is used. If 185 * the value is negative a leading hyphen-minus (-) is logged. The 186 * decimal point is a full stop (.) and is logged even if 187 * <postDecimcalDigits</code> is zero. If <code>d</code> is greater 188 * than the largest representable value of type <code>int</code>, it 189 * is logged as "TooBig". Similarly, if it is less than 190 * the negative of the largest representable value, it is logged as 191 * "TooSmall". If <code>d</code> is NaN is is logged as "NaN". 192 * 193 * @param d the double to be logged 194 * @param postDecimalDigits the number of digits to be logged after 195 * the decimal point. If less than or equal to zero no digits are 196 * logged, but the decimal point is. 197 */ 198 public static void write(double d, int postDecimalDigits) { 199 if (d != d) { 200 write("NaN"); 201 return; 202 } 203 if (d > Integer.MAX_VALUE) { 204 write("TooBig"); 205 return; 206 } 207 if (d < -Integer.MAX_VALUE) { 208 write("TooSmall"); 209 return; 210 } 211 212 boolean negative = (d < 0.0); 213 d = negative ? (-d) : d; // Take absolute value 214 int ones = (int) d; 215 int multiplier = 1; 216 while (postDecimalDigits-- > 0) 217 multiplier *= 10; 218 int remainder = (int) (multiplier * (d - ones)); 219 if (remainder < 0) remainder = 0; 220 if (negative) write('-'); 221 write(ones); 222 write('.'); 223 while (multiplier > 1) { 224 multiplier /= 10; 225 write(remainder / multiplier); 226 remainder %= multiplier; 227 } 228 } 229 230 /** 231 * writes an array of characters 232 * 233 * @param c the array of characters to be logged 234 */ 235 public static void write(char[] c) { 236 write(c, c.length); 237 } 238 239 /** 240 * writes the start of an array of characters 241 * 242 * @param c the array of characters 243 * @param len the number of characters to be logged, starting with 244 * the first character 245 */ 246 public static void write(char[] c, int len) { 247 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(len <= c.length); 248 for (int i = 0; i < len; i++) { 249 add(c[i]); 250 } 251 } 252 253 /** 254 * writes an array of bytes. The bytes are interpretted 255 * as characters. 256 * 257 * @param b the array of bytes to be logged 258 */ 259 public static void write(byte[] b) { 260 for (int i = 0; i < b.length; i++) { 261 add((char)b[i]); 262 } 263 } 264 265 /** 266 * writes a string 267 * 268 * @param s the string to be logged 269 */ 270 public static void write(String s) { 271 add(s); 272 } 273 274 /** 275 * writes a word, in hexadecimal. It is zero-padded to the size of 276 * an address. 277 * 278 * @param w the word to be logged 279 */ 280 public static void write(Word w) { 281 writeHex(w, BYTES_IN_ADDRESS); 282 } 283 284 /** 285 * writes a word, in decimal. 286 * 287 * @param w the word to be logged 288 */ 289 public static void writeDec(Word w) { 290 if (BYTES_IN_ADDRESS == 4) { 291 write(w.toInt()); 292 } else { 293 write(w.toLong()); 294 } 295 } 296 297 /** 298 * writes an address, in hexadecimal. It is zero-padded. 299 * 300 * @param a the address to be logged 301 */ 302 public static void write(Address a) { 303 writeHex(a.toWord(), BYTES_IN_ADDRESS); 304 } 305 306 /** 307 * writes a string followed by an address, in hexadecimal. 308 * @see #write(String) 309 * @see #write(Address) 310 * 311 * @param s the string to be logged 312 * @param a the address to be logged 313 */ 314 public static void write(String s, Address a) { 315 write(s); 316 write(a); 317 } 318 319 /** 320 * Write a string followed by a long 321 * @see #write(String) 322 * @see #write(long) 323 * 324 * @param s the string to be logged 325 * @param l the long to be logged 326 */ 327 public static void write(String s, long l) { 328 write(s); 329 write(l); 330 } 331 332 /** 333 * writes an object reference, in hexadecimal. It is zero-padded. 334 * 335 * @param o the object reference to be logged 336 */ 337 public static void write(ObjectReference o) { 338 writeHex(o.toAddress().toWord(), BYTES_IN_ADDRESS); 339 } 340 341 /** 342 * writes an offset, in hexadecimal. It is zero-padded. 343 * 344 * @param o the offset to be logged 345 */ 346 public static void write(Offset o) { 347 writeHex(o.toWord(), BYTES_IN_ADDRESS); 348 } 349 350 /** 351 * writes an extent, in hexadecimal. It is zero-padded. 352 * 353 * @param e the extent to be logged 354 */ 355 public static void write(Extent e) { 356 writeHex(e.toWord(), BYTES_IN_ADDRESS); 357 } 358 359 /** 360 * write a new-line and flushes the buffer 361 */ 362 public static void writeln() { 363 writelnWithFlush(true); 364 } 365 366 /** 367 * writes a boolean and a new-line, then flushes the buffer. 368 * @see #write(boolean) 369 * 370 * @param b boolean value to be logged. 371 */ 372 public static void writeln(boolean b) { writeln(b, true); } 373 374 /** 375 * writes a character and a new-line, then flushes the buffer. 376 * @see #write(char) 377 * 378 * @param c character to be logged 379 */ 380 public static void writeln(char c) { writeln(c, true); } 381 382 /** 383 * writes a long, in decimal, and a new-line, then flushes the buffer. 384 * @see #write(long) 385 * 386 * @param l long value to be logged 387 */ 388 public static void writeln(long l) { writeln(l, true); } 389 390 /** 391 * writes a <code>double</code> and a new-line, then flushes the buffer. 392 * @see #write(double) 393 * 394 * @param d the double to be logged 395 */ 396 public static void writeln(double d) { writeln(d, true); } 397 398 /** 399 * writes a <code>double</code> and a new-line, then flushes the buffer. 400 * @see #write(double, int) 401 * 402 * @param d the double to be logged 403 */ 404 public static void writeln(double d, int postDecimalDigits) { 405 writeln(d, postDecimalDigits, true); } 406 407 /** 408 * writes an array of characters and a new-line, then flushes the buffer. 409 * @see #write(char []) 410 * 411 * @param ca the array of characters to be logged 412 */ 413 public static void writeln(char [] ca) { writeln(ca, true); } 414 415 /** 416 * writes the start of an array of characters and a new-line, then 417 * flushes the buffer. 418 * @see #write(char[], int) 419 * 420 * @param ca the array of characters 421 * @param len the number of characters to be logged, starting with 422 * the first character 423 */ 424 public static void writeln(char [] ca, int len) { writeln(ca, len, true); } 425 426 /** 427 * writes an array of bytes and a new-line, then 428 * flushes the buffer. 429 * @see #write(byte[]) 430 * 431 * @param b the array of bytes to be logged 432 */ 433 public static void writeln(byte [] b) { writeln(b, true); } 434 435 /** 436 * writes a string and a new-line, then flushes the buffer. 437 * 438 * @param s the string to be logged 439 */ 440 public static void writeln(String s) { writeln(s, true); } 441 442 /** 443 * writes a word, in hexadecimal, and a new-line, then flushes the buffer. 444 * @see #write(Word) 445 * 446 * @param w the word to be logged 447 */ 448 public static void writeln(Word w) { writeln(w, true); } 449 450 /** 451 * writes an address, in hexadecimal, and a new-line, then flushes 452 * the buffer. 453 * @see #write(Address) 454 * 455 * @param a the address to be logged 456 */ 457 public static void writeln(Address a) { writeln(a, true); } 458 459 /** 460 * writes an object reference, in hexadecimal, and a new-line, then 461 * flushes the buffer. 462 * @see #write(ObjectReference) 463 * 464 * @param o the object reference to be logged 465 */ 466 public static void writeln(ObjectReference o) { writeln(o, true); } 467 468 /** 469 * writes an offset, in hexadecimal, and a new-line, then flushes the buffer. 470 * @see #write(Offset) 471 * 472 * @param o the offset to be logged 473 */ 474 public static void writeln(Offset o) { writeln(o, true); } 475 476 /** 477 * writes an extent, in hexadecimal, and a new-line, then flushes the buffer. 478 * @see #write(Extent) 479 * 480 * @param e the extent to be logged 481 */ 482 public static void writeln(Extent e) { writeln(e, true); } 483 484 /** 485 * writes a new-line without flushing the buffer 486 */ 487 public static void writelnNoFlush() { 488 writelnWithFlush(false); 489 } 490 491 /** 492 * writes a boolean and a new-line, then optionally flushes the buffer. 493 * @see #write(boolean) 494 * 495 * @param b boolean value to be logged. 496 * @param flush if <code>true</code> then flushes the buffer 497 */ 498 public static void writeln(boolean b, boolean flush) { 499 write(b); 500 writelnWithFlush(flush); 501 } 502 503 /** 504 * writes a character and a new-line, then optionally flushes the 505 * buffer. 506 * @see #write(char) 507 * 508 * @param c character to be logged 509 * @param flush if <code>true</code> then flushes the buffer 510 */ 511 public static void writeln(char c, boolean flush) { 512 write(c); 513 writelnWithFlush(flush); 514 } 515 516 /** 517 * writes a long, in decimal, and a new-line, then optionally flushes 518 * the buffer. 519 * @see #write(long) 520 * 521 * @param l long value to be logged 522 * @param flush if <code>true</code> then flushes the buffer 523 */ 524 public static void writeln(long l, boolean flush) { 525 write(l); 526 writelnWithFlush(flush); 527 } 528 529 /** 530 * writes a <code>double</code> and a new-line, then optionally flushes 531 * the buffer. 532 * @see #write(double) 533 * 534 * @param d the double to be logged 535 * @param flush if <code>true</code> then flush the buffer 536 */ 537 public static void writeln(double d, boolean flush) { 538 write(d); 539 writelnWithFlush(flush); 540 } 541 542 /** 543 * writes a <code>double</code> and a new-line, then optionally flushes 544 * the buffer. 545 * @see #write(double, int) 546 * 547 * @param d the double to be logged 548 * @param flush if <code>true</code> then flushes the buffer 549 */ 550 public static void writeln(double d, int postDecimalDigits, boolean flush) { 551 write(d, postDecimalDigits); 552 writelnWithFlush(flush); 553 } 554 555 556 /** 557 * writes an array of characters and a new-line, then optionally 558 * flushes the buffer. 559 * @see #write(char []) 560 * 561 * @param ca the array of characters to be logged 562 * @param flush if <code>true</code> then flushes the buffer 563 */ 564 public static void writeln(char[] ca, boolean flush) { 565 write(ca); 566 writelnWithFlush(flush); 567 } 568 569 /** 570 * writes the start of an array of characters and a new-line, then 571 * optionally flushes the buffer. 572 * @see #write(char[], int) 573 * 574 * @param ca the array of characters 575 * @param len the number of characters to be logged, starting with 576 * the first character 577 * @param flush if <code>true</code> then flushes the buffer 578 */ 579 public static void writeln(char[] ca, int len, boolean flush) { 580 write(ca, len); 581 writelnWithFlush(flush); 582 } 583 584 /** 585 * writes an array of bytes and a new-line, then optionally flushes the 586 * buffer. 587 * @see #write(byte[]) 588 * 589 * @param b the array of bytes to be logged 590 * @param flush if <code>true</code> then flushes the buffer 591 */ 592 public static void writeln(byte[] b, boolean flush) { 593 write(b); 594 writelnWithFlush(flush); 595 } 596 597 /** 598 * writes a string and a new-line, then optionally flushes the buffer. 599 * 600 * @param s the string to be logged 601 * @param flush if <code>true</code> then flushes the buffer 602 */ 603 public static void writeln(String s, boolean flush) { 604 write(s); 605 writelnWithFlush(flush); 606 } 607 608 public static void writeln(String s, long l) { 609 write(s); 610 writeln(l); 611 } 612 613 614 /** 615 * writes a word, in hexadecimal, and a new-line, then optionally 616 * flushes the buffer. 617 * @see #write(Word) 618 * 619 * @param w the word to be logged 620 * @param flush if <code>true</code> then flushes the buffer 621 */ 622 public static void writeln(Word w, boolean flush) { 623 write(w); 624 writelnWithFlush(flush); 625 } 626 627 628 /** 629 * writes an address, in hexadecimal, and a new-line, then optionally 630 * flushes the buffer. 631 * @see #write(Address) 632 * 633 * @param a the address to be logged 634 * @param flush if <code>true</code> then flushes the buffer 635 */ 636 public static void writeln(Address a, boolean flush) { 637 write(a); 638 writelnWithFlush(flush); 639 } 640 641 /** 642 * writes an object reference, in hexadecimal, and a new-line, then 643 * optionally flushes the buffer. 644 * @see #write(ObjectReference) 645 * 646 * @param o the object reference to be logged 647 * @param flush if <code>true</code> then flushes the buffer 648 */ 649 public static void writeln(ObjectReference o, boolean flush) { 650 write(o); 651 writelnWithFlush(flush); 652 } 653 654 /** 655 * writes an offset, in hexadecimal, and a new-line, then optionally 656 * flushes the buffer. 657 * @see #write(Offset) 658 * 659 * @param o the offset to be logged 660 * @param flush if <code>true</code> then flushes the buffer 661 */ 662 public static void writeln(Offset o, boolean flush) { 663 write(o); 664 writelnWithFlush(flush); 665 } 666 667 /** 668 * writes an extent, in hexadecimal, and a new-line, then optionally 669 * flushes the buffer. 670 * @see #write(Extent) 671 * 672 * @param e the extent to be logged 673 * @param flush if <code>true</code> then flushes the buffer 674 */ 675 public static void writeln(Extent e, boolean flush) { 676 write(e); 677 writelnWithFlush(flush); 678 } 679 680 /** 681 * writes a string followed by a Address 682 * @see #write(String) 683 * @see #write(Address) 684 * 685 * @param s the string to be logged 686 * @param a the Address to be logged 687 */ 688 public static void writeln(String s, Address a) { 689 write(s); 690 writeln(a); 691 } 692 693 /** 694 * Log a thread identifier at the start of the next message flushed. 695 */ 696 public static void prependThreadId() { 697 getLog().setThreadIdFlag(); 698 } 699 700 /** 701 * flushes the buffer. The buffered effected of writes since the last 702 * flush will be logged in one block without output from other 703 * thread's logging interleaving. 704 */ 705 public static void flush() { 706 getLog().flushBuffer(); 707 } 708 709 /** 710 * writes a new-line and optionally flushes the buffer 711 * 712 * @param flush if <code>true</code> the buffer is flushed 713 */ 714 private static void writelnWithFlush(boolean flush) { 715 add(NEW_LINE_CHAR); 716 if (flush) { 717 flush(); 718 } 719 } 720 721 /** 722 * writes a <code>long</code> in hexadecimal 723 * 724 * @param w the Word to be logged 725 * @param bytes the number of bytes from the long to be logged. If 726 * less than 8 then the least significant bytes are logged and some 727 * of the most significant bytes are ignored. 728 */ 729 private static void writeHex(Word w, int bytes) { 730 int hexDigits = bytes * (1 << LOG_HEX_DIGITS_IN_BYTE); 731 int nextDigit; 732 733 write(HEX_PREFIX); 734 735 for (int digitNumber = hexDigits - 1; digitNumber >= 0; digitNumber--) { 736 nextDigit = w.rshl(digitNumber << LOG_BITS_IN_HEX_DIGIT).toInt() & 0xf; 737 char nextChar = hexDigitCharacter[nextDigit]; 738 add(nextChar); 739 } 740 } 741 742 /** 743 * adds a character to the buffer 744 * 745 * @param c the character to add 746 */ 747 private static void add(char c) { 748 getLog().addToBuffer(c); 749 } 750 751 /** 752 * adds a string to the buffer 753 * 754 * @param s the string to add 755 */ 756 private static void add(String s) { 757 getLog().addToBuffer(s); 758 } 759 760 private static Log getLog() { 761 return VM.activePlan.log(); 762 } 763 764 /** 765 * adds a character to the buffer 766 * 767 * @param c the character to add 768 */ 769 private void addToBuffer(char c) { 770 if (bufferIndex < MESSAGE_BUFFER_SIZE) { 771 buffer[bufferIndex++] = c; 772 } else { 773 overflow = true; 774 overflowLastChar = c; 775 } 776 } 777 778 /** 779 * adds a string to the buffer 780 * 781 * @param s the string to add 782 */ 783 private void addToBuffer(String s) { 784 if (bufferIndex < MESSAGE_BUFFER_SIZE) { 785 bufferIndex += VM.strings.copyStringToChars(s, buffer, bufferIndex, MESSAGE_BUFFER_SIZE + 1); 786 if (bufferIndex == MESSAGE_BUFFER_SIZE + 1) { 787 overflow = true; 788 // We don't bother setting OVERFLOW_LAST_CHAR, since we don't have an 789 // MMTk method that lets us peek into a string. Anyway, it's just a 790 // convenience to get the newline right. 791 buffer[MESSAGE_BUFFER_SIZE] = OVERFLOW_MESSAGE_FIRST_CHAR; 792 bufferIndex--; 793 } 794 } else { 795 overflow = true; 796 } 797 } 798 799 /** 800 * flushes the buffer 801 */ 802 private void flushBuffer() { 803 int newlineAdjust = overflowLastChar == NEW_LINE_CHAR ? 0 : -1; 804 int totalMessageSize = overflow ? (MESSAGE_BUFFER_SIZE + OVERFLOW_SIZE + newlineAdjust) : bufferIndex; 805 if (threadIdFlag) { 806 VM.strings.writeThreadId(buffer, totalMessageSize); 807 } else { 808 VM.strings.write(buffer, totalMessageSize); 809 } 810 threadIdFlag = false; 811 overflow = false; 812 overflowLastChar = '\0'; 813 bufferIndex = 0; 814 } 815 816 /** 817 * sets the flag so that a thread identifier will be included before 818 * the logged message 819 */ 820 private void setThreadIdFlag() { 821 threadIdFlag = true; 822 } 823 824 /** 825 * gets the buffer for building string representations of integers. 826 * There is one of these buffers for each Log instance. 827 */ 828 private static char[] getIntBuffer() { 829 return getLog().getTempBuffer(); 830 } 831 832 /** 833 * gets the buffer for building string representations of integers. 834 */ 835 private char[] getTempBuffer() { 836 return tempBuffer; 837 } 838 }