| /* |
| * This file is part of the Jikes RVM project (http://jikesrvm.org). |
| * |
| * This file is licensed to You under the Eclipse Public License (EPL); |
| * You may not use this file except in compliance with the License. You |
| * may obtain a copy of the License at |
| * |
| * http://www.opensource.org/licenses/eclipse-1.0.php |
| * |
| * See the COPYRIGHT.txt file distributed with this work for information |
| * regarding copyright ownership. |
| */ |
| package org.mmtk.utility.deque; |
| |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.TracingConstants; |
| import org.mmtk.vm.VM; |
| import org.mmtk.utility.Constants; |
| |
| import org.vmmagic.pragma.*; |
| import org.vmmagic.unboxed.*; |
| |
| /** |
| * This supports <i>unsynchronized</i> enqueuing and dequeuing of tracing data |
| * and bulk processing of the buffer. |
| */ |
| @Uninterruptible public class TraceBuffer extends LocalQueue |
| implements Constants, TracingConstants { |
| |
| /*********************************************************************** |
| * |
| * Class based constants |
| */ |
| private static final Word TRACE_NEW_RECORD = Word.fromIntSignExtend(3); |
| private static final Word TRACE_ALLOC_SIZE = Word.fromIntSignExtend(5); |
| // private static final Word TRACE_ALLOC_NAME = Word.fromIntSignExtend(6); |
| private static final Word TRACE_ALLOC_FP = Word.fromIntSignExtend(7); |
| private static final Word TRACE_ALLOC_THREAD = Word.fromIntSignExtend(9); |
| private static final Word TRACE_TIB_VALUE = Word.fromIntSignExtend(10); |
| private static final Word TRACE_DEATH_TIME = Word.fromIntSignExtend(11); |
| private static final Word TRACE_FIELD_TARGET = Word.fromIntSignExtend(12); |
| private static final Word TRACE_ARRAY_TARGET = Word.fromIntSignExtend(13); |
| private static final Word TRACE_FIELD_SLOT = Word.fromIntSignExtend(14); |
| private static final Word TRACE_ARRAY_ELEMENT = Word.fromIntSignExtend(15); |
| private static final Word TRACE_STATIC_TARGET = Word.fromIntSignExtend(17); |
| private static final Word TRACE_BOOT_ALLOC_SIZE = Word.fromIntSignExtend(18); |
| |
| /* |
| * Debugging and trace reducing constants |
| */ |
| public static final boolean OMIT_ALLOCS=false; |
| public static final boolean OMIT_UPDATES=false; |
| public static final boolean OMIT_BOOTALLOCS=false; |
| public static final boolean OMIT_UNREACHABLES=false; |
| public static final boolean OMIT_OTHERS=false; |
| public static final boolean OMIT_OUTPUT=OMIT_ALLOCS && OMIT_UPDATES && |
| OMIT_OTHERS; |
| |
| |
| /*********************************************************************** |
| * |
| * Public methods |
| */ |
| |
| /** |
| * Constructor |
| * |
| * @param pool The shared queue to which this queue will append its |
| * buffers (when full or flushed) and from which it will aquire new |
| * buffers when it has exhausted its own. |
| */ |
| public TraceBuffer(SharedDeque pool) { |
| super(pool); |
| } |
| |
| /** |
| * Push word onto the tracing queue. |
| * |
| * @param i The data to be pushed onto the tracing queue |
| */ |
| @Inline |
| public final void push(Word i) { |
| checkTailInsert(1); |
| uncheckedTailInsert(i.toAddress()); |
| } |
| |
| /** |
| * Process the data in the tracing buffer, output information as needed. |
| */ |
| public final void process() { |
| Word traceState = TRACE_NEW_RECORD; |
| int entriesNotFlushed = 0; |
| boolean loggedRecord = false; |
| /* First we must flush any remaining data */ |
| if (!OMIT_OUTPUT) Log.writeln(); |
| |
| /* Process through the entire buffer. */ |
| while (checkDequeue(1)) { |
| /* For speed and efficiency, we will actually process the data buffer by |
| buffer and not by dequeue-ing each entry. */ |
| while (!bufferOffset(head).isZero()) { |
| head = head.minus(BYTES_IN_ADDRESS); |
| Word val = head.loadWord(); |
| if (traceState.EQ(TRACE_NEW_RECORD)) { |
| loggedRecord = false; |
| if (val.EQ(TRACE_GCSTART)) { |
| if (!OMIT_OTHERS) { |
| Log.write('G'); |
| Log.write('C'); |
| Log.writeln('B', true); |
| } |
| } else if (val.EQ(TRACE_GCEND)) { |
| if (!OMIT_OTHERS) { |
| Log.write('G'); |
| Log.write('C'); |
| Log.writeln('E', true); |
| } |
| } else { |
| traceState = val; |
| } |
| } else { |
| if (traceState.EQ(TRACE_EXACT_ALLOC) || |
| traceState.EQ(TRACE_ALLOC)) { |
| if (!OMIT_ALLOCS) { |
| Log.write((traceState.EQ(TRACE_EXACT_ALLOC)) ? 'A' : 'a'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_ALLOC_SIZE; |
| } else if (traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC) || |
| traceState.EQ(TRACE_IMMORTAL_ALLOC)) { |
| if (!OMIT_ALLOCS) { |
| Log.write((traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC)) ? 'I' : 'i'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_ALLOC_SIZE; |
| } else if (traceState.EQ(TRACE_BOOT_ALLOC)) { |
| if (!OMIT_BOOTALLOCS) { |
| Log.write('B'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_BOOT_ALLOC_SIZE; |
| } else if (traceState.EQ(TRACE_DEATH)) { |
| if (!OMIT_UNREACHABLES) { |
| Log.write('D'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_DEATH_TIME; |
| } else if (traceState.EQ(TRACE_BOOT_ALLOC_SIZE)) { |
| if (!OMIT_BOOTALLOCS) |
| Log.write(val); |
| traceState = TRACE_NEW_RECORD; |
| } else if (traceState.EQ(TRACE_ALLOC_SIZE)) { |
| if (!OMIT_ALLOCS) |
| Log.write(val); |
| traceState = TRACE_ALLOC_FP; |
| } else if (traceState.EQ(TRACE_ALLOC_FP)) { |
| if (!OMIT_ALLOCS) |
| Log.write(val); |
| traceState = TRACE_ALLOC_THREAD; |
| } else if (traceState.EQ(TRACE_ALLOC_THREAD)) { |
| if (!OMIT_ALLOCS) |
| Log.write(val); |
| traceState = TRACE_NEW_RECORD; |
| } else if (traceState.EQ(TRACE_TIB_SET)) { |
| if (!OMIT_UPDATES) { |
| Log.write('T'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_TIB_VALUE; |
| } else if (traceState.EQ(TRACE_STATIC_SET)) { |
| if (!OMIT_UPDATES) { |
| Log.write('S'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_STATIC_TARGET; |
| } else if (traceState.EQ(TRACE_TIB_VALUE) || |
| traceState.EQ(TRACE_STATIC_TARGET)) { |
| if (!OMIT_UPDATES) |
| Log.write(val); |
| traceState = TRACE_NEW_RECORD; |
| } else if (traceState.EQ(TRACE_DEATH_TIME)) { |
| if (!OMIT_UNREACHABLES) |
| Log.write(val); |
| traceState = TRACE_NEW_RECORD; |
| } else if (traceState.EQ(TRACE_FIELD_SET) || |
| traceState.EQ(TRACE_ARRAY_SET)) { |
| if (!OMIT_UPDATES) { |
| Log.write('U'); |
| Log.write(' '); |
| Log.write(val); |
| loggedRecord = true; |
| } |
| traceState = TRACE_FIELD_SLOT; |
| } else if (traceState.EQ(TRACE_FIELD_TARGET) || |
| traceState.EQ(TRACE_ARRAY_TARGET)) { |
| if (!OMIT_UPDATES) |
| Log.write(val); |
| traceState = TRACE_NEW_RECORD; |
| } else if (traceState.EQ(TRACE_FIELD_SLOT) || |
| traceState.EQ(TRACE_ARRAY_ELEMENT)) { |
| if (!OMIT_UPDATES) |
| Log.write(val); |
| traceState = TRACE_FIELD_TARGET; |
| } else { |
| VM.assertions.fail("Cannot understand directive!\n"); |
| } |
| if (traceState.EQ(TRACE_NEW_RECORD) && loggedRecord) { |
| entriesNotFlushed++; |
| Log.writeln(); |
| } else if (loggedRecord) { |
| Log.write(' '); |
| } |
| } |
| if (entriesNotFlushed == 10) { |
| if (!OMIT_OUTPUT) |
| Log.flush(); |
| entriesNotFlushed = 0; |
| } |
| } |
| } |
| resetLocal(); |
| } |
| } |