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