/*
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.ins.constant;
import java.awt.event.*;
import com.sun.max.ins.*;
import com.sun.max.ins.gui.*;
import com.sun.max.ins.method.*;
import com.sun.max.ins.util.*;
import com.sun.max.tele.*;
import com.sun.max.tele.data.*;
import com.sun.max.tele.debug.*;
import com.sun.max.tele.object.*;
import com.sun.max.tele.reference.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.classfile.constant.FieldRefConstant.FieldRefKey;
import com.sun.max.vm.type.*;
/**
* A label for displaying a {@link PoolConstant} in the VM that is a reference.
* For literal constants, the labels rely on the local counterpart to the remote one.
* For resolvable constants, an attempt is made to read the remote version in order
* to determine if resolved or not.
*/
public abstract class PoolConstantLabel extends InspectorLabel {
// TODO (mlvdv) PoolConstantLabel, only one mode implemented so far; refactor when more modes added
public enum Mode {
JAVAP,
TERSE
}
private Mode mode;
protected final Mode mode() {
return mode;
}
private final int index;
/**
* Surrogate for the {@link ConstantPool} in the VM.
* Might be null, and might be unreachable.
*/
private final TeleConstantPool teleConstantPool;
private TelePoolConstant telePoolConstant;
protected final TelePoolConstant telePoolConstant() {
return telePoolConstant;
}
private final ConstantPool localConstantPool;
protected final ConstantPool localConstantPool() {
return localConstantPool;
}
private final PoolConstant localPoolConstant;
protected final PoolConstant localPoolConstant() {
return localPoolConstant;
}
protected final boolean isResolved() {
return telePoolConstant != null && telePoolConstant.isResolved();
}
public static PoolConstantLabel make(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
PoolConstantLabel poolConstantLabel;
final PoolConstant poolConstant = localConstantPool.at(index);
if (poolConstant == null) {
poolConstantLabel = new PoolConstantLabel.Null(inspection, index, localConstantPool, teleConstantPool, mode);
} else {
switch (poolConstant.tag()) {
case CLASS:
poolConstantLabel = new PoolConstantLabel.Class(inspection, index, localConstantPool, teleConstantPool, mode);
break;
case FIELD_REF:
poolConstantLabel = new PoolConstantLabel.Field(inspection, index, localConstantPool, teleConstantPool, mode);
break;
case METHOD_REF:
poolConstantLabel = new PoolConstantLabel.ClassMethod(inspection, index, localConstantPool, teleConstantPool, mode);
break;
case INTERFACE_METHOD_REF:
poolConstantLabel = new PoolConstantLabel.InterfaceMethod(inspection, index, localConstantPool, teleConstantPool, mode);
break;
case STRING:
poolConstantLabel = new PoolConstantLabel.StringConstant(inspection, index, localConstantPool, teleConstantPool, mode);
break;
case UTF8:
poolConstantLabel = new PoolConstantLabel.Utf8Constant(inspection, index, localConstantPool, teleConstantPool, mode);
break;
default:
poolConstantLabel = new PoolConstantLabel.Other(inspection, index, localConstantPool, teleConstantPool, mode);
}
}
return poolConstantLabel;
}
protected PoolConstantLabel(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, null);
this.index = index;
this.localConstantPool = localConstantPool;
this.localPoolConstant = localConstantPool.at(index);
this.teleConstantPool = teleConstantPool;
this.mode = mode;
addMouseListener(new InspectorMouseClickAdapter(inspection) {
@Override
public void procedure(final MouseEvent mouseEvent) {
switch (inspection().gui().getButton(mouseEvent)) {
case MouseEvent.BUTTON1:
handleLeftButtonEvent();
break;
case MouseEvent.BUTTON3: {
createPopupMenu().show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
break;
}
default: {
break;
}
}
}
});
refresh(true);
}
protected abstract void updateText();
private MaxVMState lastRefreshedState = null;
public void refresh(boolean force) {
if (vm().state().newerThan(lastRefreshedState) || force) {
lastRefreshedState = vm().state();
if (teleConstantPool != null) {
try {
telePoolConstant = null;
telePoolConstant = teleConstantPool.readTelePoolConstant(index);
} catch (MaxVMBusyException maxVMBusyException) {
} catch (DataIOError dataIOError) {
} catch (InvalidReferenceException invalidReferenceException) {
} catch (TerminatedProcessIOException erminatedProcessIOException) {
}
updateText();
}
}
}
public void redisplay() {
updateText();
}
protected String prefix = "";
public void setPrefix(String prefix) {
this.prefix = prefix;
updateText();
}
protected final void setJavapText(String kind, String name) {
setText(prefix + "#" + Integer.toString(index) + "; //" + kind + " " + name);
}
protected final void setJavapToolTipText(String kind, String name) {
setWrappedToolTipHtmlText("#" + Integer.toString(index) + "<br>" + kind + " " + name);
}
protected final void setJavapResolvableToolTipText(String kind, String name) {
final String resolution = telePoolConstant == null ? inspection().nameDisplay().unavailableDataLongText() :
(isResolved() ? "Resolved" : "Unresolved");
setWrappedToolTipHtmlText("#" + Integer.toString(index) + "<br>" + kind + " " + name + " (" + resolution + ")");
}
private InspectorPopupMenu createPopupMenu() {
final InspectorPopupMenu menu = new InspectorPopupMenu();
if (telePoolConstant != null) {
menu.add(actions().copyWord(telePoolConstant.origin(), "Copy PoolConstant address toclipboard"));
menu.add(views().memory().makeViewAction(telePoolConstant, "View PoolConstant memory words"));
menu.add(views().objects().makeViewAction(telePoolConstant, "View PoolConstant #" + Integer.toString(index)));
menu.add(views().objects().makeViewAction(teleConstantPool, "View ConstantPool"));
specializeMenu(menu);
}
return menu;
}
/**
* Opportunity for subclasses to add additional menu items, depending on the type and state of the constant.
*/
protected void specializeMenu(InspectorPopupMenu menu) {
}
/**
* Opportunity for subclasses to take an action on left-click.
*/
protected void handleLeftButtonEvent() {
}
private static final class Class extends PoolConstantLabel {
private Class(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
protected void updateText() {
final ClassConstant classConstant = (ClassConstant) localPoolConstant();
final TypeDescriptor typeDescriptor = classConstant.typeDescriptor();
switch (mode()) {
case JAVAP:
setJavapText("Class", typeDescriptor.toJavaString(false));
break;
case TERSE:
setText(prefix + typeDescriptor.toJavaString(false));
break;
default:
InspectorError.unimplemented();
}
setJavapResolvableToolTipText("Class", typeDescriptor.toString());
if (isResolved()) {
setForeground(null);
} else {
setForeground(preference().style().javaUnresolvedNameColor());
}
}
@Override
protected void specializeMenu(InspectorPopupMenu menu) {
if (isResolved()) {
menu.addSeparator();
final TeleClassConstant.Resolved teleResolvedClassConstant = (TeleClassConstant.Resolved) telePoolConstant();
final TeleClassActor teleClassActor = teleResolvedClassConstant.getTeleClassActor();
menu.add(views().objects().makeViewAction(teleClassActor, "View ClassActor"));
}
}
}
private static final class Field extends PoolConstantLabel {
private Field(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final FieldRefConstant fieldRefConstant = (FieldRefConstant) localPoolConstant();
final FieldRefKey fieldRefKey = fieldRefConstant.key(localConstantPool());
final TypeDescriptor holder = fieldRefKey.holder();
final String holderName = holder.toJavaString(false);
final String fieldName = fieldRefKey.name().toString();
switch (mode()) {
case JAVAP:
setJavapText("Field", fieldName);
break;
case TERSE:
setText(prefix + fieldName);
break;
default:
InspectorError.unimplemented();
}
setJavapResolvableToolTipText("Field", holderName + "." + fieldName + ":" + fieldRefConstant.type(localConstantPool()).toString());
if (isResolved()) {
setForeground(null);
} else {
setForeground(preference().style().javaUnresolvedNameColor());
}
}
@Override
protected void specializeMenu(InspectorPopupMenu menu) {
if (isResolved()) {
menu.addSeparator();
final TeleFieldRefConstant.Resolved teleResolvedFieldRefConstant = (TeleFieldRefConstant.Resolved) telePoolConstant();
final TeleFieldActor teleFieldActor = teleResolvedFieldRefConstant.getTeleFieldActor();
menu.add(views().objects().makeViewAction(teleFieldActor, "View FieldActor"));
}
}
}
private static final class ClassMethod extends PoolConstantLabel {
/**
* Assigned when resolved.
*/
private TeleClassMethodActor teleClassMethodActor;
private ClassMethod(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
private void checkResolved() {
teleClassMethodActor = null;
if (isResolved()) {
final TeleClassMethodRefConstant.Resolved teleResolvedClassMethodRefConstant = (TeleClassMethodRefConstant.Resolved) telePoolConstant();
try {
teleClassMethodActor = teleResolvedClassMethodRefConstant.getTeleClassMethodActor();
} catch (DataIOError dataIOError) {
}
}
}
@Override
public void updateText() {
checkResolved();
final MethodRefConstant methodRefConstant = (MethodRefConstant) localPoolConstant();
final String methodName = methodRefConstant.name(localConstantPool()).toString();
final String holderName = methodRefConstant.holder(localConstantPool()).toJavaString(false);
switch (mode()) {
case JAVAP:
setJavapText("Method", methodName + "()");
break;
case TERSE:
setText(prefix + methodName + "()");
break;
default:
InspectorError.unimplemented();
}
setJavapResolvableToolTipText("ClassMethod", holderName + "." + methodName + ":" + methodRefConstant.descriptor(localConstantPool()).toString());
if (teleClassMethodActor == null) {
setForeground(preference().style().javaUnresolvedNameColor());
} else {
if (teleClassMethodActor.hasCodeAttribute()) {
setForeground(preference().style().bytecodeMethodEntryColor());
} else {
setForeground(null);
}
}
}
@Override
protected void specializeMenu(InspectorPopupMenu menu) {
checkResolved();
if (teleClassMethodActor != null) {
menu.addSeparator();
final ClassMethodActorMenuItems classMethodMenuItems = new ClassMethodActorMenuItems(inspection(), teleClassMethodActor);
classMethodMenuItems.addTo(menu);
}
}
@Override
protected void handleLeftButtonEvent() {
checkResolved();
if (teleClassMethodActor != null && teleClassMethodActor.hasCodeAttribute()) {
final TeleTargetMethod teleTargetMethod = teleClassMethodActor.getCurrentCompilation();
if (teleTargetMethod != null) {
final MaxCompilation compilation = vm().machineCode().findCompilation(teleTargetMethod.callEntryPoint());
if (compilation != null) {
focus().setCodeLocation(compilation.getCallEntryLocation());
return;
}
}
final MaxCodeLocation bytecodeLocation = vm().codeLocations().createBytecodeLocation(teleClassMethodActor, -1, "Pool constant bytecode operand");
focus().setCodeLocation(bytecodeLocation);
}
}
}
private static final class InterfaceMethod extends PoolConstantLabel {
private InterfaceMethod(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final MethodRefConstant methodRefConstant = (MethodRefConstant) localPoolConstant();
final String methodName = methodRefConstant.name(localConstantPool()).toString();
final String holderName = methodRefConstant.holder(localConstantPool()).toJavaString(false);
switch (mode()) {
case JAVAP:
setJavapText("Method", methodName + "()");
break;
case TERSE:
setText(prefix + methodName + "()");
break;
default:
InspectorError.unimplemented();
}
setJavapResolvableToolTipText("InterfaceMethod", holderName + "." + methodName + ":" + methodRefConstant.descriptor(localConstantPool()).toString());
if (isResolved()) {
setForeground(null);
} else {
setForeground(preference().style().javaUnresolvedNameColor());
}
}
@Override
protected void specializeMenu(InspectorPopupMenu menu) {
if (isResolved()) {
menu.addSeparator();
final TeleInterfaceMethodRefConstant.Resolved teleResolvedInterfaceMethodRefConstant = (TeleInterfaceMethodRefConstant.Resolved) telePoolConstant();
final TeleInterfaceMethodActor teleInterfaceMethodActor = teleResolvedInterfaceMethodRefConstant.getTeleInterfaceMethodActor();
menu.add(views().objects().makeViewAction(teleInterfaceMethodActor, "View InterfaceMethodActor"));
}
}
}
private static final class StringConstant extends PoolConstantLabel {
private StringConstant(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final String fullText = localPoolConstant().valueString(localConstantPool());
final String shortText = (fullText.length() > preference().style().maxBytecodeOperandDisplayLength() + 2) ?
fullText.substring(0, preference().style().maxBytecodeOperandDisplayLength()) + "...\"" : fullText;
switch (mode()) {
case JAVAP:
setJavapText("", shortText);
break;
case TERSE:
setText(prefix + shortText);
break;
default:
InspectorError.unimplemented();
}
setJavapToolTipText("String", fullText);
}
}
private static final class Utf8Constant extends PoolConstantLabel {
private Utf8Constant(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final String fullText = localPoolConstant().valueString(localConstantPool());
final String shortText = (fullText.length() > preference().style().maxBytecodeOperandDisplayLength() + 2) ?
fullText.substring(0, preference().style().maxBytecodeOperandDisplayLength()) + "...\"" : fullText;
switch (mode()) {
case JAVAP:
setJavapText("", shortText);
break;
case TERSE:
setText(prefix + shortText);
break;
default:
InspectorError.unimplemented();
}
setJavapToolTipText("Utf8", fullText);
}
}
private static final class Other extends PoolConstantLabel {
private Other(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final String text = localPoolConstant().valueString(localConstantPool());
switch (mode()) {
case JAVAP:
setText(prefix + text);
break;
case TERSE:
setText(prefix + text);
break;
default:
InspectorError.unimplemented();
}
setJavapToolTipText("", text);
}
}
private static final class Null extends PoolConstantLabel {
private Null(Inspection inspection, int index, ConstantPool localConstantPool, TeleConstantPool teleConstantPool, Mode mode) {
super(inspection, index, localConstantPool, teleConstantPool, mode);
redisplay();
}
@Override
public void updateText() {
final String text = "Error: null";
setJavapToolTipText("", text);
setForeground(preference().style().defaultErrorTextColor());
setBackground(preference().style().defaultErrorTextBackgroundColor());
}
}
}