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 }