/*
* Copyright (c) 2007, 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.debug;
import static com.sun.max.tele.MaxProcessState.*;
import javax.swing.*;
import com.sun.max.ins.*;
import com.sun.max.ins.gui.*;
import com.sun.max.ins.gui.TableColumnVisibilityPreferences.TableColumnViewPreferenceListener;
import com.sun.max.ins.util.*;
import com.sun.max.ins.view.*;
import com.sun.max.ins.view.InspectionViews.ViewKind;
import com.sun.max.program.*;
import com.sun.max.tele.*;
import com.sun.max.unsafe.*;
/**
* A singleton view that displays the contents of the stack frame in
* the VM that is the current user focus.
*/
public final class StackFrameView extends AbstractView<StackFrameView> implements TableColumnViewPreferenceListener {
private static final int TRACE_VALUE = 1;
private static final ViewKind VIEW_KIND = ViewKind.STACK_FRAME;
private static final String SHORT_NAME = "Stack Frame";
private static final String LONG_NAME = "Stack Frame View";
private static final String GEOMETRY_SETTINGS_KEY = "stackFrameViewGeometry";
public static final class StackFrameViewManager extends AbstractSingletonViewManager<StackFrameView> {
protected StackFrameViewManager(Inspection inspection) {
super(inspection, VIEW_KIND, SHORT_NAME, LONG_NAME);
}
@Override
protected StackFrameView createView(Inspection inspection) {
return new StackFrameView(inspection);
}
}
// Will be non-null before any instances created.
private static StackFrameViewManager viewManager = null;
public static StackFrameViewManager makeViewManager(Inspection inspection) {
if (viewManager == null) {
viewManager = new StackFrameViewManager(inspection);
}
return viewManager;
}
// This is a singleton viewer, so only use a single level of view preferences.
private static CompiledStackFrameViewPreferences viewPreferences;
private final class CopyStackFrameToClipboardAction extends InspectorAction {
private CopyStackFrameToClipboardAction() {
super(inspection(), "Copy stack frame to clipboard");
}
@Override
public void procedure() {
// TODO (mlvdv) This is pretty awkward, but has the virtue that it reproduces exactly what's displayed. Could be improved.
final String contents = compiledStackFramePanel.getContentString();
gui().postToClipboard(contents);
}
@Override
public void refresh(boolean force) {
setEnabled(compiledStackFramePanel != null);
}
}
private MaxStackFrame stackFrame;
private final InspectorPanel nullFramePanel;
private final InspectorPanel truncatedFramePanel;
private CompiledStackFramePanel compiledStackFramePanel = null;
private final InspectorAction copyStackFrameToClipboardAction = new CopyStackFrameToClipboardAction();
public StackFrameView(Inspection inspection) {
super(inspection, VIEW_KIND, GEOMETRY_SETTINGS_KEY);
Trace.begin(1, tracePrefix() + " initializing");
viewPreferences = CompiledStackFrameViewPreferences.globalPreferences(inspection);
viewPreferences.addListener(this);
nullFramePanel = new InspectorPanel(inspection);
truncatedFramePanel = new InspectorPanel(inspection);
final JTextArea truncatedFrameTextArea = new JTextArea("<truncated frame>");
truncatedFrameTextArea.setEditable(false);
truncatedFramePanel.add(truncatedFrameTextArea);
createFrame(true);
forceRefresh();
Trace.end(1, tracePrefix() + " initializing");
}
@Override
public String getTextForTitle() {
final StringBuilder sb = new StringBuilder(viewManager.shortName() + ": ");
if (!inspection().hasProcess()) {
sb.append(inspection().nameDisplay().noProcessShortText());
} else if (stackFrame == null) {
sb.append(inspection().nameDisplay().unavailableDataShortText());
} else {
if (stackFrame instanceof MaxStackFrame.Compiled) {
final MaxCompilation compilation = stackFrame.compilation();
sb.append(inspection().nameDisplay().veryShortName(compilation));
} else if (stackFrame instanceof MaxStackFrame.Native) {
sb.append("<native>");
}
sb.append(" in ").append(inspection().nameDisplay().longNameWithState(stackFrame.stack().thread()));
}
return sb.toString();
}
@Override
protected void createViewContent() {
stackFrame = inspection().focus().stackFrame();
if (stackFrame instanceof MaxStackFrame.Compiled) {
final MaxStackFrame.Compiled compiledStackFrame = (MaxStackFrame.Compiled) stackFrame;
compiledStackFramePanel = new DefaultCompiledStackFramePanel(inspection(), this, compiledStackFrame, viewPreferences);
setContentPane(compiledStackFramePanel);
} else if (stackFrame instanceof MaxStackFrame.Native) {
final InspectorPanel nativeFramePanel = new InspectorPanel(inspection());
final JTextArea nativeFrameTextArea = new JTextArea(stackFrame.entityName());
nativeFrameTextArea.setEditable(false);
nativeFramePanel.add(nativeFrameTextArea);
setContentPane(nativeFramePanel);
compiledStackFramePanel = null;
} else if (stackFrame instanceof MaxStackFrame.Truncated) {
final MaxStackFrame.Truncated truncated = (MaxStackFrame.Truncated) stackFrame;
if (truncated.omitted() >= 0) {
setContentPane(truncatedFramePanel);
} else {
final String message = "Stack walking error:\n" + truncated.error();
final InspectorPanel errorFramePanel = new InspectorPanel(inspection());
final JTextArea errorFrameTextArea = new JTextArea(message);
errorFrameTextArea.setEditable(false);
errorFramePanel.add(errorFrameTextArea);
setContentPane(errorFramePanel);
}
compiledStackFramePanel = null;
} else if (stackFrame == null) {
setContentPane(nullFramePanel);
compiledStackFramePanel = null;
} else {
InspectorError.unexpected(tracePrefix() + " unknown type of stack frame");
}
setTitle();
// Populate menu bar
makeMenu(MenuKind.DEFAULT_MENU).add(defaultMenuItems(MenuKind.DEFAULT_MENU));
final InspectorMenu editMenu = makeMenu(MenuKind.EDIT_MENU);
editMenu.add(copyStackFrameToClipboardAction);
final InspectorMenu memoryMenu = makeMenu(MenuKind.MEMORY_MENU);
memoryMenu.add(actions().viewSelectedStackFrameMemory("View memory for frame"));
memoryMenu.add(actions().viewSelectedThreadStackMemory("View memory for stack"));
memoryMenu.add(defaultMenuItems(MenuKind.MEMORY_MENU));
memoryMenu.add(views().activateSingletonViewAction(ViewKind.ALLOCATIONS));
makeMenu(MenuKind.VIEW_MENU).add(defaultMenuItems(MenuKind.VIEW_MENU));
}
@Override
protected void refreshState(boolean force) {
if (compiledStackFramePanel != null) {
compiledStackFramePanel.refresh(force);
}
// Title displays thread state, so must be updated
setTitle();
copyStackFrameToClipboardAction.refresh(force);
}
@Override
public void frameFocusChanged(MaxStackFrame oldStackFrame, MaxStackFrame newStackFrame) {
// The focus mechanism will suppress calls where the stack frame is identical to the previous frame.
if (newStackFrame != null && newStackFrame.isSameFrame(stackFrame)) {
// The frame object is different, but it represents the same frame; this typically happens
// when there has been a single step that only affects the top frame.
this.stackFrame = newStackFrame;
if (compiledStackFramePanel != null) {
compiledStackFramePanel.setStackFrame(stackFrame);
}
forceRefresh();
} else {
// Entirely new frame; start over
reconstructView();
}
}
@Override
public void addressFocusChanged(Address oldAddress, Address newAddress) {
forceRefresh();
}
@Override
public void watchpointSetChanged() {
if (vm().state().processState() == STOPPED) {
forceRefresh();
}
}
@Override
public InspectorAction getViewOptionsAction() {
return new InspectorAction(inspection(), "View Options") {
@Override
public void procedure() {
new TableColumnVisibilityPreferences.ColumnPreferencesDialog<CompiledStackFrameColumnKind>(inspection(), viewManager.shortName() + " View Options", viewPreferences);
}
};
}
public void tableColumnViewPreferencesChanged() {
reconstructView();
}
@Override
public void viewClosing() {
viewPreferences.removeListener(this);
super.viewClosing();
}
@Override
public void vmProcessTerminated() {
reconstructView();
}
}