/* * 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.java; import static com.sun.max.platform.Platform.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import com.sun.cri.ci.*; import com.sun.max.ins.*; import com.sun.max.ins.gui.*; 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.tele.object.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.classfile.*; import com.sun.max.vm.stack.*; /** * A view that displays {@linkplain CiDebugInfo debug information} (if available) about the currently selected location in compiled code. */ public final class DebugInfoView extends AbstractView<DebugInfoView> { private static final int TRACE_VALUE = 1; private static final ViewKind VIEW_KIND = ViewKind.DEBUG_INFO; private static final String SHORT_NAME = "Debug Info"; private static final String LONG_NAME = "Debug Info View"; private static final String GEOMETRY_SETTINGS_KEY = "debugInfoViewGeometry"; public static final class DebugInfoViewManager extends AbstractSingletonViewManager<DebugInfoView> { protected DebugInfoViewManager(Inspection inspection) { super(inspection, VIEW_KIND, SHORT_NAME, LONG_NAME); } @Override protected DebugInfoView createView(Inspection inspection) { return new DebugInfoView(inspection); } } private static DebugInfoViewManager viewManager = null; public static DebugInfoViewManager makeViewManager(Inspection inspection) { if (viewManager == null) { viewManager = new DebugInfoViewManager(inspection); } return viewManager; } private MaxCodeLocation codeLocation = null; private MaxCompilation compilation = null; private CiDebugInfo debugInfo = null; private final MatteBorder frameBorder; private final Rectangle originalFrameGeometry; private final InspectorPanel nullPanel; private final InspectorPanel simplePanel; private final PlainLabel simplePanelLabel; protected DebugInfoView(Inspection inspection) { super(inspection, VIEW_KIND, GEOMETRY_SETTINGS_KEY); Trace.begin(1, tracePrefix() + " initializing"); frameBorder = BorderFactory.createMatteBorder(1, 0, 1, 0, inspection.preference().style().defaultBorderColor()); nullPanel = new InspectorPanel(inspection, new BorderLayout()); nullPanel.add(new PlainLabel(inspection, inspection.nameDisplay().unavailableDataShortText()), BorderLayout.PAGE_START); simplePanel = new InspectorPanel(inspection, new BorderLayout()); simplePanelLabel = new PlainLabel(inspection, ""); simplePanel.add(simplePanelLabel, BorderLayout.PAGE_START); simplePanel.setBorder(frameBorder); updateCodeLocation(focus().codeLocation()); createFrame(true); originalFrameGeometry = getGeometry(); Trace.end(1, tracePrefix() + " initializing"); } @Override public String getTextForTitle() { final StringBuilder sb = new StringBuilder(viewManager.shortName() + ": "); if (codeLocation == null) { sb.append("<none>"); } else if (codeLocation.hasTeleClassMethodActor()) { final TeleClassMethodActor teleClassMethodActor = codeLocation.teleClassMethodActor(); sb.append(teleClassMethodActor.classMethodActor().holder().simpleName()).append("."); sb.append(inspection().nameDisplay().veryShortName(teleClassMethodActor)); } else if (codeLocation.hasAddress()) { MaxNativeFunction nativeFunction = vm().machineCode().findNativeFunction(codeLocation.address()); if (nativeFunction == null) { sb.append("<native>@" + codeLocation.address().to0xHexString()); } else { sb.append(nativeFunction.entityName()); } } return sb.toString(); } @Override protected void createViewContent() { // TODO (mlvdv) convert this to some kind of tabular display with useful // functionality (inspection, navigation, etc.) over each cell. if (codeLocation == null) { setContentPane(nullPanel); } else if (debugInfo == null) { simplePanelLabel.setText(inspection().nameDisplay().longName(codeLocation)); setContentPane(simplePanel); } else { final JPanel panel = new InspectorPanel(inspection()); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // TODO: add register and frame reference map information to panel // debugInfo.registerRefMap ... // debugInfo.frameRefMap ... CiFrame frame = debugInfo.frame(); while (frame != null) { panel.add(createFramePanel(frame), 0); frame = frame.caller(); } panel.add(createRefMapsPanel(debugInfo), 0); simplePanelLabel.setText(inspection().nameDisplay().longName(codeLocation)); panel.add(simplePanel, 0); setContentPane(new InspectorScrollPane(inspection(), panel)); } setTitle(); // Populate menu bar makeMenu(MenuKind.DEFAULT_MENU).add(defaultMenuItems(MenuKind.DEFAULT_MENU)); makeMenu(MenuKind.VIEW_MENU).add(defaultMenuItems(MenuKind.VIEW_MENU)); } @Override protected void refreshState(boolean force) { updateCodeLocation(codeLocation); reconstructView(); } @Override public void codeLocationFocusSet(MaxCodeLocation codeLocation, boolean interactiveForNative) { updateCodeLocation(codeLocation); reconstructView(); } private void updateCodeLocation(MaxCodeLocation codeLocation) { this.codeLocation = codeLocation; if (codeLocation != null) { compilation = codeLocation.compilation(); debugInfo = codeLocation.debugInfo(); } } @Override public void vmProcessTerminated() { codeLocation = null; reconstructView(); } private String shortString(CiCodePos codePos) { return codePos.method.name() + "() bci=" + codePos.bci; } private JPanel createRefMapsPanel(CiDebugInfo info) { final JPanel panel = new InspectorPanel(inspection(), new BorderLayout()); final JPanel headerPanel = new InspectorPanel(inspection(), new FlowLayout(FlowLayout.LEADING)); headerPanel.add(new TextLabel(inspection(), "Reference Map")); panel.add(headerPanel, BorderLayout.PAGE_START); final JPanel slotsPanel = new JPanel(); slotsPanel.setLayout(new BoxLayout(slotsPanel, BoxLayout.PAGE_AXIS)); if (info.hasRegisterRefMap()) { CiBitMap bm = info.registerRefMap; CiArchitecture arch = target().arch; for (int reg = bm.nextSetBit(0); reg >= 0; reg = bm.nextSetBit(reg + 1)) { slotsPanel.add(new TextLabel(inspection(), arch.registers[reg].asValue(CiKind.Object).toString())); } } if (info.hasStackRefMap()) { CiBitMap bm = info.frameRefMap; for (int i = bm.nextSetBit(0); i >= 0; i = bm.nextSetBit(i + 1)) { VMFrameLayout layout = compilation.frameLayout(); CiRegister fp = layout.framePointerReg(); int refMapOffset = i * VMFrameLayout.STACK_SLOT_SIZE; int fpOffset = refMapOffset + layout.frameReferenceMapOffset(); String slot = new CiAddress(CiKind.Object, fp.asValue(), fpOffset).toString(); slotsPanel.add(new TextLabel(inspection(), slot)); } } if (slotsPanel.getComponentCount() != 0) { panel.add(slotsPanel, BorderLayout.LINE_START); } panel.setBorder(frameBorder); return panel; } private JPanel createFramePanel(CiFrame frame) { final JPanel panel = new InspectorPanel(inspection(), new BorderLayout()); final JPanel headerPanel = new InspectorPanel(inspection(), new FlowLayout(FlowLayout.LEADING)); final CiCodePos codePos = frame; final PlainLabel bytecodeLocationLabel = new PlainLabel(inspection(), shortString(codePos)); final String methodToolTipText = CiUtil.appendLocation(new StringBuilder(10), codePos.method, codePos.bci).toString(); bytecodeLocationLabel.setToolTipText(methodToolTipText); headerPanel.add(bytecodeLocationLabel); ClassMethodActor method = (ClassMethodActor) codePos.method; String sourceFileName = method.holder().sourceFileName; final int lineNumber = method.sourceLineNumber(codePos.bci); if (sourceFileName != null || lineNumber >= 0) { if (sourceFileName == null) { sourceFileName = inspection().nameDisplay().unavailableDataShortText(); } final String labelText = lineNumber >= 0 ? String.valueOf(lineNumber) : inspection().nameDisplay().unavailableDataShortText(); final PlainLabel sourceLocationLabel = new PlainLabel(inspection(), " line=" + labelText); sourceLocationLabel.setToolTipText(methodToolTipText); sourceLocationLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { inspection().viewSourceExternally(codePos); } }); headerPanel.add(sourceLocationLabel); } panel.add(headerPanel, BorderLayout.PAGE_START); if (frame.values.length > 0) { final JPanel slotsPanel = new JPanel(); slotsPanel.setLayout(new BoxLayout(slotsPanel, BoxLayout.PAGE_AXIS)); final CodeAttribute codeAttribute = method.codeAttribute(); for (int i = 0; i < frame.numLocals; i++) { String local = "local #" + i; final LocalVariableTable.Entry entry = codeAttribute.localVariableTable().findLocalVariable(i, codePos.bci); if (entry != null) { local += ": " + entry.name(codeAttribute.cp); } local += " = " + frame.getLocalValue(i); slotsPanel.add(new TextLabel(inspection(), local)); } for (int i = 0; i < frame.numStack; i++) { String stackSlot = "stack #" + i; stackSlot += " = " + frame.getStackValue(i); slotsPanel.add(new TextLabel(inspection(), stackSlot)); } for (int i = 0; i < frame.numLocks; i++) { String lock = "lock #" + i; lock += " = " + frame.getLockValue(i); slotsPanel.add(new TextLabel(inspection(), lock)); } panel.add(slotsPanel, BorderLayout.LINE_START); } panel.setBorder(frameBorder); return panel; } }