/* * 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); } } }