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.deque;
014    
015    import org.mmtk.utility.Log;
016    import org.mmtk.utility.TracingConstants;
017    import org.mmtk.vm.VM;
018    import org.mmtk.utility.Constants;
019    
020    import org.vmmagic.pragma.*;
021    import org.vmmagic.unboxed.*;
022    
023    /**
024     * This supports <i>unsynchronized</i> enqueuing and dequeuing of tracing data
025     * and bulk processing of the buffer.
026     */
027    @Uninterruptible public class TraceBuffer extends LocalQueue
028      implements Constants, TracingConstants {
029    
030      /***********************************************************************
031       *
032       * Class based constants
033       */
034      private static final Word TRACE_NEW_RECORD = Word.fromIntSignExtend(3);
035      private static final Word TRACE_ALLOC_SIZE = Word.fromIntSignExtend(5);
036    //  private static final Word TRACE_ALLOC_NAME = Word.fromIntSignExtend(6);
037      private static final Word TRACE_ALLOC_FP = Word.fromIntSignExtend(7);
038      private static final Word TRACE_ALLOC_THREAD = Word.fromIntSignExtend(9);
039      private static final Word TRACE_TIB_VALUE = Word.fromIntSignExtend(10);
040      private static final Word TRACE_DEATH_TIME = Word.fromIntSignExtend(11);
041      private static final Word TRACE_FIELD_TARGET = Word.fromIntSignExtend(12);
042      private static final Word TRACE_ARRAY_TARGET = Word.fromIntSignExtend(13);
043      private static final Word TRACE_FIELD_SLOT = Word.fromIntSignExtend(14);
044      private static final Word TRACE_ARRAY_ELEMENT = Word.fromIntSignExtend(15);
045      private static final Word TRACE_STATIC_TARGET = Word.fromIntSignExtend(17);
046      private static final Word TRACE_BOOT_ALLOC_SIZE = Word.fromIntSignExtend(18);
047    
048      /*
049       * Debugging and trace reducing constants
050       */
051      public static final boolean OMIT_ALLOCS=false;
052      public static final boolean OMIT_UPDATES=false;
053      public static final boolean OMIT_BOOTALLOCS=false;
054      public static final boolean OMIT_UNREACHABLES=false;
055      public static final boolean OMIT_OTHERS=false;
056      public static final boolean OMIT_OUTPUT=OMIT_ALLOCS && OMIT_UPDATES &&
057                                              OMIT_OTHERS;
058    
059    
060      /***********************************************************************
061       *
062       * Public methods
063       */
064    
065      /**
066       * Constructor
067       *
068       * @param pool The shared queue to which this queue will append its
069       * buffers (when full or flushed) and from which it will aquire new
070       * buffers when it has exhausted its own.
071       */
072      public TraceBuffer(SharedDeque pool) {
073        super(pool);
074      }
075    
076      /**
077       * Push word onto the tracing queue.
078       *
079       * @param i The data to be pushed onto the tracing queue
080       */
081      @Inline
082      public final void push(Word i) {
083        checkTailInsert(1);
084        uncheckedTailInsert(i.toAddress());
085      }
086    
087      /**
088       * Process the data in the tracing buffer, output information as needed.
089       */
090      public final void process() {
091        Word traceState = TRACE_NEW_RECORD;
092        int entriesNotFlushed = 0;
093        boolean loggedRecord = false;
094        /* First we must flush any remaining data */
095        if (!OMIT_OUTPUT) Log.writeln();
096    
097        /* Process through the entire buffer. */
098        while (checkDequeue(1)) {
099          /* For speed and efficiency, we will actually process the data buffer by
100             buffer and not by dequeue-ing each entry. */
101          while (!bufferOffset(head).isZero()) {
102            head = head.minus(BYTES_IN_ADDRESS);
103            Word val = head.loadWord();
104            if (traceState.EQ(TRACE_NEW_RECORD)) {
105              loggedRecord = false;
106              if (val.EQ(TRACE_GCSTART)) {
107                if (!OMIT_OTHERS) {
108                  Log.write('G');
109                  Log.write('C');
110                  Log.writeln('B', true);
111                }
112              } else if (val.EQ(TRACE_GCEND)) {
113                if (!OMIT_OTHERS) {
114                  Log.write('G');
115                  Log.write('C');
116                  Log.writeln('E', true);
117                }
118              } else {
119                traceState = val;
120              }
121            } else {
122              if (traceState.EQ(TRACE_EXACT_ALLOC) ||
123                  traceState.EQ(TRACE_ALLOC)) {
124                if (!OMIT_ALLOCS) {
125                  Log.write((traceState.EQ(TRACE_EXACT_ALLOC)) ? 'A' : 'a');
126                  Log.write(' ');
127                  Log.write(val);
128                  loggedRecord = true;
129                }
130                traceState = TRACE_ALLOC_SIZE;
131              } else if (traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC) ||
132                         traceState.EQ(TRACE_IMMORTAL_ALLOC)) {
133                if (!OMIT_ALLOCS) {
134                  Log.write((traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC)) ? 'I' : 'i');
135                  Log.write(' ');
136                  Log.write(val);
137                  loggedRecord = true;
138                }
139                traceState = TRACE_ALLOC_SIZE;
140              } else if (traceState.EQ(TRACE_BOOT_ALLOC)) {
141                if (!OMIT_BOOTALLOCS) {
142                  Log.write('B');
143                  Log.write(' ');
144                  Log.write(val);
145                  loggedRecord = true;
146                }
147                traceState = TRACE_BOOT_ALLOC_SIZE;
148              } else if (traceState.EQ(TRACE_DEATH)) {
149                if (!OMIT_UNREACHABLES) {
150                  Log.write('D');
151                  Log.write(' ');
152                  Log.write(val);
153                  loggedRecord = true;
154                }
155                traceState = TRACE_DEATH_TIME;
156              } else if (traceState.EQ(TRACE_BOOT_ALLOC_SIZE)) {
157                if (!OMIT_BOOTALLOCS)
158                  Log.write(val);
159                traceState = TRACE_NEW_RECORD;
160              } else if (traceState.EQ(TRACE_ALLOC_SIZE)) {
161                if (!OMIT_ALLOCS)
162                  Log.write(val);
163                traceState = TRACE_ALLOC_FP;
164              } else if (traceState.EQ(TRACE_ALLOC_FP)) {
165                if (!OMIT_ALLOCS)
166                  Log.write(val);
167                traceState = TRACE_ALLOC_THREAD;
168              } else if (traceState.EQ(TRACE_ALLOC_THREAD)) {
169                if (!OMIT_ALLOCS)
170                  Log.write(val);
171                traceState = TRACE_NEW_RECORD;
172              } else if (traceState.EQ(TRACE_TIB_SET)) {
173                if (!OMIT_UPDATES) {
174                  Log.write('T');
175                  Log.write(' ');
176                  Log.write(val);
177                  loggedRecord = true;
178                }
179                traceState = TRACE_TIB_VALUE;
180              } else if (traceState.EQ(TRACE_STATIC_SET)) {
181                if (!OMIT_UPDATES) {
182                  Log.write('S');
183                  Log.write(' ');
184                  Log.write(val);
185                  loggedRecord = true;
186                }
187                traceState = TRACE_STATIC_TARGET;
188              } else if (traceState.EQ(TRACE_TIB_VALUE) ||
189                         traceState.EQ(TRACE_STATIC_TARGET)) {
190                if (!OMIT_UPDATES)
191                  Log.write(val);
192                traceState = TRACE_NEW_RECORD;
193              } else if (traceState.EQ(TRACE_DEATH_TIME)) {
194                if (!OMIT_UNREACHABLES)
195                  Log.write(val);
196                traceState = TRACE_NEW_RECORD;
197              } else if (traceState.EQ(TRACE_FIELD_SET) ||
198                         traceState.EQ(TRACE_ARRAY_SET)) {
199                if (!OMIT_UPDATES) {
200                  Log.write('U');
201                  Log.write(' ');
202                  Log.write(val);
203                  loggedRecord = true;
204                }
205                traceState = TRACE_FIELD_SLOT;
206              } else if (traceState.EQ(TRACE_FIELD_TARGET) ||
207                         traceState.EQ(TRACE_ARRAY_TARGET)) {
208                if (!OMIT_UPDATES)
209                  Log.write(val);
210                traceState = TRACE_NEW_RECORD;
211              } else if (traceState.EQ(TRACE_FIELD_SLOT) ||
212                         traceState.EQ(TRACE_ARRAY_ELEMENT)) {
213                if (!OMIT_UPDATES)
214                  Log.write(val);
215                traceState = TRACE_FIELD_TARGET;
216              } else {
217                VM.assertions.fail("Cannot understand directive!\n");
218              }
219              if (traceState.EQ(TRACE_NEW_RECORD) && loggedRecord) {
220                entriesNotFlushed++;
221                Log.writeln();
222              } else if (loggedRecord) {
223                  Log.write(' ');
224              }
225            }
226            if (entriesNotFlushed == 10) {
227              if (!OMIT_OUTPUT)
228                Log.flush();
229              entriesNotFlushed = 0;
230            }
231          }
232        }
233        resetLocal();
234      }
235    }