/*
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.jdi;
import org.visage.jdi.event.VisageEventQueue;
import org.visage.jdi.request.VisageEventRequestManager;
import com.sun.jdi.Type;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
import com.sun.jdi.BooleanType;
import com.sun.jdi.BooleanValue;
import com.sun.jdi.ByteType;
import com.sun.jdi.ByteValue;
import com.sun.jdi.CharType;
import com.sun.jdi.CharValue;
import com.sun.jdi.ClassLoaderReference;
import com.sun.jdi.ClassObjectReference;
import com.sun.jdi.ClassType;
import com.sun.jdi.DoubleType;
import com.sun.jdi.DoubleValue;
import com.sun.jdi.Field;
import com.sun.jdi.FloatType;
import com.sun.jdi.FloatValue;
import com.sun.jdi.IntegerType;
import com.sun.jdi.IntegerValue;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.LongType;
import com.sun.jdi.LongValue;
import com.sun.jdi.Method;
import com.sun.jdi.MonitorInfo;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.ShortType;
import com.sun.jdi.ShortValue;
import com.sun.jdi.StackFrame;
import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadGroupReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.Value;
import com.sun.jdi.VoidType;
import com.sun.jdi.VoidValue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author sundar
*/
public class VisageVirtualMachine extends VisageMirror implements VirtualMachine {
public VisageVirtualMachine(VirtualMachine underlying) {
super(null, underlying);
}
public boolean canForceEarlyReturn() {
return underlying().canForceEarlyReturn();
}
public boolean canGetClassFileVersion() {
return underlying().canGetClassFileVersion();
}
public boolean canGetConstantPool() {
return underlying().canGetConstantPool();
}
public boolean canGetInstanceInfo() {
return underlying().canGetInstanceInfo();
}
public boolean canGetMethodReturnValues() {
return underlying().canGetMethodReturnValues();
}
public boolean canGetMonitorFrameInfo() {
return underlying().canGetMonitorFrameInfo();
}
public boolean canRequestMonitorEvents() {
return underlying().canRequestMonitorEvents();
}
public boolean canUseSourceNameFilters() {
return underlying().canUseSourceNameFilters();
}
public long[] instanceCounts(List<? extends ReferenceType> refTypes) {
return underlying().instanceCounts(VisageWrapper.unwrapReferenceTypes(refTypes));
}
public VoidValue mirrorOfVoid() {
return voidValue();
}
@Override
public VisageVirtualMachine virtualMachine() {
return this;
}
public List<ReferenceType> allClasses() {
return VisageWrapper.wrapReferenceTypes(this, underlying().allClasses());
}
public List<ThreadReference> allThreads() {
return VisageWrapper.wrapThreads(this, underlying().allThreads());
}
public boolean canAddMethod() {
return underlying().canAddMethod();
}
public boolean canBeModified() {
return underlying().canBeModified();
}
public boolean canGetBytecodes() {
return underlying().canGetBytecodes();
}
public boolean canGetCurrentContendedMonitor() {
return underlying().canGetCurrentContendedMonitor();
}
public boolean canGetMonitorInfo() {
return underlying().canGetMonitorInfo();
}
public boolean canGetOwnedMonitorInfo() {
return underlying().canGetOwnedMonitorInfo();
}
public boolean canGetSourceDebugExtension() {
return underlying().canGetSourceDebugExtension();
}
public boolean canGetSyntheticAttribute() {
return underlying().canGetSyntheticAttribute();
}
public boolean canPopFrames() {
return underlying().canPopFrames();
}
public boolean canRedefineClasses() {
return underlying().canRedefineClasses();
}
public boolean canRequestVMDeathEvent() {
return underlying().canRequestVMDeathEvent();
}
public boolean canUnrestrictedlyRedefineClasses() {
return underlying().canUnrestrictedlyRedefineClasses();
}
public boolean canUseInstanceFilters() {
return underlying().canUseInstanceFilters();
}
public boolean canWatchFieldAccess() {
return underlying().canWatchFieldAccess();
}
public boolean canWatchFieldModification() {
return underlying().canWatchFieldModification();
}
public List<ReferenceType> classesByName(String name) {
List<ReferenceType> refTypes = underlying().classesByName(name);
return VisageWrapper.wrapReferenceTypes(this, refTypes);
}
public String description() {
return underlying().description();
}
public void dispose() {
underlying().dispose();
}
private VisageEventQueue evtQueue;
public synchronized VisageEventQueue eventQueue() {
if (evtQueue == null) {
evtQueue = VisageWrapper.wrap(this, underlying().eventQueue());
}
return evtQueue;
}
private VisageEventRequestManager evtManager;
public synchronized VisageEventRequestManager eventRequestManager() {
if (evtManager == null) {
evtManager = VisageWrapper.wrap(this, underlying().eventRequestManager());
}
return evtManager;
}
public void exit(int exitCode) {
underlying().exit(exitCode);
}
public String getDefaultStratum() {
return underlying().getDefaultStratum();
}
public VisageBooleanValue mirrorOf(boolean value) {
return new VisageBooleanValue(this, underlying().mirrorOf(value));
}
public VisageByteValue mirrorOf(byte value) {
return new VisageByteValue(this, underlying().mirrorOf(value));
}
public VisageCharValue mirrorOf(char value) {
return new VisageCharValue(this, underlying().mirrorOf(value));
}
public VisageShortValue mirrorOf(short value) {
return new VisageShortValue(this, underlying().mirrorOf(value));
}
public VisageIntegerValue mirrorOf(int value) {
return new VisageIntegerValue(this, underlying().mirrorOf(value));
}
public VisageLongValue mirrorOf(long value) {
return new VisageLongValue(this, underlying().mirrorOf(value));
}
public VisageFloatValue mirrorOf(float value) {
return new VisageFloatValue(this, underlying().mirrorOf(value));
}
public VisageDoubleValue mirrorOf(double value) {
return new VisageDoubleValue(this, underlying().mirrorOf(value));
}
public StringReference mirrorOf(String value) {
return new VisageStringReference(this, underlying().mirrorOf(value));
}
// default values
private VisageBooleanValue booleanDefaultValue;
protected synchronized VisageBooleanValue booleanDefaultValue() {
if (booleanDefaultValue == null) {
booleanDefaultValue = mirrorOf(false);
}
return booleanDefaultValue;
}
private VisageByteValue byteDefaultValue;
protected synchronized VisageByteValue byteDefaultValue() {
if (byteDefaultValue == null) {
byteDefaultValue = mirrorOf((byte)0);
}
return byteDefaultValue;
}
private VisageCharValue charDefaultValue;
protected synchronized VisageCharValue charDefaultValue() {
if (charDefaultValue == null) {
charDefaultValue = mirrorOf('\u0000');
}
return charDefaultValue;
}
private VisageShortValue shortDefaultValue;
protected synchronized VisageShortValue shortDefaultValue() {
if (shortDefaultValue == null) {
shortDefaultValue = mirrorOf((short)0);
}
return shortDefaultValue;
}
private VisageIntegerValue integerDefaultValue;
protected synchronized VisageIntegerValue integerDefaultValue() {
if (integerDefaultValue == null) {
integerDefaultValue = mirrorOf(0);
}
return integerDefaultValue;
}
private VisageLongValue longDefaultValue;
protected synchronized VisageLongValue longDefaultValue() {
if (longDefaultValue == null) {
longDefaultValue = mirrorOf(0l);
}
return longDefaultValue;
}
private VisageFloatValue floatDefaultValue;
protected synchronized VisageFloatValue floatDefaultValue() {
if (floatDefaultValue == null) {
floatDefaultValue = mirrorOf(0.0f);
}
return floatDefaultValue;
}
private VisageDoubleValue doubleDefaultValue;
protected synchronized VisageDoubleValue doubleDefaultValue() {
if (doubleDefaultValue == null) {
doubleDefaultValue = mirrorOf(0.0d);
}
return doubleDefaultValue;
}
//////////
public String name() {
return underlying().name();
}
public Process process() {
return underlying().process();
}
public void redefineClasses(Map<? extends ReferenceType, byte[]> classBytes) {
Map<ReferenceType, byte[]> unwrappedClassBytes = new HashMap<ReferenceType, byte[]>();
for (Map.Entry<? extends ReferenceType, byte[]> entry : classBytes.entrySet()) {
unwrappedClassBytes.put(VisageWrapper.unwrap(entry.getKey()), entry.getValue());
}
underlying().redefineClasses(unwrappedClassBytes);
}
public void resume() {
underlying().resume();
}
public void setDebugTraceMode(int mode) {
underlying().setDebugTraceMode(mode);
}
public void setDefaultStratum(String stratum) {
underlying().setDefaultStratum(stratum);
}
public void suspend() {
underlying().suspend();
}
public List<ThreadGroupReference> topLevelThreadGroups() {
return VisageWrapper.wrapThreadGroups(this, underlying().topLevelThreadGroups());
}
public String version() {
return underlying().version();
}
private VisageThreadReference cacheUiThread = null;
/**
* JDI addition: Return the thread upon which invokeMethods are performed to get/set fields
*
* @return the thread upon which invokeMethods are performed by Visage-JDI to get/set fields
* that have getters/setters
*/
public VisageThreadReference uiThread() {
if (cacheUiThread == null) {
VisageField uiThreadField = visageEntryType().fieldByName("uiThread");
cacheUiThread = (VisageThreadReference) ((VisageReferenceType)visageEntryType()).getValue(uiThreadField);
}
return cacheUiThread;
}
@Override
protected VirtualMachine underlying() {
return (VirtualMachine) super.underlying();
}
// Visage types
public static final String VISAGE_ENTRY_TYPE_NAME = "org.visage.runtime.Entry";
private VisageClassType visageEntryType;
public synchronized VisageClassType visageEntryType() {
if (visageEntryType == null) {
List<ReferenceType> refTypes = classesByName(VISAGE_ENTRY_TYPE_NAME);
visageEntryType = refTypes.isEmpty() ? null : (VisageClassType) refTypes.get(0);
}
return visageEntryType;
}
public static final String VISAGE_OBJECT_TYPE_NAME = "org.visage.runtime.VisageObject";
private VisageObjectType visageObjectType;
public synchronized VisageObjectType visageObjectType() {
if (visageObjectType == null) {
List<ReferenceType> refTypes = classesByName(VISAGE_OBJECT_TYPE_NAME);
visageObjectType = refTypes.isEmpty() ? null : (VisageObjectType) refTypes.get(0);
}
return visageObjectType;
}
public static final String VISAGE_MIXIN_TYPE_NAME = "org.visage.runtime.VisageMixin";
private VisageInterfaceType visageMixinType;
public synchronized VisageReferenceType visageMixinType() {
if (visageMixinType == null) {
List<ReferenceType> refTypes = classesByName(VISAGE_MIXIN_TYPE_NAME);
visageMixinType = refTypes.isEmpty()? null : (VisageInterfaceType) refTypes.get(0);
}
return visageMixinType;
}
public static final String VISAGE_SEQUENCE_TYPE_NAME = "org.visage.runtime.sequence.Sequence";
private VisageSequenceType visageSequenceType;
public synchronized VisageSequenceType visageSequenceType() {
if (visageSequenceType == null) {
List<ReferenceType> refTypes = classesByName(VISAGE_SEQUENCE_TYPE_NAME);
visageSequenceType = refTypes.isEmpty() ? null : (VisageSequenceType) refTypes.get(0);
}
return visageSequenceType;
}
public static final String VISAGE_SEQUENCES_TYPE_NAME = "org.visage.runtime.sequence.Sequences";
private VisageSequencesType visageSequencesType;
public synchronized VisageSequencesType visageSequencesType() {
if (visageSequencesType == null) {
List<ReferenceType> refTypes = classesByName(VISAGE_SEQUENCES_TYPE_NAME);
if (refTypes.isEmpty()) {
// ensure that the debuggee has loaded and initialized Sequences type
visageSequencesType = (VisageSequencesType) classType(initSequencesType());
} else {
visageSequencesType = (VisageSequencesType) refTypes.get(0);
}
}
return visageSequencesType;
}
private VisageVoidValue voidValue;
protected synchronized VisageVoidValue voidValue() {
if (voidValue == null) {
voidValue = new VisageVoidValue(this, underlying().mirrorOfVoid());
}
return voidValue;
}
// wrapper methods
// primitive type accessors
private VisageVoidType voidType;
protected synchronized VisageVoidType voidType(VoidType vt) {
if (voidType == null) {
voidType = new VisageVoidType(this, vt);
}
return voidType;
}
private VisageBooleanType booleanType;
protected synchronized VisageBooleanType booleanType(BooleanType bt) {
if (booleanType == null) {
booleanType = new VisageBooleanType(this, bt);
}
return booleanType;
}
private VisageCharType charType;
protected synchronized VisageCharType charType(CharType ct) {
if (charType == null) {
charType = new VisageCharType(this, ct);
}
return charType;
}
private VisageByteType byteType;
protected synchronized VisageByteType byteType(ByteType bt) {
if (byteType == null) {
byteType = new VisageByteType(this, bt);
}
return byteType;
}
private VisageShortType shortType;
protected synchronized VisageShortType shortType(ShortType st) {
if (shortType == null) {
shortType = new VisageShortType(this, st);
}
return shortType;
}
private VisageIntegerType integerType;
protected synchronized VisageIntegerType integerType(IntegerType it) {
if (integerType == null) {
integerType = new VisageIntegerType(this, it);
}
return integerType;
}
private VisageLongType longType;
protected synchronized VisageLongType longType(LongType lt) {
if (longType == null) {
longType = new VisageLongType(this, lt);
}
return longType;
}
private VisageFloatType floatType;
protected synchronized VisageFloatType floatType(FloatType ft) {
if (floatType == null) {
floatType = new VisageFloatType(this, ft);
}
return floatType;
}
private VisageDoubleType doubleType;
protected synchronized VisageDoubleType doubleType(DoubleType dt) {
if (doubleType == null) {
doubleType = new VisageDoubleType(this, dt);
}
return doubleType;
}
protected VisageLocation location(Location loc) {
return new VisageLocation(this, loc);
}
private final Map<ReferenceType, VisageReferenceType> refTypesCache =
new HashMap<ReferenceType, VisageReferenceType>();
protected VisageReferenceType referenceType(ReferenceType rt) {
synchronized (refTypesCache) {
if (! refTypesCache.containsKey(rt)) {
refTypesCache.put(rt, new VisageReferenceType(this, rt));
}
return refTypesCache.get(rt);
}
}
protected VisageClassType classType(ClassType ct) {
synchronized (refTypesCache) {
if (! refTypesCache.containsKey(ct)) {
String name = ct.name();
if (name.equals(VISAGE_SEQUENCES_TYPE_NAME)) {
refTypesCache.put(ct, new VisageSequencesType(this, ct));
} else {
refTypesCache.put(ct, new VisageClassType(this, ct));
}
}
return (VisageClassType) refTypesCache.get(ct);
}
}
protected VisageInterfaceType interfaceType(InterfaceType it) {
synchronized (refTypesCache) {
if (! refTypesCache.containsKey(it)) {
String name = it.name();
if (name.equals(VISAGE_OBJECT_TYPE_NAME)) {
refTypesCache.put(it, new VisageObjectType(this, it));
} else if (name.equals(VISAGE_SEQUENCE_TYPE_NAME)) {
refTypesCache.put(it, new VisageSequenceType(this, it));
} else {
refTypesCache.put(it, new VisageInterfaceType(this, it));
}
}
return (VisageInterfaceType) refTypesCache.get(it);
}
}
protected VisageArrayType arrayType(ArrayType at) {
synchronized (at) {
if (! refTypesCache.containsKey(at)) {
refTypesCache.put(at, new VisageArrayType(this, at));
}
return (VisageArrayType) refTypesCache.get(at);
}
}
protected VisageField field(Field field) {
return new VisageField(this, field);
}
protected VisageMethod method(Method method) {
return new VisageMethod(this, method);
}
protected VisageLocalVariable localVariable(LocalVariable var) {
return new VisageLocalVariable(this, var);
}
protected VisageBooleanValue booleanValue(BooleanValue value) {
return new VisageBooleanValue(this, value);
}
protected VisageCharValue charValue(CharValue value) {
return new VisageCharValue(this, value);
}
protected VisageByteValue byteValue(ByteValue value) {
return new VisageByteValue(this, value);
}
protected VisageShortValue shortValue(ShortValue value) {
return new VisageShortValue(this, value);
}
protected VisageIntegerValue integerValue(IntegerValue value) {
return new VisageIntegerValue(this, value);
}
protected VisageLongValue longValue(LongValue value) {
return new VisageLongValue(this, value);
}
protected VisageFloatValue floatValue(FloatValue value) {
return new VisageFloatValue(this, value);
}
protected VisageDoubleValue doubleValue(DoubleValue value) {
return new VisageDoubleValue(this, value);
}
protected VisageObjectReference objectReference(ObjectReference ref) {
ReferenceType rt = ref.referenceType();
if (rt instanceof ClassType) {
ClassType ct = (ClassType) rt;
boolean isSeq = ct.allInterfaces().contains(VisageWrapper.unwrap(visageSequenceType()));
if (isSeq) {
return new VisageSequenceReference(this, ref);
}
}
return new VisageObjectReference(this, ref);
}
protected VisageThreadReference threadReference(ThreadReference tref) {
return new VisageThreadReference(this, tref);
}
protected VisageThreadGroupReference threadGroupReference(ThreadGroupReference tgref) {
return new VisageThreadGroupReference(this, tgref);
}
protected VisageStringReference stringReference(StringReference sref) {
return new VisageStringReference(this, sref);
}
protected VisageClassLoaderReference classLoaderReference(ClassLoaderReference clref) {
return new VisageClassLoaderReference(this, clref);
}
protected VisageClassObjectReference classObjectReference(ClassObjectReference coref) {
return new VisageClassObjectReference(this, coref);
}
protected VisageArrayReference arrayReference(ArrayReference aref) {
return new VisageArrayReference(this, aref);
}
protected VisageMonitorInfo monitorInfo(MonitorInfo monitorInfo) {
return new VisageMonitorInfo(this, monitorInfo);
}
protected VisageStackFrame stackFrame(StackFrame frame) {
return new VisageStackFrame(this, frame);
}
protected Exception lastFieldAccessException = null;
protected void setLastFieldAccessException(Exception ee) {
lastFieldAccessException = ee;
}
/**
* JDI addition: Return the exception thrown by an invokeMethod call that was
* performed in the most recent setValue, getValue, or getValues method call.
*
* @return the exception thrown by an invokeMethod call that was
* performed in the most recent setValue, getValue, or getValues method call, or
* null if no such exception was thrown.
*/
public Exception lastFieldAccessException() {
return lastFieldAccessException;
}
// cache these masks
private int invalidFlagMask = 0;
private int readOnlyFlagMask = 0;
private int boundFlagMask = 0;
private int getFlagMask(String maskName) {
int flagMask = 0;
// we only work with underlying JDI objects here
List<ReferenceType> rtx = this.underlying().classesByName("org.visage.runtime.VisageObject");
if (rtx.size() != 1) {
System.out.println("Can't find the ReferenceType for org.visage.runtime.VisageObject");
return 0;
}
ReferenceType visageObjectRefType = rtx.get(0);
Field fieldx = visageObjectRefType.fieldByName(maskName);
Value flagValue = visageObjectRefType.getValue(fieldx);
return ((IntegerValue)flagValue).value();
}
protected int VisageReadOnlyFlagMask() {
if (readOnlyFlagMask == 0) {
readOnlyFlagMask = getFlagMask("VFLGS$IS_READONLY");
}
return readOnlyFlagMask;
}
protected int VisageInvalidFlagMask() {
if (invalidFlagMask == 0) {
invalidFlagMask = getFlagMask("VFLGS$IS_BOUND_INVALID");
}
return invalidFlagMask;
}
protected int VisageBoundFlagMask() {
if (boundFlagMask == 0) {
boundFlagMask = getFlagMask("VFLGS$IS_BOUND");
}
return boundFlagMask;
}
protected Value defaultValue(Type type) {
if (type instanceof BooleanType) {
return booleanDefaultValue();
}
if (type instanceof ByteType) {
return byteDefaultValue();
}
if (type instanceof CharType) {
return charDefaultValue();
}
if (type instanceof DoubleType) {
return doubleDefaultValue();
}
if (type instanceof FloatType) {
return floatDefaultValue();
}
if (type instanceof IntegerType) {
return integerDefaultValue();
}
if (type instanceof LongType) {
return longDefaultValue();
}
if (type instanceof ShortType) {
return shortDefaultValue();
}
// else it is an object/array/sequence/...
return null;
}
// ensure that the debuggee VM has loaded and initialized Sequences type
private synchronized ClassType initSequencesType() {
VirtualMachine vm = underlying();
ClassType classType = (ClassType) vm.classesByName("java.lang.Class").get(0);
Method forName = classType.concreteMethodByName("forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
// Class.forName(VISAGE_SEQUENCES_TYPE_NAME, true, Entry.class.getClassLoader());
try {
List<Value> args = new ArrayList<Value>(3);
args.add(vm.mirrorOf(VISAGE_SEQUENCES_TYPE_NAME));
args.add(vm.mirrorOf(true));
args.add(VisageWrapper.unwrap(visageEntryType().classLoader()));
ClassObjectReference retVal = (ClassObjectReference)classType.invokeMethod(
VisageWrapper.unwrap(uiThread()), forName, args, 0);
// retVal must be a ClassObjectReference for the Sequences class
return (ClassType)retVal.reflectedType();
} catch (RuntimeException exp) {
throw exp;
} catch (Exception exp) {
// exp.printStackTrace();
throw new RuntimeException(exp);
}
}
}