/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.ins.memory;
import static com.sun.max.tele.MaxMarkBitmap.MarkColor.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.sun.max.ins.*;
import com.sun.max.ins.gui.*;
import com.sun.max.tele.*;
import com.sun.max.tele.MaxMarkBitmap.MarkColor;
import com.sun.max.tele.data.*;
import com.sun.max.unsafe.*;
/**
* A table cell renderer for tables with rows representing memory words: displays in the cell
* the contents of the {@linkplain MaxMarkBitmap Mark Bitmap} word containing the bit that is used to mark each word.
* <p>
* If a {@linkplain MaxMarkBitmap Mark Bitmap} is not used, or if one is used but has not yet been initialized, or if
* the word is not covered by the bitmap, then the cell is rendered blank with an explanatory tooltip.</p>
* <p>
* The relevant bitmap word is displayed as a sequence of bytes in hex format, with the exception of the byte containing the mark bit
* for the word. That byte is displayed in binary, surrounded by '|' characters. The specific bit used to mark the word is
* bracketed with '<' and '>'.</p>
*
* @see MaxMarkBitmap
*/
public final class MemoryMarkBitsTableCellRenderer extends InspectorTableCellRenderer {
private final InspectorTable inspectorTable;
private final InspectorMemoryTableModel tableModel;
// This kind of label has no interaction state, so we only need one, which we set up on demand.
private final InspectorLabel label;
private final InspectorLabel[] labels = new InspectorLabel[1];
/**
* A renderer that displays the VM's memory region name, if any, into which the word value in the memory represented
* by the table row points.
*
* @param inspection
* @param inspectorTable the table holding the cell to be rendered
* @param tableModel a table model in which rows represent memory regions
*/
public MemoryMarkBitsTableCellRenderer(Inspection inspection, final InspectorTable inspectorTable, InspectorMemoryTableModel tableModel) {
super(inspection);
this.inspectorTable = inspectorTable;
this.tableModel = tableModel;
this.label = new TextLabel(inspection, "");
this.label.setOpaque(true);
this.labels[0] = this.label;
label.addMouseListener(new InspectorMouseClickAdapter(inspection()) {
@Override
public void procedure(final MouseEvent mouseEvent) {
switch (inspection().gui().getButton(mouseEvent)) {
case MouseEvent.BUTTON1: {
break;
}
case MouseEvent.BUTTON2: {
break;
}
case MouseEvent.BUTTON3: {
final Point p = mouseEvent.getPoint();
final int col = inspectorTable.columnAtPoint(p);
final int row = inspectorTable.rowAtPoint(p);
if ((col != -1) && (row != -1) && inspection().gui().getButton(mouseEvent) == MouseEvent.BUTTON3) {
final InspectorAction showHeapMarkAction = getShowHeapMarkAction(row);
if (showHeapMarkAction != null) {
final InspectorPopupMenu menu = new InspectorPopupMenu();
menu.add(showHeapMarkAction);
menu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
}
}
}
}
}
});
redisplay();
}
@Override
public void redisplay() {
label.setFont(preference().style().hexDataFont());
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, int column) {
final InspectorStyle style = inspection().preference().style();
Color backgroundColor = inspectorTable.cellBackgroundColor();
Color foregroundColor = inspectorTable.cellForegroundColor(row, column);
InspectorLabel renderer = label;
final MaxMarkBitmap markBitmap = vm().heap().markBitmap();
final Address memoryAddress = tableModel.getAddress(row);
if (!vm().heap().hasMarkBitmap()) {
renderer.setText("");
renderer.setToolTipPrefix(tableModel.getRowDescription(row));
renderer.setWrappedToolTipHtmlText("<br>No bitmap used in this VM");
} else if (markBitmap == null) {
renderer.setText("");
renderer.setToolTipPrefix(tableModel.getRowDescription(row));
renderer.setWrappedToolTipHtmlText("<br>Bitmap not yet allocated");
} else if (!markBitmap.isCovered(memoryAddress)) {
renderer.setText("");
renderer.setToolTipPrefix(tableModel.getRowDescription(row));
renderer.setWrappedToolTipHtmlText("<br>Not covered by bitmap");
} else {
final int bitIndex = markBitmap.getBitIndexOf(memoryAddress);
final int bitIndexInWord = markBitmap.getBitIndexInWord(bitIndex);
final int byteIndexInWord = 7 - (bitIndexInWord / 8);
final int bitIndexInByte = 7 - (bitIndexInWord % 8);
byte[] bytes = new byte[8];
try {
final long bitmapWord = markBitmap.readBitmapWord(bitIndex);
bytes[0] = (byte) (bitmapWord >>> 56);
bytes[1] = (byte) (bitmapWord >>> 48);
bytes[2] = (byte) (bitmapWord >>> 40);
bytes[3] = (byte) (bitmapWord >>> 32);
bytes[4] = (byte) (bitmapWord >>> 24);
bytes[5] = (byte) (bitmapWord >>> 16);
bytes[6] = (byte) (bitmapWord >>> 8);
bytes[7] = (byte) (bitmapWord >>> 0);
} catch (DataIOError dataIOError) {
return inspection().gui().getUnavailableDataTableCellRenderer();
}
final StringBuilder result = new StringBuilder(100);
String prefix = "";
for (int index = 0; index < 8; index++) {
byte b = bytes[index];
result.append(prefix);
final StringBuffer bitString = new StringBuffer();
if (index == byteIndexInWord) {
for (short mask = 0x80; mask != 0; mask >>>= 1) {
bitString.append((b & mask) == 0 ? "0" : "1");
}
bitString.insert(bitIndexInByte + 1, '>').insert(bitIndexInByte, '<');
result.append("|").append(bitString).append("|");
} else {
result.append(String.format("%02X", b));
}
prefix = " ";
}
renderer.setWrappedHtmlText(InspectorLabel.htmlify(result.toString()));
renderer.setToolTipPrefix(tableModel.getRowDescription(row));
// renderer.setToolTipText("Mark Bitmap word@" + markBitmap.bitmapWordAddress(bitIndex).to0xHexString());
// Is this the first bit of a mark?
MarkColor markColor = markBitmap.getMarkColor(bitIndex);
if (markColor == null && bitIndex > 0) {
// Is this the second bit of a mark? If so, render the cell with the same style as as the first bit
markColor = markBitmap.getMarkColor(bitIndex - 1);
}
if (markColor != null) {
switch(markColor) {
case MARK_WHITE:
backgroundColor = style.markedWhiteBackgroundColor();
foregroundColor = Color.BLACK;
break;
case MARK_GRAY:
backgroundColor = style.markedGrayBackgroundColor();
foregroundColor = Color.WHITE;
break;
case MARK_BLACK:
backgroundColor = style.markedBlackBackgroundColor();
foregroundColor = Color.WHITE;
break;
case MARK_INVALID:
backgroundColor = style.markInvalidBackgroundColor();
foregroundColor = Color.WHITE;
break;
case MARK_UNAVAILABLE:
break;
}
} else if (markBitmap.isBitSet(bitIndex)) {
// Not a valid location for a mark bit; shouldn't be set
backgroundColor = style.markInvalidBackgroundColor();
foregroundColor = Color.WHITE;
markColor = MARK_INVALID;
}
final StringBuilder sb = new StringBuilder();
sb.append("<br>Heap mark bit(");
sb.append(bitIndex);
sb.append(")=");
sb.append(markBitmap.isBitSet(bitIndex) ? "1" : "0");
sb.append(", color=");
sb.append(markBitmap.getMarkColor(bitIndex));
renderer.setWrappedToolTipHtmlText(sb.toString());
}
renderer.setBackground(backgroundColor);
renderer.setForeground(foregroundColor);
if (inspectorTable.isBoundaryRow(row)) {
renderer.setBorder(preference().style().defaultPaneTopBorder());
} else {
renderer.setBorder(null);
}
return renderer;
}
@Override
protected InspectorLabel[] getLabels() {
return labels;
}
private InspectorAction getShowHeapMarkAction(final int bitIndex) {
final MaxMarkBitmap markBitMap = vm().heap().markBitmap();
if (bitIndex >= 0 && markBitMap != null) {
final Address address = markBitMap.heapAddress(bitIndex);
if (markBitMap.isCovered(address)) {
final MarkColor markColor = markBitMap.getMarkColor(bitIndex);
final StringBuilder sb = new StringBuilder();
sb.append("Show heap mark bit(");
sb.append(bitIndex);
sb.append(")=");
sb.append(markBitMap.isBitSet(bitIndex) ? "1" : "0");
sb.append(", color=");
sb.append(markColor);
return new InspectorAction(inspection(), sb.toString()) {
@Override
protected void procedure() {
focus().setMarkBitIndex(bitIndex);
focus().setAddress(address);
}
};
}
}
return null;
}
}