/*
* Copyright (c) 2008, 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;
import java.io.*;
import java.lang.reflect.*;
import java.math.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import com.sun.cri.ci.*;
import com.sun.max.*;
import com.sun.max.ins.debug.*;
import com.sun.max.ins.gui.*;
import com.sun.max.ins.memory.*;
import com.sun.max.ins.method.*;
import com.sun.max.ins.object.*;
import com.sun.max.ins.type.*;
import com.sun.max.ins.util.*;
import com.sun.max.ins.view.InspectionViews.ViewKind;
import com.sun.max.lang.*;
import com.sun.max.program.*;
import com.sun.max.tele.*;
import com.sun.max.tele.MaxWatchpointManager.MaxDuplicateWatchpointException;
import com.sun.max.tele.MaxWatchpointManager.MaxTooManyWatchpointsException;
import com.sun.max.tele.interpreter.*;
import com.sun.max.tele.method.*;
import com.sun.max.tele.object.*;
import com.sun.max.unsafe.*;
import com.sun.max.util.*;
import com.sun.max.vm.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.layout.Layout.HeaderField;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.thread.*;
import com.sun.max.vm.type.*;
import com.sun.max.vm.value.*;
/**
* Provider of {@link InspectorAction}s that are of general use.
* <p>
* <b>How to create an {@link InspectorAction} to perform "doSomething":</b>
*
* <ol>
*
* <li><b>Create an action class:</b>
* <ul>
* <li> {@code final class DoSomethingAction extends InspectorAction}</li>
* <li> The Action classes are in package scope so that they can be used by {@link InspectorKeyBindings}.</li>
* <li> Add a title: {@code private static final DEFAULT_NAME = "do something"}.</li>
* <li> If the
* action is interactive, for example if it produces a dialog, then the name should conclude with "...".
* Capitalize the first word of the title but not the others, except for distinguished names such as
* "View" and acronyms.</li>
* <li> For singletons, add a package scope constructor with one argument: {@code String title}</li>
* <li> For non-singletons, package scope constructor contains additional arguments that
* customize the action, for example that specify to what "something" is to be done.</li>
* <li> In the constructor: {@code super(inspection(), title == null ? DEFAULT_TITLE : title);}
* (being able to override isn't used in many cases, but it adds flexibility).</li>
* <li> If a singleton and if it contains state, for example enabled/disabled, that might change
* depending on external circumstances, then register for general notification:
* {@code _refreshableActions.append(this);} in the constructor.</li>
* <li> Alternately, if state updates depend on a more specific kind of event, register
* in the constructor explicitly for that event with a listener, for example
* {@code focus().addListener(new InspectionFocusAdapter() .... );}
* The body of the listener should call {@code refresh}.</li>
* <li>Override {@code protected void procedure()} with a method that does what
* needs to be done.</li>
* <li>If a singleton and if it contains state that might be changed depending on
* external circumstances, override {@code public void refresh(boolean force)}
* with a method that updates the state.</li>
* </ul></li>
*
*<li><b>Create a singleton variable if needed</b>:
*<ul>
* <li>If the command is a singleton, create an initialized variable, static if possible.</li>
* <li>{@code private static InspectorAction _doSomething = new DoSomethingAction(null);}</li>
* </ul></li>
*
* <li><b>Create an accessor:</b>
* <ul>
* <li>Singleton: {@code public InspectorAction doSomething()}.</li>
* <li> Singleton accessor returns the singleton variable.</li>
* <li>Non-singletons have additional arguments that customize the action, e.g. specifying to what "something"
* is to be done; they also take a {@code String title} argument that permits customization of the
* action's name, for example when it appears in menus.</li>
* <li> Non-singletons return {@code new DoSomethignAction(args, String title)}.</li>
* <li>Add a descriptive Javadoc comment: "@return an Action that does something".</li>
* </ul></li>
*
* </ol>
* <p>
*/
public class InspectionActions extends AbstractInspectionHolder implements Prober{
private static final int TRACE_VALUE = 2;
/**
* Name of the Action for searching in a view.
*/
public static final String SEARCH_ACTION = "Search";
/**
* Actions that are held and shared; they have state that will be refreshed.
* This is particularly important for actions that enable/disable, depending on the inspection state.
*/
private final List<InspectorAction> refreshableActions = new ArrayList<InspectorAction>();
InspectionActions(Inspection inspection) {
super(inspection);
Trace.line(TRACE_VALUE, "InspectionActions initialized.");
}
public final void refresh(boolean force) {
for (Prober prober : refreshableActions) {
prober.refresh(force);
}
}
public final void redisplay() {
// non-op
}
/**
* Action: displays the {@link AboutSessionDialog}.
*/
final class AboutSessionAction extends InspectorAction {
private static final String DEFAULT_TITLE = "About this session";
AboutSessionAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
new AboutSessionDialog(inspection());
}
}
/**
* @return an Action that will display the {@link AboutSessionDialog}.
*/
public final InspectorAction aboutSession(String title) {
return new AboutSessionAction(title);
}
/**
* @return an Action that doesn't do anything and is disabled.
*/
public final InspectorAction inertAction(String actionTitle) {
final InspectorAction action = new InspectorAction(inspection(), actionTitle) {
@Override
protected void procedure() {
}
};
action.setEnabled(false);
return action;
}
/**
* Action: displays the {@link AboutMaxineDialog}.
*/
final class AboutMaxineAction extends InspectorAction {
private static final String DEFAULT_TITLE = "About Maxine";
AboutMaxineAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
AboutMaxineDialog.create(inspection());
}
}
/**
* @return an Action that will display the {@link AboutMaxineDialog}.
*/
public final InspectorAction aboutMaxine(String title) {
return new AboutMaxineAction(title);
}
/**
* Action: displays the {@link PreferenceDialog}.
*/
final class PreferencesAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Preferences";
PreferencesAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
PreferenceDialog.create(inspection());
}
}
private InspectorAction preferences = new PreferencesAction(null);
/**
* @return an Action that will display the {@link PreferenceDialog}.
*/
public final InspectorAction preferences() {
return preferences;
}
/**
* Action: refreshes all data from the VM.
*/
final class RefreshAllAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Refresh all views";
RefreshAllAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
inspection().refreshAll(true);
}
}
private final InspectorAction refreshAll = new RefreshAllAction(null);
/**
* @return singleton Action that updates all displayed information read from the VM.
*/
public final InspectorAction refreshAll() {
return refreshAll;
}
/**
* Action: quits inspection session.
*/
final class QuitAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Quit Inspector";
QuitAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
inspection().quit();
}
}
private final InspectorAction quitAction = new QuitAction(null);
/**
* @return Singleton Action that quits the VM inspection session.
*/
public final InspectorAction quit() {
return quitAction;
}
/**
* Action: relocates the boot image.
*/
final class RelocateBootImageAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Relocate Boot Image";
RelocateBootImageAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
try {
vm().advanceToJavaEntryPoint();
} catch (IOException ioException) {
gui().errorMessage("error during relocation of boot image");
}
setEnabled(false);
}
}
private final InspectorAction relocateBootImageAction = new RelocateBootImageAction(null);
/**
* @return Singleton Action that relocates the boot image.
*/
public final InspectorAction relocateBootImage() {
return relocateBootImageAction;
}
/**
* Action: sets level of trace output in Inspector code.
*/
final class SetInspectorTraceLevelAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set Inspector trace level...";
SetInspectorTraceLevelAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final int oldLevel = Trace.level();
int newLevel = oldLevel;
final String input = gui().inputDialog(DEFAULT_TITLE, Integer.toString(oldLevel));
if (input == null) {
// User clicked cancel.
return;
}
try {
newLevel = Integer.parseInt(input);
} catch (NumberFormatException numberFormatException) {
gui().errorMessage(numberFormatException.toString());
}
if (newLevel != oldLevel) {
Trace.on(newLevel);
}
}
}
private final InspectorAction setInspectorTraceLevelAction = new SetInspectorTraceLevelAction(null);
/**
* @return Singleton interactive Action that permits setting the level of Inspector {@link Trace} output.
*/
public final InspectorAction setInspectorTraceLevel() {
return setInspectorTraceLevelAction;
}
/**
* Action: changes the threshold determining when the Inspectors uses its
* {@linkplain TeleInterpreter interpreter} for access to VM state.
*/
final class ChangeInterpreterUseLevelAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Change Interpreter use level...";
ChangeInterpreterUseLevelAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final int oldLevel = vm().getInterpreterUseLevel();
int newLevel = oldLevel;
final String input = gui().inputDialog("Change interpreter use level (0=none, 1=some, etc)", Integer.toString(oldLevel));
if (input == null) {
// User clicked cancel.
return;
}
try {
newLevel = Integer.parseInt(input);
} catch (NumberFormatException numberFormatException) {
gui().errorMessage(numberFormatException.toString());
}
if (newLevel != oldLevel) {
vm().setInterpreterUseLevel(newLevel);
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final InspectorAction changeInterpreterUseLevelAction = new ChangeInterpreterUseLevelAction(null);
/**
* @return Singleton interactive action that permits changing the level at which the interpreter
* will be used when communicating with the VM.
*/
public final InspectorAction changeInterpreterUseLevel() {
return changeInterpreterUseLevelAction;
}
/**
* Action: sets debugging level for transport.
* Appears unused October '08 (mlvdv)
*/
final class SetTransportDebugLevelAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set transport debug level...";
SetTransportDebugLevelAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final int oldLevel = vm().transportDebugLevel();
int newLevel = oldLevel;
final String input = gui().inputDialog(" (Set transport debug level, 0=none, 1=some, etc)", Integer.toString(oldLevel));
if (input == null) {
// User clicked cancel.
return;
}
try {
newLevel = Integer.parseInt(input);
} catch (NumberFormatException numberFormatException) {
gui().errorMessage(numberFormatException.toString());
}
if (newLevel != oldLevel) {
vm().setTransportDebugLevel(newLevel);
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final InspectorAction setTransportDebugLevelAction = new SetTransportDebugLevelAction(null);
/**
* @return Singleton interactive action that permits setting the debugging level for transport.
*/
public final InspectorAction setTransportDebugLevel() {
return setTransportDebugLevelAction;
}
/**
* Action: runs Inspector commands from a specified file.
*/
final class RunFileCommandsAction extends InspectorAction {
RunFileCommandsAction() {
super(inspection(), "Execute commands from file...");
}
@Override
protected void procedure() {
final String fileName = gui().inputDialog("File name: ", FileCommands.defaultCommandFile());
if (fileName != null && !fileName.equals("")) {
vm().executeCommandsFromFile(fileName);
}
}
}
private final InspectorAction runFileCommandsAction = new RunFileCommandsAction();
/**
* @return Singleton interactive Action that will run Inspector commands from a specified file.
*/
public final InspectorAction runFileCommands() {
return runFileCommandsAction;
}
/**
* Action: updates the {@linkplain MaxClasses#updateLoadableTypeDescriptorsFromClasspath() types available} on
* the VM's class path by rescanning the complete class path for types.
*/
final class UpdateClasspathTypesAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Rescan class path for types";
UpdateClasspathTypesAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().classes().updateLoadableTypeDescriptorsFromClasspath();
}
}
private final InspectorAction updateClasspathTypesAction = new UpdateClasspathTypesAction(null);
/**
* @return Singleton Action that updates the {@linkplain MaxClasses#updateLoadableTypeDescriptorsFromClasspath() types available} on
* the VM's class path by rescanning the complete class path for types.
*/
public final InspectorAction updateClasspathTypes() {
return updateClasspathTypesAction;
}
/**
* Action: sets the level of tracing in the VM interactively.
*/
final class SetVMTraceLevelAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set VM trace level";
SetVMTraceLevelAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final int oldLevel = vm().getVMTraceLevel();
int newLevel = oldLevel;
final String input = gui().inputDialog("Set VM Trace Level", Integer.toString(oldLevel));
if (input == null) {
// User clicked cancel.
return;
}
try {
newLevel = Integer.parseInt(input);
} catch (NumberFormatException numberFormatException) {
gui().errorMessage(numberFormatException.toString());
}
if (newLevel != oldLevel) {
vm().setVMTraceLevel(newLevel);
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private InspectorAction setVMTraceLevel = new SetVMTraceLevelAction(null);
/**
* @return an interactive Action that will set the level of tracing in the VM.
*/
public final InspectorAction setVMTraceLevel() {
return setVMTraceLevel;
}
/**
* Action: sets the threshold of tracing in the VM interactively.
*/
final class SetVMTraceThresholdAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set VM trace threshold";
SetVMTraceThresholdAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final long oldThreshold = vm().getVMTraceThreshold();
long newThreshold = oldThreshold;
final String input = gui().inputDialog("Set VM trace threshold", Long.toString(oldThreshold));
if (input == null) {
// User clicked cancel.
return;
}
try {
newThreshold = Long.parseLong(input);
} catch (NumberFormatException numberFormatException) {
gui().errorMessage(numberFormatException.toString());
}
if (newThreshold != oldThreshold) {
vm().setVMTraceThreshold(newThreshold);
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private InspectorAction setVMTraceThreshold = new SetVMTraceThresholdAction(null);
/**
* @return an interactive Action that will set the threshold of tracing in the VM.
*/
public final InspectorAction setVMTraceThreshold() {
return setVMTraceThreshold;
}
/**
* Action: copies a hex string version of a {@link Word} to the system clipboard.
*/
final class CopyWordAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy word to clipboard";
private final Word word;
private CopyWordAction(Word word, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.word = word;
}
@Override
public void procedure() {
gui().postToClipboard(word.toHexString());
}
}
/**
* @param word a {@link Word} from the VM.
* @param actionTitle a string to use as the title of the action, uses default name if null.
* @return an Action that copies the word's text value in hex to the system clipboard
*/
public final InspectorAction copyWord(Word word, String actionTitle) {
return new CopyWordAction(word, actionTitle);
}
/**
* Action: copies a string version of a {@link Value} to the system clipboard.
*/
final class CopyValueAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy value to clipboard";
private final Value value;
private CopyValueAction(Value value, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.value = value;
}
@Override
public void procedure() {
final Kind kind = value.kind();
if (kind == Kind.REFERENCE || kind == Kind.WORD) {
gui().postToClipboard(value.asWord().toHexString());
} else {
gui().postToClipboard(value.toString());
}
}
}
/**
* @param value a {@link Word} wrapped as a {@link Value} from the VM.
* @param actionTitle a string to use as the title of the action, uses default name if null.
* @return an Action that copies the word's text value in hex to the system clipboard,
* null if not a word.
*/
public final InspectorAction copyValue(Value value, String actionTitle) {
return new CopyValueAction(value, actionTitle);
}
/**
* Action: copies a hex string version of a VM object's origin to the system clipboard.
*/
final class CopyObjectOriginAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy object origin to clipboard";
private final MaxObject object;
private CopyObjectOriginAction(MaxObject object, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
}
@Override
public void procedure() {
gui().postToClipboard(object.origin().toHexString());
}
}
/**
* Creates an action that will copy a hex string version of a VM object's origin
* to the system clipboard.
*
* @param object a VM object
* @param actionTitle optional title of the action
* @return an action to copy the object's origin address
*/
public final InspectorAction copyObjectOrigin(MaxObject object, String actionTitle) {
return new CopyObjectOriginAction(object, actionTitle);
}
/**
* Action: copies a hex string version of a VM object's origin,
* followed by a textual description of the object to the system clipboard.
*/
final class CopyObjectDescriptionAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy object origin to clipboard";
private final MaxObject object;
private CopyObjectDescriptionAction(MaxObject object, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
}
@Override
public void procedure() {
final StringBuilder sb = new StringBuilder(object.origin().toHexString());
sb.append(": ");
sb.append(inspection().nameDisplay().referenceLabelText(object));
gui().postToClipboard(sb.toString());
}
}
/**
* Creates an action that will copy a hex string version of a VM object's origin,
* followed by a textual description of the object to the system clipboard.
*
* @param object the VM object to be described
* @param actionTitle optional title of the action
* @return an action to copy the description
*/
public final InspectorAction copyObjectDescription(MaxObject object, String actionTitle) {
return new CopyObjectDescriptionAction(object, actionTitle);
}
/**
* Menu: display a sub-menu of commands to inspect the basic allocation
* regions of the VM.
*/
final class ViewMemoryAllocationsMenu extends JMenu {
public ViewMemoryAllocationsMenu() {
super("View Memory allocated for:");
addMenuListener(new MenuListener() {
public void menuCanceled(MenuEvent e) {
}
public void menuDeselected(MenuEvent e) {
}
public void menuSelected(MenuEvent e) {
removeAll();
final SortedSet<MaxMemoryRegion> regionSet = new TreeSet<MaxMemoryRegion>(MaxMemoryRegion.Util.nameComparator());
regionSet.addAll(vm().state().memoryAllocations());
for (MaxMemoryRegion memoryRegion : regionSet) {
//System.out.println(memoryRegion.toString());
add(views().memory().makeViewAction(memoryRegion, memoryRegion.regionName(), memoryRegion.regionName()));
}
}
});
}
}
/**
* Creates a menu of actions to view allocated memory regions.
* <br>
* <strong>Note:</strong> This menu does not depend on context, so it would be natural to use
* a singleton to be shared among all uses. Unfortunately, that does not seem to work.
*
* @return a dynamically populated menu that contains an action to view each currently allocated
* region of memory in the VM.
*/
public final JMenu viewMemoryAllocationsMenu() {
return new ViewMemoryAllocationsMenu();
}
public final JMenu viewHeapRegionInfoMenu() {
return HeapRegionInfoView.viewManager(inspection()).viewMenu();
}
/**
* Action: view the HeapRegionInfo for the currently selected WordValueLabel when this one is in a mode denoting a heap address.
*/
final class ViewSelectedAddressHeapRegionInfo extends InspectorAction {
public ViewSelectedAddressHeapRegionInfo(String actionTitle) {
super(inspection(), actionTitle == null ? "View heap region info for selected address" : actionTitle);
}
@Override
protected void procedure() {
MaxMemoryManagementInfo info = inspection().vm().heap().getMemoryManagementInfo(focus().address());
// TODO: revisit this.
if (info.status().equals(MaxMemoryManagementStatus.LIVE)) {
final MaxObject object = info.tele();
focus().setHeapObject(object);
}
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a heap region info view
* for the memory location at the selected address
*/
public final InspectorAction viewSelectedAddressHeapRegionInfo(String actionTitle) {
return new ViewSelectedAddressHeapRegionInfo(actionTitle);
}
/**
*Action: view the memory allocated to the currently selected thread's stack.
*/
final class ViewSelectedThreadStackMemoryAction extends InspectorAction {
public ViewSelectedThreadStackMemoryAction(String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for selected thread's stack" : actionTitle);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
if (thread != null) {
views().memory().makeView(thread.stack().memoryRegion(), "Thread " + thread.toShortString()).highlight();
} else {
gui().errorMessage("no thread selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread());
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for memory allocated by the currently selected stack frame
*/
public final InspectorAction viewSelectedThreadStackMemory(String actionTitle) {
return new ViewSelectedThreadStackMemoryAction(actionTitle);
}
/**
*Action: view the memory allocated to the currently selected thread's stack.
*/
final class ViewSelectedThreadVMLogMemoryAction extends InspectorAction {
public ViewSelectedThreadVMLogMemoryAction(String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for selected thread's VM log" : actionTitle);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
if (thread != null) {
MaxEntityMemoryRegion<MaxThreadVMLog> memoryRegion = thread.vmLog().memoryRegion();
if (memoryRegion != null) {
views().memory().makeView(thread.vmLog().memoryRegion(), "Thread " + thread.toShortString()).highlight();
} else {
gui().errorMessage("thread has no VM log buffer");
}
} else {
gui().errorMessage("no thread selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread());
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for memory allocated by the currently selected stack frame
*/
public final InspectorAction viewSelectedThreadVMLogMemory(String actionTitle) {
return new ViewSelectedThreadVMLogMemoryAction(actionTitle);
}
/**
*Action: view the memory allocated to the currently selected thread's locals block.
*/
final class ViewSelectedThreadLocalsBlockMemoryAction extends InspectorAction {
public ViewSelectedThreadLocalsBlockMemoryAction(String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for selected thread's locals block" : actionTitle);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
if (thread != null) {
views().memory().makeView(thread.localsBlock().memoryRegion(), "Thread locals block " + thread.toShortString()).highlight();
} else {
gui().errorMessage("no thread selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && focus().thread().localsBlock().memoryRegion() != null);
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for the thread locals block allocated by the currently selected thread
*/
public final InspectorAction viewSelectedThreadLocalsBlockMemory(String actionTitle) {
return new ViewSelectedThreadLocalsBlockMemoryAction(actionTitle);
}
/**
*Action: view the memory allocated to one of the currently selected thread's locals areas.
*/
final class ViewSelectedThreadLocalsAreaMemoryAction extends InspectorAction {
private final SafepointPoll.State state;
public ViewSelectedThreadLocalsAreaMemoryAction(SafepointPoll.State state, String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for selected thread's locals area=" + state.name() : actionTitle);
this.state = state;
}
@Override
protected void procedure() {
final MaxMemoryRegion memoryRegion = getMemoryRegion();
if (memoryRegion != null) {
final String regionName = "Thread locals area " + state.name() + " for " + focus().thread().toShortString();
views().memory().makeView(memoryRegion, regionName).highlight();
} else {
gui().errorMessage("no region found");
}
}
@Override
public void refresh(boolean force) {
setEnabled(getMemoryRegion() != null);
}
private MaxMemoryRegion getMemoryRegion() {
final MaxThread thread = focus().thread();
if (thread != null) {
final MaxThreadLocalsBlock localsBlock = thread.localsBlock();
if (localsBlock != null) {
final MaxThreadLocalsArea tlaFor = localsBlock.tlaFor(state);
if (tlaFor != null) {
final MaxEntityMemoryRegion<MaxThreadLocalsArea> memoryRegion = tlaFor.memoryRegion();
return memoryRegion;
}
}
}
return null;
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for one of the thread locals areas allocated by the currently selected thread
*/
public final InspectorAction viewSelectedThreadLocalsAreaMemory(SafepointPoll.State state, String actionTitle) {
return new ViewSelectedThreadLocalsAreaMemoryAction(state, actionTitle);
}
/**
*Action: view the memory allocated to the currently selected stack frame.
*/
final class ViewSelectedStackFrameMemoryAction extends InspectorAction {
public ViewSelectedStackFrameMemoryAction(String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for selected stack frame" : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxStackFrame stackFrame = focus().stackFrame();
if (stackFrame != null) {
views().memory().makeView(stackFrame.memoryRegion(), "Stack Frame " + stackFrame.entityName()).highlight();
} else {
gui().errorMessage("no stack frame selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasStackFrame() && focus().stackFrame().memoryRegion() != null);
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for memory allocated by the currently selected stack frame
*/
public final InspectorAction viewSelectedStackFrameMemory(String actionTitle) {
return new ViewSelectedStackFrameMemoryAction(actionTitle);
}
/**
*Action: view the memory allocated to a stack frame.
*/
final class ViewStackFrameMemoryAction extends InspectorAction {
private final MaxStackFrame stackFrame;
public ViewStackFrameMemoryAction(MaxStackFrame stackFrame, String actionTitle) {
super(inspection(), actionTitle == null ? "View memory for stack frame" : actionTitle);
assert stackFrame != null;
this.stackFrame = stackFrame;
}
@Override
protected void procedure() {
if (stackFrame.memoryRegion() != null) {
views().memory().makeView(stackFrame.memoryRegion(), "Stack Frame " + stackFrame.entityName()).highlight();
} else {
gui().errorMessage("stack frame " + stackFrame.entityName() + " null memory region");
}
}
}
/**
* @param actionTitle title for the action, uses a default if null
* @return an action that will create a memory view
* for memory allocated by the currently selected stack frame
*/
public final InspectorAction viewtackFrameMemory(MaxStackFrame stackFrame, String actionTitle) {
return new ViewStackFrameMemoryAction(stackFrame, actionTitle);
}
/**
*Action: view the memory allocated to the currently selected memory watchpoint.
*/
final class ViewSelectedMemoryWatchpointAction extends InspectorAction {
public ViewSelectedMemoryWatchpointAction(String actionTitle) {
super(inspection(), actionTitle == null ? "View memory at selected watchpoint" : actionTitle);
}
@Override
protected void procedure() {
final MaxWatchpoint watchpoint = focus().watchpoint();
if (watchpoint != null) {
views().memory().makeView(watchpoint.memoryRegion(), "Watchpoint " + watchpoint.description()).highlight();
} else {
gui().errorMessage("no watchpoint selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasWatchpoint());
}
}
private final InspectorAction viewSelectedMemoryWatchpointAction = new ViewSelectedMemoryWatchpointAction(null);
/**
* @return Singleton action that will create a memory view
* for memory allocated by the currently selected thread
*/
public final InspectorAction viewSelectedMemoryWatchpointAction() {
return viewSelectedMemoryWatchpointAction;
}
/**
* Action: creates a memory view for the currently selected memory region, if any.
*/
final class ViewSelectedMemoryRegionAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View selected memory region";
ViewSelectedMemoryRegionAction() {
super(inspection(), DEFAULT_TITLE);
refreshableActions.add(this);
refresh(true);
}
@Override
protected void procedure() {
final MaxMemoryRegion memoryRegion = focus().memoryRegion();
if (memoryRegion != null) {
views().memory().makeView(memoryRegion, memoryRegion.regionName()).highlight();
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasMemoryRegion());
}
}
private final InspectorAction viewSelectedMemoryRegionAction = new ViewSelectedMemoryRegionAction();
/**
* @return Singleton Action that will create a Memory view for the currently selected region of memory
*/
public final InspectorAction viewSelectedMemoryRegion() {
return viewSelectedMemoryRegionAction;
}
/**
* Action: sets inspection focus to specified {@link MaxMemoryRegion}.
*/
final class SelectMemoryRegionAction extends InspectorAction {
private final MaxMemoryRegion memoryRegion;
private static final String DEFAULT_TITLE = "Select memory region";
SelectMemoryRegionAction(MaxMemoryRegion memoryRegion, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.memoryRegion = memoryRegion;
}
@Override
protected void procedure() {
focus().setMemoryRegion(memoryRegion);
}
}
/**
* @return an Action that will create a Memory Inspector at the start of the boot code
*/
public final InspectorAction selectMemoryRegion(MaxMemoryRegion memoryRegion) {
final String actionTitle = "Select memory region \"" + memoryRegion.regionName() + "\"";
return new SelectMemoryRegionAction(memoryRegion, actionTitle);
}
/**
* Menu: display a sub-menu of commands to inspect the basic allocation
* regions of the VM.
*/
final class ViewSingletonMenu extends JMenu {
public ViewSingletonMenu() {
super("View VM singletons:");
addMenuListener(new MenuListener() {
public void menuCanceled(MenuEvent e) {
}
public void menuDeselected(MenuEvent e) {
}
public void menuSelected(MenuEvent e) {
removeAll();
for (MaxObject object : vm().inspectableObjects()) {
add(views().objects().makeViewAction(object, object.maxineRole()));
}
}
});
}
}
/**
* Creates a menu of actions to view allocated memory regions.
* <br>
* <strong>Note:</strong> This menu does not depend on context, so it would be natural to use
* a singleton to be shared among all uses. Unfortunately, that does not seem to work.
*
* @return a dynamically populated menu that contains an action to view each currently allocated
* region of memory in the VM.
*/
public final JMenu viewSingletonMenu() {
return new ViewSingletonMenu();
}
/**
* Action: view a {@link ClassActor} object for an interactively named class loaded in the VM,
* specified by class name.
*/
final class ViewClassActorByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View ClassActor by name...";
ViewClassActorByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View ClassActor ...", "View");
if (teleClassActor != null) {
focus().setHeapObject(teleClassActor);
}
}
}
private final InspectorAction viewClassActorByNameAction = new ViewClassActorByNameAction(null);
/**
* @return Singleton interactive Action that views a {@link ClassActor} object for a class loaded in the VM,
* specified by class name.
*/
public final InspectorAction viewClassActorByName() {
return viewClassActorByNameAction;
}
/**
* Action: view a {@link ClassActor} for an interactively named class loaded in the VM,
* specified by the class ID in hex.
*/
final class ViewClassActorByHexIdAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View ClassActor by ID (Hex) ...";
ViewClassActorByHexIdAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final String value = gui().questionMessage("ID (hex): ");
if (value != null && !value.equals("")) {
try {
final int serial = Integer.parseInt(value, 16);
final TeleClassActor teleClassActor = vm().classes().findTeleClassActor(serial);
if (teleClassActor == null) {
gui().errorMessage("failed to find classActor for ID: " + InspectorLabel.intTo0xHex(serial));
} else {
focus().setHeapObject(teleClassActor);
}
} catch (NumberFormatException ex) {
gui().errorMessage("Hex integer required");
}
}
}
}
private final InspectorAction viewClassActorByHexIdAction = new ViewClassActorByHexIdAction(null);
/**
* @return Singleton interactive Action that views a {@link ClassActor} object for a class loaded in the VM,
* specified by class ID in hex.
*/
public final InspectorAction viewClassActorByHexId() {
return viewClassActorByHexIdAction;
}
/**
* Action: view a {@link ClassActor} for an interactively named class loaded in the VM,
* specified by the class ID in decimal.
*/
final class ViewClassActorByDecimalIdAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View ClassActor by ID (decimal) ...";
ViewClassActorByDecimalIdAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final String value = gui().questionMessage("ID (decimal): ");
if (value != null && !value.equals("")) {
try {
final int serial = Integer.parseInt(value, 10);
final TeleClassActor teleClassActor = vm().classes().findTeleClassActor(serial);
if (teleClassActor == null) {
gui().errorMessage("failed to find ClassActor for ID: " + serial);
} else {
focus().setHeapObject(teleClassActor);
}
} catch (NumberFormatException ex) {
gui().errorMessage("Hex integer required");
}
}
}
}
private final InspectorAction viewClassActorByDecimalIdAction = new ViewClassActorByDecimalIdAction(null);
/**
* @return Singleton interactive Action that views a {@link ClassActor} object for a class loaded in the VM,
* specified by class ID in decimal.
*/
public final InspectorAction viewClassActorByDecimalId() {
return viewClassActorByDecimalIdAction;
}
/**
* Action: view the {@link StaticTuple} object for an interactively named class loaded in the VM,
* specified by class name.
*/
final class ViewStaticTupleByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View StaticTuple by class name...";
ViewStaticTupleByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View StaticTuple for class ...", "View");
if (teleClassActor != null) {
TeleStaticTuple staticTuple = teleClassActor.getTeleStaticTuple();
if (staticTuple == null) {
gui().errorMessage("StaticTuple for class not available");
} else {
focus().setHeapObject(staticTuple);
}
}
}
}
private final InspectorAction viewStaticTupleByNameAction = new ViewStaticTupleByNameAction(null);
/**
* @return Singleton interactive Action that views the {@link StaticTuple} object for a class loaded in the VM,
* specified by class name.
*/
public final InspectorAction viewStaticTupleByName() {
return viewStaticTupleByNameAction;
}
/**
* Action: view the {@link StaticTuple} object for an interactively named class loaded in the VM,
* specified by class name.
*/
final class ViewStaticTupleForObjectAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View StaticTuple for object class";
private final MaxObject object;
private TeleStaticTuple staticTuple = null;
/**
* @param object
* @param actionTitle
*/
ViewStaticTupleForObjectAction(MaxObject object, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
setEnabled(false);
ClassActor classActor = object.classActorForObjectType();
if (classActor != null) {
Class< ? > javaClass = classActor.toJava();
if (javaClass != null) {
TeleClassActor teleClassActor = vm().classes().findTeleClassActor(javaClass);
if (teleClassActor != null) {
this.staticTuple = teleClassActor.getTeleStaticTuple();
if (staticTuple != object) {
// Only enable if we find a static tuple, and if the object
// is not itself a static tuple, in which case it is its own static tuple.
setName("View StaticTuple for class " + javaClass.getSimpleName());
setEnabled(true);
}
}
}
}
}
@Override
protected void procedure() {
if (staticTuple == null) {
gui().errorMessage("StaticTuple for class not available");
} else {
focus().setHeapObject(staticTuple);
}
}
}
/**
* @return Singleton interactive Action that views the {@link StaticTuple} object for a class loaded in the VM,
* specified by class name.
*/
public final InspectorAction viewStaticTupleForObject(MaxObject object) {
return new ViewStaticTupleForObjectAction(object, null);
}
/**
* Action: view the {@link DynamicHub} object for an interactively named class loaded in the VM,
* specified by class name.
*/
final class ViewDynamicHubByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View DynamicHub by class name...";
ViewDynamicHubByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View DynamicHub for class ...", "View");
if (teleClassActor != null) {
final TeleDynamicHub dynamicHub = teleClassActor.getTeleDynamicHub();
if (dynamicHub == null) {
gui().errorMessage("DynamicHub for class not available");
} else {
focus().setHeapObject(dynamicHub);
}
}
}
}
private final InspectorAction viewDynamicHubByNameAction = new ViewDynamicHubByNameAction(null);
/**
* @return Singleton interactive Action that views a {@link DynamicHub} object for a class loaded in the VM,
* specified by class name.
*/
public final InspectorAction viewDynamicHubByName() {
return viewDynamicHubByNameAction;
}
/**
* Action: view the {@link StaticHub} object for an interactively named class loaded in the VM,
* specified by class name.
*/
final class ViewStaticHubByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View StaticHub by class name...";
ViewStaticHubByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View StaticHub for class ...", "View");
if (teleClassActor != null) {
final TeleStaticHub staticicHub = teleClassActor.getTeleStaticHub();
if (staticicHub == null) {
gui().errorMessage("StaticHub for class not available");
} else {
focus().setHeapObject(staticicHub);
}
}
}
}
private final InspectorAction viewStaticHubByNameAction = new ViewStaticHubByNameAction(null);
/**
* @return Singleton interactive Action that views the {@link StaticHub} object for a class loaded in the VM,
* specified by class name.
*/
public final InspectorAction viewStaticHubByName() {
return viewStaticHubByNameAction;
}
/**
* Action: view a {@link MethodActor} object in the VM, specified by name.
*/
final class ViewMethodActorByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View MethodActor by name...";
ViewMethodActorByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View MethodActor in class...", "Select");
if (teleClassActor != null) {
final TeleMethodActor teleMethodActor = MethodActorSearchDialog.show(inspection(), teleClassActor, "View MethodActor...", "View");
if (teleMethodActor != null) {
focus().setHeapObject(teleMethodActor);
}
}
}
}
private InspectorAction viewMethodActorByName = new ViewMethodActorByNameAction(null);
/**
* @return an interactive Action that will view a {@link MethodActor} object in the VM, specified by name.
*/
public final InspectorAction viewMethodActorByName() {
return viewMethodActorByName;
}
/**
* Action: view the class actor from which a method was substituted.
*/
final class ViewSubstitutionSourceClassActorAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View method substitution source";
private final TeleClassMethodActor teleClassMethodActor;
private ViewSubstitutionSourceClassActorAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
setEnabled(teleClassMethodActor.isSubstituted());
}
@Override
public void procedure() {
if (teleClassMethodActor != null) {
focus().setHeapObject(teleClassMethodActor.teleClassActorSubstitutedFrom());
}
}
}
/**
* Creates an action to view the class actor from which a method was substituted.
*
* @param teleClassMethodActor representation of a class method in the VM
* @param actionTitle name of the action
* @return an action that will view the class actor, if any, from which the method was substituted
*/
public final InspectorAction viewSubstitutionSourceClassActorAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new ViewSubstitutionSourceClassActorAction(teleClassMethodActor, actionTitle);
}
/**
* Creates an action to view the class actor from which a method was substituted.
*
* @param teleClassMethodActor representation of a class method in the VM
* @return an action that will view the class actor, if any, from which the method was substituted
*/
public final InspectorAction viewSubstitutionSourceClassActorAction(TeleClassMethodActor teleClassMethodActor) {
return new ViewSubstitutionSourceClassActorAction(teleClassMethodActor, null);
}
/**
* Menu: contains actions to view each of the compilations of a method.
*/
final class ViewMethodCompilationsMenu extends InspectorMenu {
private static final String DEFAULT_TITLE = "Compilations";
private final TeleClassMethodActor teleClassMethodActor;
public ViewMethodCompilationsMenu(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
refresh(true);
}
@Override
public void refresh(boolean force) {
final List<MaxCompilation> compilations = vm().machineCode().compilations(teleClassMethodActor);
if (getMenuComponentCount() < compilations.size()) {
for (int index = getMenuComponentCount(); index < compilations.size(); index++) {
final MaxCompilation compilation = compilations.get(index);
final String name = inspection().nameDisplay().shortName(compilation);
add(views().objects().makeViewAction(compilation.representation(), name.toString()));
}
}
}
}
/**
* Creates a menu containing actions to view all compilations of a method, dynamically updated
* as compilations are added.
*
* @param teleClassMethodActor representation of a Java method in the VM
* @param actionTitle name of the action to appear on button or menu
* @return a dynamically refreshed menu that contains actions to view each of the compilations of a method.
*/
public InspectorMenu inspectMethodCompilationsMenu(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new ViewMethodCompilationsMenu(teleClassMethodActor, actionTitle);
}
/**
* Creates a menu containing actions to view all compilations of a method, dynamically updated
* as compilations are added.
*
* @param teleClassMethodActor representation of a Java method in the VM
* @return a dynamically refreshed menu that contains actions to view each of the compilations of a method.
*/
public InspectorMenu viewMethodCompilationsMenu(TeleClassMethodActor teleClassMethodActor) {
return new ViewMethodCompilationsMenu(teleClassMethodActor, null);
}
/**
* Action: displays Java source for a specified method.
*/
final class ViewJavaSourceAction extends InspectorAction {
private final TeleClassMethodActor teleClassMethodActor;
public ViewJavaSourceAction(TeleClassMethodActor teleClassMethodActor) {
super(inspection(), "View Java Source (external)");
this.teleClassMethodActor = teleClassMethodActor;
}
@Override
public void procedure() {
inspection().viewSourceExternally(new CiCodePos(null, teleClassMethodActor.classMethodActor(), 0));
}
}
/**
* Creates an action that will produce an external view of method source code.
*
* @param teleClassMethodActor surrogate of a Java method in the VM.
* @return an action that creates an external of the Java source for the method.
*/
public InspectorAction viewJavaSource(TeleClassMethodActor teleClassMethodActor) {
return new ViewJavaSourceAction(teleClassMethodActor);
}
/**
* Action: displays in the {@MethodInspector} the method or native function whose machine code contains
* an interactively specified address.
*/
final class ViewMachineCodeByAddressAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View code by address...";
public ViewMachineCodeByAddressAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
// Most likely situation is that we are just about to call a function method in which case RAX is the address
Address defaultAddress = Address.zero();
final MaxThread thread = focus().thread();
if (thread != null) {
final Address registerValue = thread.registers().getCallRegisterValue();
if (vm().machineCode().findMachineCode(registerValue) != null) {
defaultAddress = registerValue;
}
}
new AddressInputDialog(inspection(), defaultAddress, "View machine code containing address...", "View Code") {
@Override
protected String validateInput(Address address) {
if (address.isZero()) {
return "Zero is not a valid code address";
}
final MaxEntityMemoryRegion<? extends MaxEntity> memoryRegion = vm().state().findMemoryRegion(address);
if (!(memoryRegion.owner() instanceof MaxCodeHoldingRegion<?>)) {
return address.to0xHexString() + " points into region \"" + memoryRegion.regionName() + "\"";
}
return null;
}
@Override
public void entered(Address address) {
if (vm().machineCode().findMachineCode(address) == null) {
final String message = "Address " + address.to0xHexString() + " not in any known compilation or native function, try anyway?";
if (!gui().yesNoDialog(message)) {
return;
}
}
try {
focus().setCodeLocation(vm().codeLocations().createMachineCodeLocation(address, "user specified address"));
} catch (InvalidCodeAddressException e) {
gui().errorMessage("Unable to view, no code @ " + e.getAddressString() + ": " + e.getMessage());
}
}
};
}
}
private final InspectorAction viewMachineCodeByAddressAction = new ViewMachineCodeByAddressAction(null);
/**
* @return Singleton interactive action that displays in the {@link MethodView} the method whose
* machine code contains the specified address in the VM.
*/
public final InspectorAction viewMachineCodeByAddress() {
return viewMachineCodeByAddressAction;
}
/**
* Action: displays the method code containing an address.
*/
final class ViewMethodCodeAtLocationAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View code at a location";
private final MaxCodeLocation codeLocation;
public ViewMethodCodeAtLocationAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
assert codeLocation != null;
this.codeLocation = codeLocation;
refreshableActions.add(this);
}
@Override
protected void procedure() {
focus().setCodeLocation(codeLocation, true);
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread());
}
}
/**
* @return an Action that displays in the {@link MethodView} a method at some code location.
*/
public final InspectorAction viewMethodCodeAtLocation(MaxCodeLocation codeLocation, String actionTitle) {
return new ViewMethodCodeAtLocationAction(codeLocation, actionTitle);
}
/**
* Action: displays the method code containing the current code selection.
*/
final class ViewMethodCodeAtSelectionAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View code at current selection";
public ViewMethodCodeAtSelectionAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
focus().setCodeLocation(focus().codeLocation(), true);
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasCodeLocation());
}
}
private final ViewMethodCodeAtSelectionAction viewMethodCodeAtSelection = new ViewMethodCodeAtSelectionAction(null);
/**
* @return Singleton action that displays in the {@link MethodView} the method code
* containing the current code selection.
*/
public final InspectorAction viewMethodCodeAtSelection() {
return viewMethodCodeAtSelection;
}
/**
* Action: displays the method code containing the current instruction pointer.
*/
final class ViewMethodCodeAtIPAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View code at current IP";
public ViewMethodCodeAtIPAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
focus().setCodeLocation(focus().thread().ipLocation());
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread());
}
}
private final ViewMethodCodeAtIPAction viewMethodCodeAtIP = new ViewMethodCodeAtIPAction(null);
/**
* @return Singleton Action that displays in the {@link MethodView} the method
* containing the current instruction pointer.
*/
public final InspectorAction viewMethodCodeAtIP() {
return viewMethodCodeAtIP;
}
/**
* Action: displays the bytecode for a specified method.
*/
final class ViewMethodBytecodeAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View bytecode...";
private final TeleClassMethodActor teleClassMethodActor;
public ViewMethodBytecodeAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
setEnabled(teleClassMethodActor.hasCodeAttribute());
}
@Override
protected void procedure() {
final MaxCodeLocation teleCodeLocation = vm().codeLocations().createBytecodeLocation(teleClassMethodActor, 0, "view method bytecode action");
focus().setCodeLocation(teleCodeLocation);
}
}
/**
* @return an interactive Action that displays bytecode in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodBytecode(TeleClassMethodActor teleClassMethodActor) {
return new ViewMethodBytecodeAction(teleClassMethodActor, null);
}
/**
* Creates an action to view the bytecodes (if they exist) for a Java method.
*
* @param teleClassMethodActor
* @param actionTitle name of the action to appear in menu or button
* @return an interactive Action that displays bytecode in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodBytecode(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new ViewMethodBytecodeAction(teleClassMethodActor, actionTitle);
}
/**
* Action: displays the bytecode for an interactively specified method.
*/
final class ViewMethodBytecodeByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Bytecode...";
public ViewMethodBytecodeByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View bytecode for method in class...", "Select");
if (teleClassActor != null) {
final Predicate<TeleMethodActor> hasBytecodePredicate = new Predicate<TeleMethodActor>() {
public boolean evaluate(TeleMethodActor teleMethodActor) {
return teleMethodActor.hasCodeAttribute();
}
};
final TeleMethodActor teleMethodActor = MethodActorSearchDialog.show(inspection(), teleClassActor, hasBytecodePredicate, "View Bytecodes for Method...", "View");
if (teleMethodActor != null && teleMethodActor instanceof TeleClassMethodActor) {
final TeleClassMethodActor teleClassMethodActor = (TeleClassMethodActor) teleMethodActor;
final MaxCodeLocation teleCodeLocation = vm().codeLocations().createBytecodeLocation(teleClassMethodActor, 0, "view method by name bytecode action");
focus().setCodeLocation(teleCodeLocation);
}
}
}
}
private final InspectorAction viewMethodBytecodeByNameAction = new ViewMethodBytecodeByNameAction(null);
/**
* @return an interactive Action that displays bytecode in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodBytecodeByName() {
return viewMethodBytecodeByNameAction;
}
/**
* @param actionTitle name of the action to appear in menu or button
* @return an interactive Action that displays bytecode in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodBytecodeByName(String actionTitle) {
return new ViewMethodBytecodeByNameAction(actionTitle);
}
/**
* Action: displays the machine code for an interactively specified method.
*/
final class ViewMethodCompilationByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Method compilation...";
public ViewMethodCompilationByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "View compiled code for method in class...", "Select");
if (teleClassActor != null) {
final List<MaxCompilation> compilations =
MethodCompilationSearchDialog.show(inspection(), teleClassActor, "View Compiled Code for Method...", "View Code", false);
if (compilations != null) {
focus().setCodeLocation(Utils.first(compilations).getCallEntryLocation());
}
}
}
}
private final InspectorAction viewMethodCompilationByNameAction = new ViewMethodCompilationByNameAction(null);
/**
* @return Singleton interactive Action that displays machine code in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodCompilationByName() {
return viewMethodCompilationByNameAction;
}
/**
* Action: displays the machine code for an interactively specified method.
*/
final class ViewNativeFunctionByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Native function...";
public ViewNativeFunctionByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final MaxNativeLibrary nativeLibrary = NativeLibrarySearchDialog.show(inspection(), "View code for native function in library...", "Select");
if (nativeLibrary != null) {
final List<MaxNativeFunction> functions = NativeFunctionSearchDialog.show(inspection(), nativeLibrary, "View Native Function...", "View Code", false);
if (functions != null) {
try {
focus().setCodeLocation(vm().codeLocations().createMachineCodeLocation(Utils.first(functions).getCodeStart(), "native function address from library"), true);
} catch (InvalidCodeAddressException e) {
gui().errorMessage("Unable to view code, no code @ " + e.getAddressString() + ": " + e.getMessage());
}
}
}
}
}
private final InspectorAction viewNativeFunctionByNameAction = new ViewNativeFunctionByNameAction(null);
/**
* @return Singleton interactive Action that displays machine code in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewNativeFunctionByName() {
return viewNativeFunctionByNameAction;
}
/**
* Action: displays the compiled code for an interactively specified method.
*/
final class ViewMethodMachineCodeAction extends InspectorAction {
private static final String DEFAULT_TITLE = "View compiled code...";
public ViewMethodMachineCodeAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final List<MaxCompilation> compilations =
MethodCompilationSearchDialog.show(inspection(), null, "View compiled code for method...", "View Code", false);
if (compilations != null) {
focus().setCodeLocation(Utils.first(compilations).getCallEntryLocation(), false);
}
}
}
private final InspectorAction viewMethodMachineCodeAction = new ViewMethodMachineCodeAction(null);
/**
* @return Singleton interactive Action that displays machine code in the {@link MethodView}
* for a selected method.
*/
public final InspectorAction viewMethodMachineCode() {
return viewMethodMachineCodeAction;
}
/**
* Menu: contains actions to view code for each of the compilations of a method.
*/
final class ViewMethodCompilationsCodeMenu extends InspectorMenu {
private static final String DEFAULT_TITLE = "View compilations";
private final TeleClassMethodActor teleClassMethodActor;
public ViewMethodCompilationsCodeMenu(TeleClassMethodActor teleClassMethodactor, String actionTitle) {
super(actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodactor;
refresh(true);
}
@Override
public void refresh(boolean force) {
final List<MaxCompilation> compilations = vm().machineCode().compilations(teleClassMethodActor);
if (getMenuComponentCount() < compilations.size()) {
for (int index = getMenuComponentCount(); index < compilations.size(); index++) {
final MaxCompilation compilation = compilations.get(index);
final StringBuilder name = new StringBuilder();
name.append(inspection().nameDisplay().shortMethodCompilationID(compilation));
name.append(" ");
name.append(compilation.classActorForObjectType().simpleName());
add(actions().viewMethodCodeAtLocation(compilation.getCallEntryLocation(), name.toString()));
}
}
}
}
/**
* Creates a menu containing actions to view the machine code for all compilations of a method, dynamically updated
* as compilations are added.
*
* @param teleClassMethodActor representation of a Java method in the VM
* @param actionTitle name of the action to appear on button or menu
* @return a dynamically refreshed menu that contains actions to view code for each of the compilations of a method.
*/
public InspectorMenu viewMethodCompilationsMenu(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new ViewMethodCompilationsCodeMenu(teleClassMethodActor, actionTitle);
}
/**
* Creates a menu containing actions to inspect the machine code for all compilations of a method, dynamically updated
* as compilations are added.
*
* @param teleClassMethodActor representation of a Java method in the VM
* @return a dynamically refreshed menu that contains actions to view code for each of the compilations of a method.
*/
public InspectorMenu viewMethodCompilationsCodeMenu(TeleClassMethodActor teleClassMethodActor) {
return new ViewMethodCompilationsCodeMenu(teleClassMethodActor, null);
}
/**
* Action: displays in the {@link MethodView} the code of a specified
* method in the boot image.
*/
final class ViewMethodCodeInBootImageAction extends InspectorAction {
private final int offset;
public ViewMethodCodeInBootImageAction(int offset, Class clazz, String name, Class... parameterTypes) {
super(inspection(), clazz.getName() + "." + name + SignatureDescriptor.fromJava(Void.TYPE, parameterTypes).toJavaString(false, false));
this.offset = offset;
}
public ViewMethodCodeInBootImageAction(int offset, Method method) {
this(offset, method.getDeclaringClass(), method.getName(), method.getParameterTypes());
}
@Override
protected void procedure() {
try {
focus().setCodeLocation(vm().codeLocations().createMachineCodeLocation(vm().bootImageStart().plus(offset), "address from boot image"), true);
} catch (InvalidCodeAddressException e) {
gui().errorMessage("Unable to view, no machine code @ " + e.getAddressString() + ": " + e.getMessage());
}
}
}
private final InspectorAction viewRunMethodCodeInBootImageAction =
new ViewMethodCodeInBootImageAction(vm().bootImage().header.vmRunMethodOffset, ClassRegistry.MaxineVM_run.toJava());
/**
* @return an Action that displays in the {@link MethodView} the code of
* the {@link MaxineVM} run method in the boot image.
*/
public final InspectorAction viewRunMethodCodeInBootImage() {
return viewRunMethodCodeInBootImageAction;
}
private final InspectorAction viewThreadRunMethodCodeInBootImageAction =
new ViewMethodCodeInBootImageAction(vm().bootImage().header.vmThreadRunMethodOffset, ClassRegistry.VmThread_run.toJava());
/**
* @return an Action that displays in the {@link MethodView} the code of
* the {@link VmThread} run method in the boot image.
*/
public final InspectorAction viewThreadRunMethodCodeInBootImage() {
return viewThreadRunMethodCodeInBootImageAction;
}
/**
* Action: copies to the system clipboard a textual representation of the
* disassembled machine code for a method compilation.
*/
final class CopyCompiledCodeToClipboardAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy disassembled machine code to clipboard";
private final MaxCompilation compilation;
private CopyCompiledCodeToClipboardAction(MaxCompilation compilation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.compilation = compilation;
}
@Override
public void procedure() {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final PrintStream printStream = new PrintStream(outputStream);
compilation.writeSummary(printStream);
gui().postToClipboard(outputStream.toString());
}
}
/**
* @return an Action that copies to the system clipboard a textual disassembly of machine code.
*/
public InspectorAction copyCompiledCodeToClipboard(MaxCompilation compilation, String actionTitle) {
return new CopyCompiledCodeToClipboardAction(compilation, actionTitle);
}
/**
* Action: copies to the system clipboard a textual representation of the
* disassembled machine code for a method compilation.
*/
final class CopyBytecodeToClipboardAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Copy disassembled bytecode to clipboard";
private final TeleClassMethodActor teleClassMethodActor;
private CopyBytecodeToClipboardAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
}
@Override
public void procedure() {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final PrintStream printStream = new PrintStream(outputStream);
teleClassMethodActor.writeSummary(printStream);
gui().postToClipboard(outputStream.toString());
}
}
/**
* @return an Action that copies to the system clipboard a textual disassembly of machine code.
*/
public InspectorAction copyBytecodeToClipboard(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new CopyBytecodeToClipboardAction(teleClassMethodActor, actionTitle);
}
/**
* Menu: display a sub-menu of commands for setting breakpoints at standard locations.
*/
final class BuiltinBreakpointsMenu extends InspectorMenu {
public BuiltinBreakpointsMenu(String title) {
super(title == null ? "Break at" : title);
addMenuListener(new MenuListener() {
public void menuCanceled(MenuEvent e) {
}
public void menuDeselected(MenuEvent e) {
}
public void menuSelected(MenuEvent e) {
removeAll();
for (MaxCodeLocation codeLocation : vm().inspectableMethods()) {
add(actions().setBreakpoint(codeLocation));
}
}
});
}
}
/**
* Action: removes the currently selected breakpoint from the VM.
*/
final class RemoveSelectedBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove selected breakpoint";
RemoveSelectedBreakpointAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
focus().addListener(new InspectionFocusAdapter() {
@Override
public void breakpointFocusSet(MaxBreakpoint oldBreakpoint, MaxBreakpoint breakpoint) {
refresh(false);
}
});
refresh(false);
}
@Override
protected void procedure() {
final MaxBreakpoint selectedBreakpoint = focus().breakpoint();
if (selectedBreakpoint != null) {
try {
selectedBreakpoint.remove();
focus().setBreakpoint(null);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
} else {
gui().errorMessage("No breakpoint selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasBreakpoint());
}
}
private InspectorAction removeBreakpoint = new RemoveSelectedBreakpointAction(null);
/**
* @return an Action that will remove the currently selected breakpoint, if any.
*/
public final InspectorAction removeSelectedBreakpoint() {
return removeBreakpoint;
}
/**
* Action: removes a specific breakpoint in the VM.
*/
final class RemoveBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove breakpoint";
final MaxBreakpoint breakpoint;
RemoveBreakpointAction(MaxBreakpoint breakpoint, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.breakpoint = breakpoint;
}
@Override
protected void procedure() {
if (focus().breakpoint() == breakpoint) {
focus().setBreakpoint(null);
}
try {
breakpoint.remove();
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
/**
* @param breakpoint surrogate for a breakpoint in the VM.
* @param actionTitle a string name for the Action, uses default name if null.
* @return an Action that will remove the breakpoint
*/
public final InspectorAction removeBreakpoint(MaxBreakpoint breakpoint, String actionTitle) {
return new RemoveBreakpointAction(breakpoint, actionTitle);
}
/**
* Action: removes all existing breakpoints in the VM.
*/
final class RemoveAllBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove all breakpoints";
RemoveAllBreakpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
inspection().addInspectionListener(new InspectionListenerAdapter() {
@Override
public void breakpointStateChanged() {
refresh(true);
}
});
}
@Override
protected void procedure() {
focus().setBreakpoint(null);
try {
for (MaxBreakpoint breakpoint : vm().breakpointManager().breakpoints()) {
breakpoint.remove();
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && (vm().breakpointManager().breakpoints().size() > 0));
}
}
private InspectorAction removeAllBreakpoints = new RemoveAllBreakpointsAction(null);
/**
* @return an Action that will remove all breakpoints in the VM.
*/
public final InspectorAction removeAllBreakpoints() {
return removeAllBreakpoints;
}
/**
* Action: enables a specific breakpoint in the VM.
*/
final class EnableBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Enable breakpoint";
final MaxBreakpoint breakpoint;
EnableBreakpointAction(MaxBreakpoint breakpoint, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.breakpoint = breakpoint;
}
@Override
protected void procedure() {
if (focus().breakpoint() == breakpoint) {
focus().setBreakpoint(null);
}
try {
breakpoint.setEnabled(true);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
inspection().refreshAll(false);
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && !breakpoint.isEnabled());
}
}
/**
* @param breakpoint surrogate for a breakpoint in the VM.
* @param actionTitle a string name for the Action, uses default name if null.
* @return an Action that will enable the breakpoint
*/
public final InspectorAction enableBreakpoint(MaxBreakpoint breakpoint, String actionTitle) {
return new EnableBreakpointAction(breakpoint, actionTitle);
}
/**
* Action: disables a specific breakpoint in the VM.
*/
final class DisableBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Disable breakpoint";
final MaxBreakpoint breakpoint;
DisableBreakpointAction(MaxBreakpoint breakpoint, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.breakpoint = breakpoint;
}
@Override
protected void procedure() {
if (focus().breakpoint() == breakpoint) {
focus().setBreakpoint(null);
}
try {
breakpoint.setEnabled(false);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
inspection().refreshAll(false);
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && breakpoint.isEnabled());
}
}
/**
* @param breakpoint surrogate for a breakpoint in the VM.
* @param actionTitle a string name for the Action, uses default name if null.
* @return an Action that will disable the breakpoint
*/
public final InspectorAction disableBreakpoint(MaxBreakpoint breakpoint, String actionTitle) {
return new DisableBreakpointAction(breakpoint, actionTitle);
}
/**
* Action: set a breakpoint.
*/
final class SetBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set breakpoint";
private final MaxCodeLocation codeLocation;
public SetBreakpointAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
assert codeLocation != null;
this.codeLocation = codeLocation;
refresh(true);
}
@Override
protected void procedure() {
try {
final MaxBreakpoint breakpoint = vm().breakpointManager().makeBreakpoint(codeLocation);
focus().setBreakpoint(breakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(vm().breakpointManager().findBreakpoint(codeLocation) == null);
}
}
public final InspectorAction setBreakpoint(MaxCodeLocation codeLocation, String actionTitle) {
return new SetBreakpointAction(codeLocation, actionTitle);
}
public final InspectorAction setBreakpoint(MaxCodeLocation codeLocation) {
return new SetBreakpointAction(codeLocation, codeLocation.description());
}
/**
* Action: set a machine code breakpoint at a particular address.
*/
final class SetMachineCodeBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set machine code breakpoint";
private final MaxCodeLocation codeLocation;
public SetMachineCodeBreakpointAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
assert codeLocation != null && codeLocation.hasAddress();
this.codeLocation = codeLocation;
refresh(true);
}
@Override
protected void procedure() {
try {
final MaxBreakpoint breakpoint = vm().breakpointManager().makeBreakpoint(codeLocation);
focus().setBreakpoint(breakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(vm().breakpointManager().findBreakpoint(codeLocation) == null);
}
}
public final InspectorAction setMachineCodeBreakpoint(MaxCodeLocation codeLocation, String actionTitle) {
return new SetMachineCodeBreakpointAction(codeLocation, actionTitle);
}
/**
* Action: remove a machine code breakpoint at a particular address.
*/
final class RemoveMachineCodeBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove machine code breakpoint";
private final MaxCodeLocation codeLocation;
public RemoveMachineCodeBreakpointAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
assert codeLocation != null && codeLocation.hasAddress();
this.codeLocation = codeLocation;
refresh(true);
}
@Override
protected void procedure() {
final MaxBreakpoint breakpoint = vm().breakpointManager().findBreakpoint(codeLocation);
if (breakpoint != null) {
try {
breakpoint.remove();
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
focus().setBreakpoint(null);
}
}
@Override
public void refresh(boolean force) {
setEnabled(vm().breakpointManager().findBreakpoint(codeLocation) != null);
}
}
public final InspectorAction removeMachineCodeBreakpoint(MaxCodeLocation codeLocation, String actionTitle) {
return new RemoveMachineCodeBreakpointAction(codeLocation, actionTitle);
}
/**
* Action: toggle on/off a breakpoint at the machine code location specified, or
* if not initialized, then to the machine code location of the current focus.
*/
final class ToggleMachineCodeBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Toggle machine code breakpoint";
private final MaxCodeLocation codeLocation;
ToggleMachineCodeBreakpointAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.codeLocation = null;
refreshableActions.add(this);
focus().addListener(new InspectionFocusAdapter() {
@Override
public void codeLocationFocusSet(MaxCodeLocation codeLocation, boolean interactiveForNative) {
refresh(false);
}
});
refresh(true);
}
ToggleMachineCodeBreakpointAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
assert codeLocation != null && codeLocation.hasAddress();
this.codeLocation = codeLocation;
}
@Override
protected void procedure() {
final MaxCodeLocation toggleCodeLocation = (codeLocation != null) ? codeLocation : focus().codeLocation();
if (toggleCodeLocation.hasAddress() && toggleCodeLocation.address().isNotZero()) {
MaxBreakpoint breakpoint = vm().breakpointManager().findBreakpoint(toggleCodeLocation);
try {
if (breakpoint == null) {
try {
breakpoint = vm().breakpointManager().makeBreakpoint(toggleCodeLocation);
focus().setBreakpoint(breakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
} else {
breakpoint.remove();
focus().setBreakpoint(null);
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && focus().hasCodeLocation() && focus().codeLocation().hasAddress());
}
}
private InspectorAction toggleMachineCodeBreakpoint = new ToggleMachineCodeBreakpointAction(null);
/**
* @return an Action that will toggle on/off a breakpoint at the machine code location of the current focus.
*/
public final InspectorAction toggleMachineCodeBreakpoint() {
return toggleMachineCodeBreakpoint;
}
/**
* @param actionTitle string that identifies the action
* @return an Action that will toggle on/off a breakpoint at the machine code location of the current focus.
*/
public final InspectorAction toggleMachineCodeBreakpoint(String actionTitle) {
return new ToggleMachineCodeBreakpointAction(actionTitle);
}
/**
* @param codeLocation code location
* @param actionTitle string that identifies the action
* @return an Action that will toggle on/off a breakpoint at the specified machine code location.
*/
public final InspectorAction toggleMachineCodeBreakpoint(MaxCodeLocation codeLocation, String actionTitle) {
return new ToggleMachineCodeBreakpointAction(codeLocation, actionTitle);
}
/**
* Action: sets a breakpoint at the machine code location specified interactively..
*/
final class SetMachineCodeBreakpointAtAddressAction extends InspectorAction {
private static final String DEFAULT_TITLE = "At address...";
SetMachineCodeBreakpointAtAddressAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
refresh(true);
}
@Override
protected void procedure() {
new NativeLocationInputDialog(inspection(), "Break at machine code address...", vm().bootImageStart(), "") {
@Override
public void entered(Address address, String description) {
MaxBreakpoint breakpoint = null;
try {
breakpoint = vm().breakpointManager().makeBreakpoint(vm().codeLocations().createMachineCodeLocation(address, "set machine breakpoint"));
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
return;
} catch (InvalidCodeAddressException e) {
gui().errorMessage("Unable to create breakpoint, no code @ " + e.getAddressString() + ": " + e.getMessage());
return;
}
if (breakpoint == null) {
gui().errorMessage("Unable to create breakpoint at: " + address.to0xHexString());
return;
}
breakpoint.setDescription(description);
}
};
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private InspectorAction setMachineCodeBreakpointAtAddressAction = new SetMachineCodeBreakpointAtAddressAction(null);
/**
* @return an Action that will toggle on/off a breakpoint at the machine code location of the current focus.
*/
public final InspectorAction setMachineCodeBreakpointAtAddress() {
return setMachineCodeBreakpointAtAddressAction;
}
/**
* Action: sets a breakpoint at every label in a compilation.
*/
final class SetMachineCodeLabelBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set breakpoint at every machine code label";
final MaxCompilation compilation;
SetMachineCodeLabelBreakpointsAction(MaxCompilation compilation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.compilation = compilation;
setEnabled(inspection().hasProcess() && compilation.getMachineCodeInfo().labelIndexes().size() > 0);
}
@Override
protected void procedure() {
try {
final MaxMachineCodeInfo machineCodeInfo = compilation.getMachineCodeInfo();
for (int index : machineCodeInfo.labelIndexes()) {
vm().breakpointManager().makeBreakpoint(machineCodeInfo.instructionLocation(index));
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
/**
* @return an Action that will set a breakpoint at every machine code label in a compilation
*/
public final InspectorAction setMachineCodeLabelBreakpoints(MaxCompilation compilation, String actionTitle) {
return new SetMachineCodeLabelBreakpointsAction(compilation, actionTitle);
}
/**
* Action: removes any breakpoints at machine code labels.
*/
final class RemoveMachineCodeLabelBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove breakpoint at every machine code label";
private final MaxCompilation compilation;
RemoveMachineCodeLabelBreakpointsAction(MaxCompilation compilation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.compilation = compilation;
setEnabled(inspection().hasProcess() && compilation.getMachineCodeInfo().labelIndexes().size() > 0);
}
@Override
protected void procedure() {
try {
final MaxMachineCodeInfo machineCodeInfo = compilation.getMachineCodeInfo();
for (int index : machineCodeInfo.labelIndexes()) {
final MaxBreakpoint breakpoint = vm().breakpointManager().findBreakpoint(machineCodeInfo.instructionLocation(index));
if (breakpoint != null) {
breakpoint.remove();
}
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
/**
* @return an Action that will remove any breakpoints machine code labels.
*/
public final InspectorAction removeMachineCodeLabelBreakpoints(MaxCompilation compilation, String actionTitle) {
return new RemoveMachineCodeLabelBreakpointsAction(compilation, actionTitle);
}
/**
* Action: sets machine code breakpoints at a specified compiled code entry.
*/
final class SetMachineCodeBreakpointAtEntryAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set machine code breakpoint at code entry";
private final MaxCompilation compilation;
SetMachineCodeBreakpointAtEntryAction(MaxCompilation compilation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.compilation = compilation;
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxCodeLocation callEntryLocation = compilation.getCallEntryLocation();
try {
MaxBreakpoint breakpoint = vm().breakpointManager().makeBreakpoint(callEntryLocation);
focus().setBreakpoint(breakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
/**
* @return an interactive Action that sets a machine code breakpoint at code entry.
*/
public final InspectorAction setMachineCodeBreakpointAtEntry(MaxCompilation compilation, String actionTitle) {
return new SetMachineCodeBreakpointAtEntryAction(compilation, actionTitle);
}
/**
* @return an interactive Action that sets a compiled code breakpoint at a method entry
*/
public final InspectorAction setMachineCodeBreakpointAtEntry(MaxCompilation compilation) {
return new SetMachineCodeBreakpointAtEntryAction(compilation, null);
}
/**
* Action: sets machine code breakpoints at code entries to be selected interactively by name.
*/
final class SetMachineCodeBreakpointAtEntriesByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Compiled code...";
SetMachineCodeBreakpointAtEntriesByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor =
ClassActorSearchDialog.show(inspection(), "Class for machine code entry breakpoints...", "Select");
if (teleClassActor != null) {
final List<MaxCompilation> compilations =
MethodCompilationSearchDialog.show(inspection(), teleClassActor, "Compiled Method Entry Breakpoints", "Set Breakpoints", true);
if (compilations != null) {
try {
// There may be multiple compilations of a method in the result.
MaxBreakpoint machineCodeBreakpoint = null;
for (MaxCompilation compilation : compilations) {
machineCodeBreakpoint =
vm().breakpointManager().makeBreakpoint(compilation.getCallEntryLocation());
}
focus().setBreakpoint(machineCodeBreakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final SetMachineCodeBreakpointAtEntriesByNameAction setMachineCodeBreakpointAtEntriesByNameAction =
new SetMachineCodeBreakpointAtEntriesByNameAction(null);
/**
* @return Singleton interactive Action that sets a machine code breakpoint at a method entry to be selected by name.
*/
public final InspectorAction setMachineCodeBreakpointAtEntriesByName() {
return setMachineCodeBreakpointAtEntriesByNameAction;
}
/**
* Action: sets machine code breakpoints at native function entries to be selected interactively by name.
*/
final class SetNativeFunctionBreakpointByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Native function...";
SetNativeFunctionBreakpointByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxNativeLibrary maxNativeLibrary = NativeLibrarySearchDialog.show(inspection(), "Native function library for breakpoints...", "Select");
if (maxNativeLibrary != null) {
final List<MaxNativeFunction> functions = NativeFunctionSearchDialog.show(inspection(), maxNativeLibrary, "Native Function Breakpoints...", "Set Breakpoint", true);
if (functions != null) {
try {
MaxBreakpoint machineCodeBreakpoint = null;
for (MaxNativeFunction nativeFunction : functions) {
try {
machineCodeBreakpoint =
vm().breakpointManager().makeBreakpoint(vm().codeLocations().createMachineCodeLocation(nativeFunction.getCodeStart(), "set machine breakpoint"));
} catch (InvalidCodeAddressException e) {
gui().errorMessage("Unable to set breakpoint, no code @ " + e.getAddressString() + ": " + e.getMessage());
}
}
focus().setBreakpoint(machineCodeBreakpoint);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final SetNativeFunctionBreakpointByNameAction setNativeFunctionBreakpointByNameAction =
new SetNativeFunctionBreakpointByNameAction(null);
/**
* @return Singleton interactive Action that sets a machine code breakpoint at a method entry to be selected by name.
*/
public final InspectorAction setNativeFunctionBreakpointByName() {
return setNativeFunctionBreakpointByNameAction;
}
/**
* Action: sets machine code breakpoint at object initializers of a class specified interactively by name.
*/
final class SetMachineCodeBreakpointAtObjectInitializerAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Object initializers of class...";
SetMachineCodeBreakpointAtObjectInitializerAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final TeleClassActor teleClassActor = ClassActorSearchDialog.show(inspection(), "Add breakpoint in Object Initializers of Class...", "Set Breakpoint");
if (teleClassActor != null) {
final ClassActor classActor = teleClassActor.classActor();
if (classActor.localVirtualMethodActors() != null) {
try {
MaxBreakpoint breakpoint = null;
for (VirtualMethodActor virtualMethodActor : classActor.localVirtualMethodActors()) {
if (virtualMethodActor.name == SymbolTable.INIT) {
final TeleClassMethodActor teleClassMethodActor = vm().findTeleMethodActor(TeleClassMethodActor.class, virtualMethodActor);
if (teleClassMethodActor != null) {
for (MaxCompilation compilation : vm().machineCode().compilations(teleClassMethodActor)) {
final MaxCodeLocation callEntryLocation = compilation.getCallEntryLocation();
breakpoint = vm().breakpointManager().makeBreakpoint(callEntryLocation);
}
}
}
}
if (breakpoint != null) {
focus().setBreakpoint(breakpoint);
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private InspectorAction setMachineCodeBreakpointAtObjectInitializer =
new SetMachineCodeBreakpointAtObjectInitializerAction(null);
/**
* @return an interactive Action that will set a machine code breakpoint at the
* object initializer for a class specified by name.
*/
public final InspectorAction setMachineCodeBreakpointAtObjectInitializer() {
return setMachineCodeBreakpointAtObjectInitializer;
}
/**
* Action: toggle on/off a breakpoint at the bytecode location of the current focus.
*/
class ToggleBytecodeBreakpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Toggle bytecode breakpoint";
ToggleBytecodeBreakpointAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
focus().addListener(new InspectionFocusAdapter() {
@Override
public void codeLocationFocusSet(MaxCodeLocation codeLocation, boolean interactiveForNative) {
refresh(false);
}
});
}
@Override
protected void procedure() {
final MaxCodeLocation codeLocation = focus().codeLocation();
if (codeLocation.hasMethodKey()) {
final MaxBreakpoint breakpoint = vm().breakpointManager().findBreakpoint(codeLocation);
try {
if (breakpoint == null) {
vm().breakpointManager().makeBreakpoint(codeLocation);
} else {
breakpoint.remove();
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && focus().hasCodeLocation() && focus().codeLocation().hasTeleClassMethodActor());
}
}
private InspectorAction toggleBytecodeBreakpoint = new ToggleBytecodeBreakpointAction(null);
/**
* @return an Action that will toggle on/off a breakpoint at the bytecode location of the current focus.
*/
public final InspectorAction toggleBytecodeBreakpoint() {
return toggleBytecodeBreakpoint;
}
/**
* Action: sets a bytecode breakpoint at a specified method entry.
*/
final class SetBytecodeBreakpointAtMethodEntryAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Method on classpath";
private final TeleClassMethodActor teleClassMethodActor;
SetBytecodeBreakpointAtMethodEntryAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
refreshableActions.add(this);
refresh(true);
}
@Override
protected void procedure() {
final MaxCodeLocation location = vm().codeLocations().createBytecodeLocation(teleClassMethodActor, -1, "teleClassMethodActor entry");
try {
vm().breakpointManager().makeBreakpoint(location);
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && teleClassMethodActor.hasCodeAttribute());
}
}
/**
* @return an Action that will set a bytecode breakpoint at a method entry.
*/
public final InspectorAction setBytecodeBreakpointAtMethodEntry(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new SetBytecodeBreakpointAtMethodEntryAction(teleClassMethodActor, actionTitle);
}
/**
* @return an Action that will set a bytecode breakpoint at a method entry.
*/
public final InspectorAction setBytecodeBreakpointAtMethodEntry(TeleClassMethodActor teleClassMethodActor) {
return new SetBytecodeBreakpointAtMethodEntryAction(teleClassMethodActor, null);
}
/**
* Action: sets a bytecode breakpoint at a method entry specified interactively by name.
*/
final class SetBytecodeBreakpointAtMethodEntryByNameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Method on classpath, by name...";
SetBytecodeBreakpointAtMethodEntryByNameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final TypeDescriptor typeDescriptor = TypeSearchDialog.show(inspection(), "Class for bytecode method entry breakpoint...", "Select");
if (typeDescriptor != null) {
final MethodKey methodKey = MethodSearchDialog.show(inspection(), typeDescriptor, "Bytecodes method entry breakpoint", "Set Breakpoint");
if (methodKey != null) {
try {
vm().breakpointManager().makeBreakpoint(vm().codeLocations().createBytecodeLocation(methodKey, "set bytecode breakpoint"));
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final SetBytecodeBreakpointAtMethodEntryByNameAction setBytecodeBreakpointAtMethodEntryByNameAction =
new SetBytecodeBreakpointAtMethodEntryByNameAction(null);
/**
* @return Singleton interactive Action that will set a bytecode breakpoint at a method entry to be selected by name.
*/
public final InspectorAction setBytecodeBreakpointAtMethodEntryByName() {
return setBytecodeBreakpointAtMethodEntryByNameAction;
}
/**
* Action: sets a bytecode breakpoint at a method entry specified interactively by name.
*/
final class SetBytecodeBreakpointAtMethodEntryByKeyAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Method matched by key...";
SetBytecodeBreakpointAtMethodEntryByKeyAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MethodKey methodKey = MethodKeyInputDialog.show(inspection(), "Specify method");
if (methodKey != null) {
try {
vm().breakpointManager().makeBreakpoint(vm().codeLocations().createBytecodeLocation(methodKey, "set bytecode breakpoint"));
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess());
}
}
private final SetBytecodeBreakpointAtMethodEntryByKeyAction setBytecodeBreakpointAtMethodEntryByKeyAction =
new SetBytecodeBreakpointAtMethodEntryByKeyAction(null);
/**
* @return Singleton interactive Action that will set a bytecode breakpoint at a method entry to be selected by name.
*/
public final InspectorAction setBytecodeBreakpointAtMethodEntryByKey() {
return setBytecodeBreakpointAtMethodEntryByKeyAction;
}
/**
* Action: create a memory word watchpoint, interactive if no location specified.
*/
final class SetWordWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch memory word";
private final MaxMemoryRegion memoryRegion;
SetWordWatchpointAction() {
super(inspection(), "Watch memory word at address...");
this.memoryRegion = null;
setEnabled(true);
}
SetWordWatchpointAction(Address address, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.memoryRegion = new MemoryWordRegion(inspection(), address, 1);
setEnabled(vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
@Override
protected void procedure() {
if (memoryRegion != null) {
setWatchpoint(memoryRegion, "");
} else {
final int nBytesInWord = vm().platform().nBytesInWord();
new MemoryRegionInputDialog(inspection(), vm().bootImageStart(), "Watch memory starting at address...", "Watch") {
@Override
public void entered(Address address, long nBytes) {
setWatchpoint(new MemoryWordRegion(inspection(), address, nBytes / nBytesInWord), "User specified region");
}
};
}
}
private void setWatchpoint(MaxMemoryRegion memoryRegion, String description) {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final MaxWatchpoint watchpoint = vm().watchpointManager().createRegionWatchpoint(description, memoryRegion, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && vm().watchpointManager() != null);
}
}
private final SetWordWatchpointAction setWordWatchpointAction = new SetWordWatchpointAction();
/**
* @return Singleton interactive Action that will create a memory word watchpoint in the VM.
*/
public final InspectorAction setWordWatchpoint() {
return setWordWatchpointAction;
}
/**
* Creates an action that will create a memory word watchpoint.
*
* @param address a memory location in the VM
* @return an Action that will set a memory watchpoint at the address.
*/
public final InspectorAction setWordWatchpoint(Address address, String string) {
return new SetWordWatchpointAction(address, string);
}
/**
* Action: create a memory watchpoint, interactive if no location specified.
*/
final class SetRegionWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch memory region";
private static final String DEFAULT_REGION_DESCRIPTION = "";
private final MaxMemoryRegion memoryRegion;
private final String regionDescription;
SetRegionWatchpointAction() {
super(inspection(), "Watch memory region...");
this.memoryRegion = null;
this.regionDescription = null;
setEnabled(true);
}
SetRegionWatchpointAction(MaxMemoryRegion memoryRegion, String actionTitle, String regionDescription) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.memoryRegion = memoryRegion;
this.regionDescription = regionDescription == null ? DEFAULT_REGION_DESCRIPTION : regionDescription;
setEnabled(vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
@Override
protected void procedure() {
if (memoryRegion != null) {
setWatchpoint(memoryRegion, regionDescription);
} else {
// TODO (mlvdv) Generalize AddressInputDialog for a Region
new AddressInputDialog(inspection(), vm().bootImageStart(), "Watch memory...", "Watch") {
@Override
public void entered(Address address) {
setWatchpoint(new FixedMemoryRegion(inspection(), "", address, vm().platform().nBytesInWord()), "User specified region");
}
};
}
}
private void setWatchpoint(MaxMemoryRegion memoryRegion, String description) {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final MaxWatchpoint watchpoint = vm().watchpointManager().createRegionWatchpoint(description, memoryRegion, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess() && vm().watchpointManager() != null);
}
}
private final InspectorAction setRegionWatchpointAction = new SetRegionWatchpointAction();
/**
* @return Singleton interactive Action that will create a memory watchpoint in the VM.
*/
public final InspectorAction setRegionWatchpoint() {
return setRegionWatchpointAction;
}
/**
* Creates an action that will create a memory watchpoint.
*
* @param memoryRegion an area of memory in the VM
* @param actionTitle a name for the action, use default name if null
* @param regionName a description that will be attached to the watchpoint for viewing purposes, default if null.
* @return an Action that will set a memory watchpoint at the address.
*/
public final InspectorAction setRegionWatchpoint(MaxMemoryRegion memoryRegion, String actionTitle, String regionName) {
return new SetRegionWatchpointAction(memoryRegion, actionTitle, regionName);
}
/**
* Action: create an object memory watchpoint.
*/
final class SetObjectWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch object memory";
private final MaxObject object;
private final MaxMemoryRegion memoryRegion;
SetObjectWatchpointAction(MaxObject object, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
this.memoryRegion = object.objectMemoryRegion();
refresh(true);
}
@Override
protected void procedure() {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final String description = "Whole object";
final MaxWatchpoint watchpoint = vm().watchpointManager().createObjectWatchpoint(description, object, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
InspectorWarning.message(inspection(), "Watchpoint creation failed", maxVMBusyException);
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess()
&& vm().watchpointManager() != null
&& vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
}
/**
* Creates an action that will create an object memory watchpoint.
*
* @param object a heap object in the VM
* @param actionTitle a name for the action, use default name if null
* @return an Action that will set an object field watchpoint.
*/
public final InspectorAction setObjectWatchpoint(MaxObject object, String actionTitle) {
return new SetObjectWatchpointAction(object, actionTitle);
}
/**
* Action: create an object field watchpoint.
*/
final class SetFieldWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch object field";
private final MaxObject object;
private final FieldActor fieldActor;
private final MaxMemoryRegion memoryRegion;
SetFieldWatchpointAction(MaxObject object, FieldActor fieldActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
this.fieldActor = fieldActor;
this.memoryRegion = object.fieldMemoryRegion(fieldActor);
refresh(true);
}
@Override
protected void procedure() {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final String description = "Field \"" + fieldActor.name.toString() + "\"";
final MaxWatchpoint watchpoint = vm().watchpointManager().createFieldWatchpoint(description, object, fieldActor, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess()
&& vm().watchpointManager() != null
&& vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
}
/**
* Creates an action that will create an object field watchpoint.
*
* @param object a heap object in the VM
* @param fieldActor description of a field in the class type of the heap object
* @param actionTitle a name for the action, use default name if null
* @return an Action that will set an object field watchpoint.
*/
public final InspectorAction setFieldWatchpoint(MaxObject object, FieldActor fieldActor, String actionTitle) {
return new SetFieldWatchpointAction(object, fieldActor, actionTitle);
}
/**
* Action: create an object field watchpoint.
*/
final class SetArrayElementWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch array element";
private final MaxObject object;
private final Kind elementKind;
private final int arrayOffsetFromOrigin;
private final int index;
private final String indexPrefix;
private final MaxMemoryRegion memoryRegion;
SetArrayElementWatchpointAction(MaxObject object, Kind elementKind, int arrayOffsetFromOrigin, int index, String indexPrefix, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
this.elementKind = elementKind;
this.arrayOffsetFromOrigin = arrayOffsetFromOrigin;
this.index = index;
this.indexPrefix = indexPrefix;
final Pointer address = object.origin().plus(arrayOffsetFromOrigin + (index * elementKind.width.numberOfBytes));
this.memoryRegion = new FixedMemoryRegion(inspection(), "", address, elementKind.width.numberOfBytes);
refresh(true);
}
@Override
protected void procedure() {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final String description = "Element " + indexPrefix + "[" + Integer.toString(index) + "]";
final MaxWatchpoint watchpoint
= vm().watchpointManager().createArrayElementWatchpoint(description, object, elementKind, arrayOffsetFromOrigin, index, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess()
&& vm().watchpointManager() != null
&& vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
}
/**
* Creates an action that will create an array element watchpoint.
*
* @param object a heap object in the VM
* @param elementKind type category of the array elements
* @param arrayOffsetFromOrigin offset in bytes from the object origin of element 0
* @param index index into the array
* @param indexPrefix text to prepend to the displayed name(index) of each element.
* @param actionTitle a name for the action, use default name if null
* @return an Action that will set an array element watchpoint.
*/
public final InspectorAction setArrayElementWatchpoint(MaxObject object, Kind elementKind, int arrayOffsetFromOrigin, int index, String indexPrefix, String actionTitle) {
return new SetArrayElementWatchpointAction(object, elementKind, arrayOffsetFromOrigin, index, indexPrefix, actionTitle);
}
/**
* Action: create an object header field watchpoint.
*/
final class SetHeaderWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch object header field";
private final MaxObject object;
private final HeaderField headerField;
private final MaxMemoryRegion memoryRegion;
SetHeaderWatchpointAction(MaxObject object, HeaderField headerField, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.object = object;
this.headerField = headerField;
this.memoryRegion = object.headerMemoryRegion(headerField);
refresh(true);
}
@Override
protected void procedure() {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final String description = "Field \"" + headerField.name + "\"";
final MaxWatchpoint watchpoint = vm().watchpointManager().createHeaderWatchpoint(description, object, headerField, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess()
&& vm().watchpointManager() != null
&& vm().watchpointManager().findWatchpoints(memoryRegion).isEmpty());
}
}
/**
* Creates an action that will create an object header field watchpoint.
*
* @param object a heap object in the VM
* @param headerField identification of an object header field
* @param actionTitle a name for the action, use default name if null
* @return an Action that will set an object header watchpoint
*/
public final InspectorAction setHeaderWatchpoint(MaxObject object, HeaderField headerField, String actionTitle) {
return new SetHeaderWatchpointAction(object, headerField, actionTitle);
}
/**
* Action: create an object field watchpoint.
*/
final class SetThreadLocalWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Watch thread local variable";
private final MaxThreadLocalVariable threadLocalVariable;
SetThreadLocalWatchpointAction(MaxThreadLocalVariable threadLocalVariable, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.threadLocalVariable = threadLocalVariable;
refresh(true);
}
@Override
protected void procedure() {
final WatchpointsViewPreferences prefs = WatchpointsViewPreferences.globalPreferences(inspection());
try {
final String description = "Thread local variable\"" + threadLocalVariable.variableName()
+ "\" (" + inspection().nameDisplay().shortName(threadLocalVariable.thread()) + ","
+ threadLocalVariable.safepointState().toString() + ")";
final MaxWatchpoint watchpoint = vm().watchpointManager().createVmThreadLocalWatchpoint(description, threadLocalVariable, prefs.settings());
if (watchpoint == null) {
gui().errorMessage("Watchpoint creation failed");
} else {
focus().setWatchpoint(watchpoint);
}
} catch (MaxTooManyWatchpointsException tooManyWatchpointsException) {
gui().errorMessage(tooManyWatchpointsException.getMessage());
} catch (MaxDuplicateWatchpointException duplicateWatchpointException) {
gui().errorMessage(duplicateWatchpointException.getMessage());
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(inspection().hasProcess()
&& vm().watchpointManager() != null
&& vm().watchpointManager().findWatchpoints(threadLocalVariable.memoryRegion()).isEmpty());
}
}
/**
* Creates an action that will create a thread local variable watchpoint.
*
* @param threadLocalVariable a thread local variable
* @param actionTitle a name for the action, use default name if null
* @return an action that will create a thread local variable watchpoint
*/
public final InspectorAction setThreadLocalWatchpoint(MaxThreadLocalVariable threadLocalVariable, String actionTitle) {
return new SetThreadLocalWatchpointAction(threadLocalVariable, actionTitle);
}
/**
* Action: remove a specified memory watchpoint.
*/
final class RemoveWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove memory watchpoint";
private final MaxWatchpoint watchpoint;
RemoveWatchpointAction(MaxWatchpoint watchpoint, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.watchpoint = watchpoint;
}
@Override
protected void procedure() {
try {
if (watchpoint.remove()) {
focus().setWatchpoint(null);
} else {
gui().errorMessage("Watchpoint removal failed");
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
/**
* Creates an action that will remove a watchpoint.
*
* @param watchpoint an existing VM memory watchpoint
* @param actionTitle a title for the action, use default name if null
* @return an Action that will remove a watchpoint, if present at memory location.
*/
public final InspectorAction removeWatchpoint(MaxWatchpoint watchpoint, String actionTitle) {
return new RemoveWatchpointAction(watchpoint, actionTitle);
}
/**
* Action: removes the watchpoint from the VM that is currently selected.
*/
final class RemoveSelectedWatchpointAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove selected watchpoint";
RemoveSelectedWatchpointAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
focus().addListener(new InspectionFocusAdapter() {
@Override
public void watchpointFocusSet(MaxWatchpoint oldWatchpoint, MaxWatchpoint watchpoint) {
refresh(false);
}
});
refresh(false);
}
@Override
protected void procedure() {
final MaxWatchpoint watchpoint = focus().watchpoint();
try {
if (watchpoint != null) {
if (watchpoint.remove()) {
focus().setWatchpoint(null);
} else {
gui().errorMessage("Watchpoint removal failed");
}
} else {
gui().errorMessage("No watchpoint selected");
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasWatchpoint());
}
}
private InspectorAction removeSelectedWatchpoint = new RemoveSelectedWatchpointAction(null);
/**
* @return an Action that will remove the currently selected breakpoint, if any.
*/
public final InspectorAction removeSelectedWatchpoint() {
return removeSelectedWatchpoint;
}
/**
* Action: removes a set of existing watchpoints in the VM.
*/
final class RemoveWatchpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove watchpoints";
private final List<MaxWatchpoint> watchpoints;
RemoveWatchpointsAction(List<MaxWatchpoint> watchpoints, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.watchpoints = watchpoints;
}
@Override
protected void procedure() {
final MaxWatchpoint focusWatchpoint = focus().watchpoint();
for (MaxWatchpoint watchpoint : watchpoints) {
if (focusWatchpoint == watchpoint) {
focus().setWatchpoint(null);
}
try {
if (!watchpoint.remove()) {
gui().errorMessage("Failed to remove watchpoint" + watchpoint);
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(watchpoints.size() > 0);
}
}
/**
* @return an Action that will remove all watchpoints in the VM.
*/
public final InspectorAction removeWatchpoints(List<MaxWatchpoint> watchpoints, String actionTitle) {
return new RemoveWatchpointsAction(watchpoints, actionTitle);
}
/**
* Action: removes all existing watchpoints in the VM.
*/
final class RemoveAllWatchpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Remove all watchpoints";
RemoveAllWatchpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
inspection().addInspectionListener(new InspectionListenerAdapter() {
@Override
public void watchpointSetChanged() {
refresh(true);
}
});
}
@Override
protected void procedure() {
focus().setWatchpoint(null);
for (MaxWatchpoint watchpoint : vm().watchpointManager().watchpoints()) {
try {
if (!watchpoint.remove()) {
gui().errorMessage("Failed to remove watchpoint" + watchpoint);
}
} catch (MaxVMBusyException maxVMBusyException) {
inspection().announceVMBusyFailure(name());
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(vm().watchpointManager() != null && vm().watchpointManager().watchpoints().size() > 0);
}
}
private InspectorAction removeAllWatchpoints = new RemoveAllWatchpointsAction(null);
final class SetMarkBitAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Set Mark bit";
SetMarkBitAction() {
super(inspection(), "Mark word at address...");
refreshableActions.add(this);
}
@Override
protected void procedure() {
new AddressInputDialog(inspection(), Address.zero(), "Set Mark Bit for word at address...", "Set Bit") {
@Override
public void entered(Address address) {
MaxMarkBitmap markBitmap = vm().heap().markBitmap();
assert markBitmap != null;
if (!markBitmap.isCovered(address)) {
gui().errorMessage("Address " + address + " is not covered with a mark bit");
return;
}
if (!address.isWordAligned()) {
gui().errorMessage("Address " + address + " is not word aligned");
}
final int bitIndexOf = vm().heap().markBitmap().getBitIndexOf(address);
if (markBitmap.isBitSet(bitIndexOf)) {
gui().informationMessage("Mark bit already set for address=" + address.to0xHexString());
} else {
markBitmap.setBit(bitIndexOf);
}
}
};
}
@Override
public void refresh(boolean force) {
setEnabled(vm().heap().markBitmap() != null);
}
}
private InspectorAction setMarkBitAtAddressAction = new SetMarkBitAction();
/**
* @return an Action that will remove all watchpoints in the VM.
*/
public final InspectorAction removeAllWatchpoints() {
return removeAllWatchpoints;
}
/**
* Action: pause the running VM.
*/
final class DebugPauseAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Pause process";
DebugPauseAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
try {
vm().pauseVM();
} catch (Exception exception) {
gui().errorMessage("Pause could not be initiated", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMRunning());
}
}
private final InspectorAction debugPauseAction = new DebugPauseAction(null);
/**
* @return Singleton Action that will pause execution of theVM.
*/
public final InspectorAction debugPause() {
return debugPauseAction;
}
/**
* Action: resumes the running VM.
*/
final class DebugResumeAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Resume";
DebugResumeAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
try {
vm().resume(false, true);
} catch (Exception exception) {
gui().errorMessage("Run to instruction could not be performed.", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugResumeAction = new DebugResumeAction(null);
/**
* @return Singleton Action that will resume full execution of theVM.
*/
public final InspectorAction debugResume() {
return debugResumeAction;
}
/**
* Action: advance the currently selected thread until it returns from its current frame in the VM,
* ignoring breakpoints.
*/
final class DebugReturnFromFrameAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Return from frame (ignoring breakpoints)";
DebugReturnFromFrameAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
try {
vm().returnFromFrame(focus().thread(), false, false);
// TODO (mlvdv) too broad a catch; narrow this
} catch (Exception exception) {
gui().errorMessage("Return from frame (ignoring breakpoints) could not be performed.", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugReturnFromFrameAction = new DebugReturnFromFrameAction(null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the first instruction after returning
* from the current frame of the currently selected thread
*/
public final InspectorAction debugReturnFromFrame() {
return debugReturnFromFrameAction;
}
/**
* Action: advance the currently selected thread until it returns from its current frame
* or hits a breakpoint in the VM.
*/
final class DebugReturnFromFrameWithBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Return from frame";
DebugReturnFromFrameWithBreakpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
public void procedure() {
try {
vm().returnFromFrame(focus().thread(), false, true);
} catch (Exception exception) {
gui().errorMessage("Return from frame could not be performed.", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugReturnFromFrameWithBreakpointsAction = new DebugReturnFromFrameWithBreakpointsAction(null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the first instruction after returning
* from the current frame of the currently selected thread, or at a breakpoint, whichever comes first.
*/
public final InspectorAction debugReturnFromFrameWithBreakpoints() {
return debugReturnFromFrameWithBreakpointsAction;
}
/**
* Action: advance the currently selected thread in the VM until it reaches the specified instruction, or
* if none specified, then the currently selected instruction, ignoring breakpoints.
*/
final class DebugRunToInstructionAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Run to selected instruction (ignoring breakpoints)";
private final MaxCodeLocation codeLocation;
DebugRunToInstructionAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.codeLocation = codeLocation;
refreshableActions.add(this);
refresh(true);
}
@Override
protected void procedure() {
final MaxCodeLocation machineCodeLocation = (codeLocation != null) ? codeLocation : focus().codeLocation();
if (machineCodeLocation.address().isNotZero()) {
try {
vm().runToInstruction(machineCodeLocation, false, false);
} catch (Exception exception) {
InspectorError.unexpected("Run to instruction (ignoring breakpoints) could not be performed.", exception);
}
} else {
gui().errorMessage("No instruction selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && focus().hasCodeLocation() && inspection().isVMReady());
}
}
private final InspectorAction debugRunToSelectedInstructionAction = new DebugRunToInstructionAction(null, null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the the currently
* selected instruction, ignoring breakpoints.
*/
public final InspectorAction debugRunToSelectedInstruction() {
return debugRunToSelectedInstructionAction;
}
/**
* @param codeLocation a code location in the VM
* @param actionTitle string that describes the action
* @return an Action that will resume execution in the VM, stopping at the specified
* code location, ignoring breakpoints.
*/
public final InspectorAction debugRunToInstruction(MaxCodeLocation codeLocation, String actionTitle) {
return new DebugRunToInstructionAction(codeLocation, actionTitle);
}
/**
* Action: advance the currently selected thread in the VM until it reaches the specified code location
* (or the currently selected instruction if none specified) or a breakpoint, whichever comes first.
*/
final class DebugRunToInstructionWithBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Run to selected instruction";
final MaxCodeLocation codeLocation;
DebugRunToInstructionWithBreakpointsAction(MaxCodeLocation codeLocation, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.codeLocation = codeLocation;
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxCodeLocation machineCodeLocation = (codeLocation != null) ? codeLocation : focus().codeLocation();
if (machineCodeLocation != null && machineCodeLocation.hasAddress()) {
try {
vm().runToInstruction(machineCodeLocation, false, true);
// TODO (mlvdv) narrow the catch
} catch (Exception exception) {
InspectorError.unexpected("Run to selection instruction could not be performed.", exception);
}
} else {
gui().errorMessage("No instruction selected");
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && focus().hasCodeLocation() && inspection().isVMReady());
}
}
private final InspectorAction debugRunToSelectedInstructionWithBreakpointsAction = new DebugRunToInstructionWithBreakpointsAction(null, null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the selected instruction
* or a breakpoint, whichever comes first..
*/
public final InspectorAction debugRunToSelectedInstructionWithBreakpoints() {
return debugRunToSelectedInstructionWithBreakpointsAction;
}
/**
* @param codeLocation a code location in the VM
* @param actionTitle string that identifies the action
* @return an Action that will resume execution in the VM, stopping at the specified instruction
* or a breakpoint, whichever comes first..
*/
public final InspectorAction debugRunToInstructionWithBreakpoints(MaxCodeLocation codeLocation, String actionTitle) {
return new DebugRunToInstructionWithBreakpointsAction(codeLocation, actionTitle);
}
/**
* Action: advance the currently selected thread in the VM until it reaches the next call instruction,
* ignoring breakpoints; fails if there is no known call in the method containing the IP.
*/
final class DebugRunToNextCallAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Run to next call instruction (ignoring breakpoints)";
DebugRunToNextCallAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxCodeLocation maxCodeLocation = focus().codeLocation();
if (maxCodeLocation != null && maxCodeLocation.hasAddress()) {
final MaxCompilation compilation = vm().machineCode().findCompilation(maxCodeLocation.address());
if (compilation != null) {
final MaxMachineCodeInfo machineCodeInfo = compilation.getMachineCodeInfo();
final int instructionIndex = machineCodeInfo.findInstructionIndex(maxCodeLocation.address());
for (int index = instructionIndex + 1; index < machineCodeInfo.length(); index++) {
if (machineCodeInfo.isCall(index)) {
try {
vm().runToInstruction(machineCodeInfo.instructionLocation(index), false, false);
} catch (Exception exception) {
InspectorError.unexpected("Run to next call instruction (ignoring breakpoints) could not be performed.", exception);
}
break;
}
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && focus().hasCodeLocation() && inspection().isVMReady());
}
}
private final InspectorAction debugRunToNextCallAction = new DebugRunToNextCallAction(null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the next call instruction,
* ignoring breakpoints; fails if there is no known call in the method containing the IP.
*/
public final InspectorAction debugRunToNextCall() {
return debugRunToNextCallAction;
}
/**
* Action: advance the currently selected thread in the VM until it reaches the selected instruction
* or a breakpoint.
*/
final class DebugRunToNextCallWithBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Run to next call instruction";
DebugRunToNextCallWithBreakpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxCodeLocation maxCodeLocation = focus().codeLocation();
if (maxCodeLocation != null && maxCodeLocation.hasAddress()) {
final MaxCompilation compilation = vm().machineCode().findCompilation(maxCodeLocation.address());
if (compilation != null) {
final MaxMachineCodeInfo machineCodeInfo = compilation.getMachineCodeInfo();
final int instructionIndex = machineCodeInfo.findInstructionIndex(maxCodeLocation.address());
for (int index = instructionIndex + 1; index < machineCodeInfo.length(); index++) {
if (machineCodeInfo.isCall(index)) {
try {
vm().runToInstruction(machineCodeInfo.instructionLocation(index), false, true);
} catch (Exception exception) {
InspectorError.unexpected("Run to next call instruction could not be performed.", exception);
}
break;
}
}
}
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && focus().hasCodeLocation() && inspection().isVMReady());
}
}
private final InspectorAction debugNextRunToCallWithBreakpointsAction = new DebugRunToNextCallWithBreakpointsAction(null);
/**
* @return Singleton Action that will resume execution in the VM, stopping at the first instruction after returning
* from the current frame of the currently selected thread, or at a breakpoint, whichever comes first.
*/
public final InspectorAction debugRunToNextCallWithBreakpoints() {
return debugNextRunToCallWithBreakpointsAction;
}
/**
* Action: advances the currently selected thread one step in the VM.
*/
class DebugSingleStepAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Single instruction step";
DebugSingleStepAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
public void procedure() {
final MaxThread thread = focus().thread();
try {
vm().singleStepThread(thread, false);
} catch (Exception exception) {
gui().errorMessage("Couldn't single step", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugSingleStepAction = new DebugSingleStepAction(null);
/**
* @return Singleton action that will single step the currently selected thread in the VM
*/
public final InspectorAction debugSingleStep() {
return debugSingleStepAction;
}
/**
* Action: resumes execution of the VM, stopping at the one immediately after the current
* instruction of the currently selected thread.
*/
final class DebugStepOverAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Step over (ignoring breakpoints)";
DebugStepOverAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
try {
vm().stepOver(thread, false, false);
} catch (Exception exception) {
gui().errorMessage("Step over (ignoring breakpoints) could not be performed.", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugStepOverAction = new DebugStepOverAction(null);
/**
* @return Singleton Action that will resume execution of the VM, stopping at the one immediately after the current
* instruction of the currently selected thread
*/
public final InspectorAction debugStepOver() {
return debugStepOverAction;
}
/**
* Action: resumes execution of the VM, stopping at the one immediately after the current
* instruction of the currently selected thread or at a breakpoint.
*/
final class DebugStepOverWithBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Step over";
DebugStepOverWithBreakpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
refreshableActions.add(this);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
try {
vm().stepOver(thread, false, true);
} catch (Exception exception) {
gui().errorMessage("Step over could not be performed.", exception.toString());
}
}
@Override
public void refresh(boolean force) {
setEnabled(focus().hasThread() && inspection().isVMReady());
}
}
private final InspectorAction debugStepOverWithBreakpointsAction = new DebugStepOverWithBreakpointsAction(null);
/**
* @return Singleton Action that will resume execution of the VM, stopping at the one immediately after the current
* instruction of the currently selected thread
*/
public final InspectorAction debugStepOverWithBreakpoints() {
return debugStepOverWithBreakpointsAction;
}
/**
* Action: interactively invoke a method.
*/
private class DebugInvokeMethodAction extends InspectorAction {
private static final String DEFAULT_TITLE = "Invoke method";
private final TeleClassMethodActor teleClassMethodActor;
public DebugInvokeMethodAction(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
this.teleClassMethodActor = teleClassMethodActor;
}
@Override
public void procedure() {
ClassMethodActor classMethodActor = teleClassMethodActor.classMethodActor();
ReferenceValue receiver = null;
if (classMethodActor instanceof VirtualMethodActor) {
final String input = gui().inputDialog("Argument 0 (receiver, must be a reference to a " + classMethodActor.holder() + " or subclass, origin address in hex):", "");
if (input == null) {
// User clicked cancel.
return;
}
receiver = vm().createReferenceValue(vm().makeReference(Pointer.fromLong(new BigInteger(input, 16).longValue())));
final ClassActor dynamicClass = receiver.getClassActor();
classMethodActor = dynamicClass.findClassMethodActor(classMethodActor.name, classMethodActor.descriptor());
}
final Value[] arguments = MethodArgsDialog.getArgs(inspection(), classMethodActor, receiver);
if (arguments == null) {
// User clicked cancel.
return;
}
try {
final Value returnValue = vm().interpretMethod(classMethodActor, arguments);
gui().informationMessage("Method " + classMethodActor.name + " returned " + returnValue.toString());
} catch (InvocationTargetException e) {
InspectorError.unexpected("Interpreter failure", e);
}
}
}
/**
* Creates an action that lets the user invoke a method interactively.
*
* @param teleClassMethodActor representation of a method in the VM
* @param actionTitle name of the action for display on menu or button
* @return an interactive action for method invocation
*/
public InspectorAction debugInvokeMethod(TeleClassMethodActor teleClassMethodActor, String actionTitle) {
return new DebugInvokeMethodAction(teleClassMethodActor, actionTitle);
}
/**
* Creates an action that lets the user invoke a method interactively.
*
* @param teleClassMethodActor representation of a method in the VM
* @return an interactive action for method invocation
*/
public InspectorAction debugInvokeMethod(TeleClassMethodActor teleClassMethodActor) {
return new DebugInvokeMethodAction(teleClassMethodActor, null);
}
/**
* Action: lists to the console this history of the VM state.
*/
final class ListVMStateHistoryAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List VM state history";
ListVMStateHistoryAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().state().writeSummary(System.out);
}
}
private InspectorAction listVMStateHistory = new ListVMStateHistoryAction(null);
/**
* @return an Action that will list to the console the history of the VM state
*/
public final InspectorAction listVMStateHistory() {
return listVMStateHistory;
}
/**
* Action: lists to the console all existing threads.
*/
final class ListThreadsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List all threads";
ListThreadsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().threadManager().writeSummary(System.out);
}
}
private InspectorAction listThreads = new ListThreadsAction(null);
/**
* @return an Action that will list to the console a description of every thread.
*/
public final InspectorAction listThreads() {
return listThreads;
}
/**
* Action: lists to the console the stack frames in the currently focused thread.
*/
final class ListStackFrames extends InspectorAction {
private static final String DEFAULT_TITLE = "List current thread's stack";
ListStackFrames(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
final MaxThread thread = focus().thread();
if (thread != null) {
thread.stack().writeSummary(System.out);
}
}
}
private InspectorAction listStackFrames = new ListStackFrames(null);
/**
* @return an Action that will list to the console the history of the VM state
*/
public final InspectorAction listStackFrames() {
return listStackFrames;
}
/**
* Action: lists to the console all method compilations and native functions.
*/
final class ListMachineCodeAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List compilations & native functions";
ListMachineCodeAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().machineCode().writeSummary(System.out);
}
}
private InspectorAction listMachineCode = new ListMachineCodeAction(null);
/**
* @return an Action that will list to the console the entries in the {@link MaxCodeCache}.
*/
public final InspectorAction listMachineCode() {
return listMachineCode;
}
/**
* Action: lists all method compilations and native functions to an interactively specified file.
*/
final class ListMachineCodeToFileAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List compilations & native functions to a file...";
ListMachineCodeToFileAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
//Create a file chooser
final JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
fileChooser.setDialogTitle("Save machine code summary to file:");
final int returnVal = fileChooser.showSaveDialog(gui().frame());
if (returnVal != JFileChooser.APPROVE_OPTION) {
return;
}
final File file = fileChooser.getSelectedFile();
if (file.exists() && !gui().yesNoDialog("File " + file + "exists. Overwrite?\n")) {
return;
}
try {
final PrintStream printStream = new PrintStream(new FileOutputStream(file, false));
vm().machineCode().writeSummary(printStream);
} catch (FileNotFoundException fileNotFoundException) {
gui().errorMessage("Unable to open " + file + " for writing:" + fileNotFoundException);
}
}
}
private InspectorAction listMachineCodeToFile = new ListMachineCodeToFileAction(null);
/**
* @return an interactive Action that will list to a specified file the entries in the {@link MaxCodeCache}.
*/
public final InspectorAction listMachineCodeToFile() {
return listMachineCodeToFile;
}
/**
* Action: lists to the console all existing breakpoints.
*/
final class ListBreakpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List all breakpoints";
ListBreakpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().breakpointManager().writeSummary(System.out);
}
}
private InspectorAction listBreakpoints = new ListBreakpointsAction(null);
/**
* @return an Action that will list to the console a summary of breakpoints in the VM.
*/
public final InspectorAction listBreakpoints() {
return listBreakpoints;
}
/**
* Action: lists to the console all existing breakpoints.
*/
final class ListInspectableMethodsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List inspectable methods for menu";
ListInspectableMethodsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
System.out.println("Inspectable Methods for menu:");
for (MaxCodeLocation codeLocation : vm().inspectableMethods()) {
codeLocation.hasAddress();
System.out.println("\t" + codeLocation.description() + ", " + codeLocation.toString());
}
}
}
private InspectorAction listInspectableMethods = new ListInspectableMethodsAction(null);
/**
* @return an Action that will list to the console a summary of breakpoints in the VM.
*/
public final InspectorAction listInspectableMethods() {
return listInspectableMethods;
}
/**
* Action: lists to the console all existing watchpoints.
*/
final class ListWatchpointsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List all watchpoints";
ListWatchpointsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
vm().watchpointManager().writeSummary(System.out);
}
}
private InspectorAction listWatchpoints = new ListWatchpointsAction(null);
/**
* @return an Action that will list to the console a summary of watchpoints in the VM.
*/
public final InspectorAction listWatchpoints() {
return listWatchpoints;
}
/**
* Action: lists to the console current settings.
*/
final class ListSettingsAction extends InspectorAction {
private static final String DEFAULT_TITLE = "List all settings";
ListSettingsAction(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
@Override
protected void procedure() {
inspection().settings().writeSummary(System.out);
}
}
private InspectorAction listSettings = new ListSettingsAction(null);
/**
* @return an Action that will list to the console a summary of current settings
* in the inspection session.
*/
public final InspectorAction listSettings() {
return listSettings;
}
/**
* Action: execute a static method on a value.
*/
class InvokeHostMethod extends InspectorAction {
private static final String DEFAULT_TITLE = "Invoke a host method";
InvokeHostMethod(String actionTitle) {
super(inspection(), actionTitle == null ? DEFAULT_TITLE : actionTitle);
}
private Method getMethod(MethodKey methodKey) {
String className = methodKey.holder().toJavaString();
Class<?> klass = Classes.forName(className);
Class<?>[] parameterTypes = methodKey.signature().resolveParameterTypes(ClassLoader.getSystemClassLoader());
try {
return klass.getDeclaredMethod(methodKey.name().string, parameterTypes);
} catch (NoSuchMethodException ex) {
gui().errorMessage("no such method");
return null;
}
}
@Override
protected void procedure() {
final TypeDescriptor typeDescriptor = TypeSearchDialog.show(inspection(), "Class for method invocation...", "Select");
if (typeDescriptor != null) {
final MethodKey methodKey = MethodSearchDialog.show(inspection(), typeDescriptor, "Method for invocation", "Invoke");
if (methodKey != null) {
Method method = getMethod(methodKey);
Kind[] parameterKinds = methodKey.signature().copyParameterKinds(null, 0);
invoke(method, parameterKinds);
// remember it as new menu item
String menuName = "Invoke " + method.getName();
InspectorMenu debugMenu = gui().getMainMenuBar().debugMenu();
for (int i = 0; i < debugMenu.getComponentCount(); i++) {
if (debugMenu.getComponent(i).getName().equals(menuName)) {
return;
}
}
debugMenu.add(new ExecuteSpecificHostMethod(menuName, method, parameterKinds));
}
}
}
protected void invoke(Method method, Kind[] parameterKinds) {
final Value[] arguments = MethodArgsDialog.getArgs(inspection(), parameterKinds, null);
if (arguments == null) {
// User clicked cancel.
return;
}
Object[] objArgs = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
Value value = arguments[i];
Kind kind = value.kind();
if (kind == Kind.LONG) {
objArgs[i] = value.asLong();
} else if (kind == Kind.INT) {
objArgs[i] = value.asInt();
} else {
gui().errorMessage("unsupported argument type");
}
}
try {
Object returnValue = method.invoke(null, objArgs);
views().activateSingletonView(ViewKind.INVOKE_METHOD_LOG);
InvokeMethodLogView.getInvokeMethodLogView().appendText(returnValue.toString());
} catch (Exception e) {
gui().informationMessage("Method " + method.getName() + " threw " + e.getMessage());
}
}
}
private InspectorAction invokeHostMethod = new InvokeHostMethod(null);
public final InspectorAction invokeHostMethod() {
return invokeHostMethod;
}
private class ExecuteSpecificHostMethod extends InvokeHostMethod {
private final Method method;
private final Kind[] parameterKinds;
ExecuteSpecificHostMethod(String actionTitle, Method method, Kind[] parameterKinds) {
super(actionTitle);
this.method = method;
this.parameterKinds = parameterKinds;
}
@Override
protected void procedure() {
invoke(method, parameterKinds);
}
}
/**
* @return menu items for memory-related actions that are independent of context
*/
public InspectorMenuItems genericMemoryMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
menu.add(viewMemoryAllocationsMenu());
menu.add(views().memory().viewMenu());
if (vm().heap().providesHeapRegionInfo()) {
menu.add(viewHeapRegionInfoMenu());
}
menu.add(views().memoryBytes().viewMenu());
if (vm().heap().hasMarkBitmap()) {
menu.add(markBitmapMenu());
}
}
};
}
public JMenu markBitmapMenu() {
final JMenu menu = new JMenu("Mark Bitmap");
menu.add(setMarkBitAtAddressAction);
return menu;
}
/**
* @return menu items for code-related actions that are independent of context
*/
public InspectorMenuItems genericCodeMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
menu.add(actions().viewMethodCodeAtSelection());
menu.add(actions().viewMethodCodeAtIP());
menu.add(actions().viewMethodMachineCode());
final JMenu byNameSub = new JMenu("View code by name");
byNameSub.add(actions().viewMethodBytecodeByName());
byNameSub.add(actions().viewMethodCompilationByName());
byNameSub.add(actions().viewNativeFunctionByName());
menu.add(byNameSub);
menu.add(actions().viewMachineCodeByAddress());
final JMenu bootMethodSub = new JMenu("View boot image method code");
bootMethodSub.add(actions().viewRunMethodCodeInBootImage());
bootMethodSub.add(actions().viewThreadRunMethodCodeInBootImage());
menu.add(bootMethodSub);
}
};
}
/**
* @return menu items for breakpoint-related actions that are independent of context
*/
public InspectorMenuItems genericBreakpointMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
final InspectorMenu builtinBreakpointsMenu = new BuiltinBreakpointsMenu("Break at builtin");
menu.add(builtinBreakpointsMenu);
final InspectorMenu methodEntryBreakpoints = new InspectorMenu("Break at method entry");
methodEntryBreakpoints.add(actions().setMachineCodeBreakpointAtEntriesByName());
methodEntryBreakpoints.add(actions().setBytecodeBreakpointAtMethodEntryByName());
methodEntryBreakpoints.add(actions().setBytecodeBreakpointAtMethodEntryByKey());
menu.add(methodEntryBreakpoints);
final InspectorMenu breakAt = new InspectorMenu("Break at machine code");
breakAt.add(actions().setMachineCodeBreakpointAtAddress());
breakAt.add(actions().setNativeFunctionBreakpointByName());
breakAt.add(actions().setMachineCodeBreakpointAtObjectInitializer());
menu.add(breakAt);
final InspectorMenu toggle = new InspectorMenu("Toggle breakpoint");
toggle.add(actions().toggleMachineCodeBreakpoint());
menu.add(toggle);
menu.add(actions().removeAllBreakpoints());
}
};
}
/**
* @return menu items for watchpoint-related actions that are independent of context
*/
public InspectorMenuItems genericWatchpointMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
menu.add(actions().setWordWatchpoint());
menu.add(actions().removeAllWatchpoints());
}
};
}
/**
* @return menu items for object-related actions that are independent of context
*/
public InspectorMenuItems genericObjectMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
final JMenu methodActorMenu = new JMenu("View method actor");
methodActorMenu.add(viewMethodActorByName());
menu.add(methodActorMenu);
final JMenu classActorMenu = new JMenu("View class actor");
classActorMenu.add(viewClassActorByName());
classActorMenu.add(viewClassActorByHexId());
classActorMenu.add(viewClassActorByDecimalId());
menu.add(classActorMenu);
final JMenu classStaticsMenu = new JMenu("View class statics");
classStaticsMenu.add(viewStaticTupleByName());
menu.add(classStaticsMenu);
final JMenu classHubsMenu = new JMenu("View class hubs");
classHubsMenu.add(viewDynamicHubByName());
classHubsMenu.add(viewStaticHubByName());
menu.add(classHubsMenu);
menu.add(viewSingletonMenu());
menu.add(views().objects().viewMenu());
}
};
}
/**
* @return menu items for view-related actions that are independent of context
*/
public InspectorMenuItems genericViewMenuItems() {
return new AbstractInspectorMenuItems(inspection()) {
public void addTo(InspectorMenu menu) {
menu.add(views().activateSingletonViewAction(ViewKind.ALLOCATIONS));
menu.add(views().activateSingletonViewAction(ViewKind.BOOT_IMAGE));
menu.add(views().activateSingletonViewAction(ViewKind.BREAKPOINTS));
menu.add(views().activateSingletonViewAction(ViewKind.CARD_TABLE));
menu.add(views().activateSingletonViewAction(ViewKind.DEBUG_INFO));
menu.add(views().activateSingletonViewAction(ViewKind.MARK_BITMAP));
menu.add(views().memory().viewMenu());
menu.add(views().memoryBytes().viewMenu());
menu.add(views().activateSingletonViewAction(ViewKind.METHODS));
menu.add(views().activateSingletonViewAction(ViewKind.NOTEPAD));
menu.add(views().objects().viewMenu());
menu.add(views().activateSingletonViewAction(ViewKind.REGISTERS));
menu.add(views().activateSingletonViewAction(ViewKind.STACK));
menu.add(views().activateSingletonViewAction(ViewKind.STACK_FRAME));
menu.add(views().activateSingletonViewAction(ViewKind.THREADS));
menu.add(views().activateSingletonViewAction(ViewKind.THREAD_LOCALS));
menu.add(views().activateSingletonViewAction(ViewKind.WATCHPOINTS));
menu.add(views().activateSingletonViewAction(ViewKind.VMLOG));
menu.add(views().activateSingletonViewAction(ViewKind.INVOKE_METHOD_LOG));
}
};
}
}