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