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    }