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}