Mercurial > hg > truffle
view agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java @ 17716:cdb71841f4bc
6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author | minqi |
---|---|
date | Wed, 26 Feb 2014 15:20:41 -0800 |
parents | 5a98bf7d847b |
children |
line wrap: on
line source
/* * Copyright (c) 2002, 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 sun.jvm.hotspot.jdi; import com.sun.jdi.*; import com.sun.jdi.event.EventQueue; import com.sun.jdi.request.EventRequestManager; import sun.jvm.hotspot.HotSpotAgent; import sun.jvm.hotspot.types.TypeDataBase; import sun.jvm.hotspot.oops.Klass; import sun.jvm.hotspot.oops.InstanceKlass; import sun.jvm.hotspot.oops.ArrayKlass; import sun.jvm.hotspot.oops.ObjArrayKlass; import sun.jvm.hotspot.oops.TypeArrayKlass; import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.oops.Instance; import sun.jvm.hotspot.oops.Array; import sun.jvm.hotspot.oops.ObjArray; import sun.jvm.hotspot.oops.TypeArray; import sun.jvm.hotspot.oops.Symbol; import sun.jvm.hotspot.oops.ObjectHeap; import sun.jvm.hotspot.oops.DefaultHeapVisitor; import sun.jvm.hotspot.oops.JVMDIClassStatus; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.JavaThread; import sun.jvm.hotspot.memory.SystemDictionary; import sun.jvm.hotspot.memory.SymbolTable; import sun.jvm.hotspot.memory.Universe; import sun.jvm.hotspot.utilities.Assert; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.Iterator; import java.util.Collections; import java.util.HashMap; import java.util.Observer; import java.util.StringTokenizer; import java.lang.ref.SoftReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.Reference; public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine { private HotSpotAgent saAgent = new HotSpotAgent(); private VM saVM; private Universe saUniverse; private SystemDictionary saSystemDictionary; private SymbolTable saSymbolTable; private ObjectHeap saObjectHeap; VM saVM() { return saVM; } SystemDictionary saSystemDictionary() { return saSystemDictionary; } SymbolTable saSymbolTable() { return saSymbolTable; } Universe saUniverse() { return saUniverse; } ObjectHeap saObjectHeap() { return saObjectHeap; } com.sun.jdi.VirtualMachineManager vmmgr; private final ThreadGroup threadGroupForJDI; // Per-vm singletons for primitive types and for void. // singleton-ness protected by "synchronized(this)". private BooleanType theBooleanType; private ByteType theByteType; private CharType theCharType; private ShortType theShortType; private IntegerType theIntegerType; private LongType theLongType; private FloatType theFloatType; private DoubleType theDoubleType; private VoidType theVoidType; private VoidValue voidVal; private Map typesByID; // Map<Klass, ReferenceTypeImpl> private List typesBySignature; // List<ReferenceTypeImpl> - used in signature search private boolean retrievedAllTypes = false; private List bootstrapClasses; // all bootstrap classes private ArrayList allThreads; private ArrayList topLevelGroups; final int sequenceNumber; // ObjectReference cache // "objectsByID" protected by "synchronized(this)". private final Map objectsByID = new HashMap(); private final ReferenceQueue referenceQueue = new ReferenceQueue(); // names of some well-known classes to jdi private Symbol javaLangString; private Symbol javaLangThread; private Symbol javaLangThreadGroup; private Symbol javaLangClass; private Symbol javaLangClassLoader; // used in ReferenceTypeImpl.isThrowableBacktraceField private Symbol javaLangThrowable; // names of classes used in array assignment check // refer to ArrayTypeImpl.isAssignableTo private Symbol javaLangObject; private Symbol javaLangCloneable; private Symbol javaIoSerializable; // symbol used in ClassTypeImpl.isEnum check private Symbol javaLangEnum; Symbol javaLangObject() { return javaLangObject; } Symbol javaLangCloneable() { return javaLangCloneable; } Symbol javaIoSerializable() { return javaIoSerializable; } Symbol javaLangEnum() { return javaLangEnum; } Symbol javaLangThrowable() { return javaLangThrowable; } // name of the current default stratum private String defaultStratum; // initialize known class name symbols private void initClassNameSymbols() { SymbolTable st = saSymbolTable(); javaLangString = st.probe("java/lang/String"); javaLangThread = st.probe("java/lang/Thread"); javaLangThreadGroup = st.probe("java/lang/ThreadGroup"); javaLangClass = st.probe("java/lang/Class"); javaLangClassLoader = st.probe("java/lang/ClassLoader"); javaLangThrowable = st.probe("java/lang/Throwable"); javaLangObject = st.probe("java/lang/Object"); javaLangCloneable = st.probe("java/lang/Cloneable"); javaIoSerializable = st.probe("java/io/Serializable"); javaLangEnum = st.probe("java/lang/Enum"); } private void init() { saVM = VM.getVM(); saUniverse = saVM.getUniverse(); saSystemDictionary = saVM.getSystemDictionary(); saSymbolTable = saVM.getSymbolTable(); saObjectHeap = saVM.getObjectHeap(); initClassNameSymbols(); } static public VirtualMachineImpl createVirtualMachineForCorefile(VirtualMachineManager mgr, String javaExecutableName, String coreFileName, int sequenceNumber) throws Exception { if (Assert.ASSERTS_ENABLED) { Assert.that(coreFileName != null, "SA VirtualMachineImpl: core filename = null is not yet implemented"); } if (Assert.ASSERTS_ENABLED) { Assert.that(javaExecutableName != null, "SA VirtualMachineImpl: java executable = null is not yet implemented"); } VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); try { myvm.saAgent.attach(javaExecutableName, coreFileName); myvm.init(); } catch (Exception ee) { myvm.saAgent.detach(); throw ee; } return myvm; } static public VirtualMachineImpl createVirtualMachineForPID(VirtualMachineManager mgr, int pid, int sequenceNumber) throws Exception { VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); try { myvm.saAgent.attach(pid); myvm.init(); } catch (Exception ee) { myvm.saAgent.detach(); throw ee; } return myvm; } static public VirtualMachineImpl createVirtualMachineForServer(VirtualMachineManager mgr, String server, int sequenceNumber) throws Exception { if (Assert.ASSERTS_ENABLED) { Assert.that(server != null, "SA VirtualMachineImpl: DebugServer = null is not yet implemented"); } VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); try { myvm.saAgent.attach(server); myvm.init(); } catch (Exception ee) { myvm.saAgent.detach(); throw ee; } return myvm; } VirtualMachineImpl(VirtualMachineManager mgr, int sequenceNumber) throws Exception { super(null); // Can't use super(this) vm = this; this.sequenceNumber = sequenceNumber; this.vmmgr = mgr; /* Create ThreadGroup to be used by all threads servicing * this VM. */ threadGroupForJDI = new ThreadGroup("JDI [" + this.hashCode() + "]"); ((com.sun.tools.jdi.VirtualMachineManagerImpl)mgr).addVirtualMachine(this); // By default SA agent classes prefer Windows process debugger // to windbg debugger. SA expects special properties to be set // to choose other debuggers. We will set those here before // attaching to SA agent. System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true"); } // we reflectively use newly spec'ed class because our ALT_BOOTDIR // is 1.4.2 and not 1.5. private static Class vmCannotBeModifiedExceptionClass = null; void throwNotReadOnlyException(String operation) { RuntimeException re = null; if (vmCannotBeModifiedExceptionClass == null) { try { vmCannotBeModifiedExceptionClass = Class.forName("com.sun.jdi.VMCannotBeModifiedException"); } catch (ClassNotFoundException cnfe) { vmCannotBeModifiedExceptionClass = UnsupportedOperationException.class; } } try { re = (RuntimeException) vmCannotBeModifiedExceptionClass.newInstance(); } catch (Exception exp) { re = new RuntimeException(exp.getMessage()); } throw re; } public boolean equals(Object obj) { // Oh boy; big recursion troubles if we don't have this! // See MirrorImpl.equals return this == obj; } public int hashCode() { // big recursion if we don't have this. See MirrorImpl.hashCode return System.identityHashCode(this); } public List classesByName(String className) { String signature = JNITypeParser.typeNameToSignature(className); List list; if (!retrievedAllTypes) { retrieveAllClasses(); } list = findReferenceTypes(signature); return Collections.unmodifiableList(list); } public List allClasses() { if (!retrievedAllTypes) { retrieveAllClasses(); } ArrayList a; synchronized (this) { a = new ArrayList(typesBySignature); } return Collections.unmodifiableList(a); } // classes loaded by bootstrap loader List bootstrapClasses() { if (bootstrapClasses == null) { bootstrapClasses = new ArrayList(); List all = allClasses(); for (Iterator itr = all.iterator(); itr.hasNext();) { ReferenceType type = (ReferenceType) itr.next(); if (type.classLoader() == null) { bootstrapClasses.add(type); } } } return bootstrapClasses; } private synchronized List findReferenceTypes(String signature) { if (typesByID == null) { return new ArrayList(0); } // we haven't sorted types by signatures. But we can take // advantage of comparing symbols instead of name. In the worst // case, we will be comparing N addresses rather than N strings // where N being total no. of classes in allClasses() list. // The signature could be Lx/y/z; or [.... // If it is Lx/y/z; the internal type name is x/y/x // for array klasses internal type name is same as // signature String typeName = null; if (signature.charAt(0) == 'L') { typeName = signature.substring(1, signature.length() - 1); } else { typeName = signature; } Symbol typeNameSym = saSymbolTable().probe(typeName); // if there is no symbol in VM, then we wouldn't have that type if (typeNameSym == null) { return new ArrayList(0); } Iterator iter = typesBySignature.iterator(); List list = new ArrayList(); while (iter.hasNext()) { // We have cached type name as symbol in reference type ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); if (typeNameSym.equals(type.typeNameAsSymbol())) { list.add(type); } } return list; } private void retrieveAllClasses() { final List saKlasses = new ArrayList(); SystemDictionary.ClassVisitor visitor = new SystemDictionary.ClassVisitor() { public void visit(Klass k) { for (Klass l = k; l != null; l = l.arrayKlassOrNull()) { // for non-array classes filter out un-prepared classes // refer to 'allClasses' in share/back/VirtualMachineImpl.c if (l instanceof ArrayKlass) { saKlasses.add(l); } else { int status = l.getClassStatus(); if ((status & JVMDIClassStatus.PREPARED) != 0) { saKlasses.add(l); } } } } }; // refer to jvmtiGetLoadedClasses.cpp - getLoadedClasses in VM code. // classes from SystemDictionary saSystemDictionary.classesDo(visitor); // From SystemDictionary we do not get primitive single // dimensional array classes. add primitive single dimensional array // klasses from Universe. saVM.getUniverse().basicTypeClassesDo(visitor); // Hold lock during processing to improve performance // and to have safe check/set of retrievedAllTypes synchronized (this) { if (!retrievedAllTypes) { // Number of classes int count = saKlasses.size(); for (int ii = 0; ii < count; ii++) { Klass kk = (Klass)saKlasses.get(ii); ReferenceTypeImpl type = referenceType(kk); } retrievedAllTypes = true; } } } ReferenceTypeImpl referenceType(Klass kk) { ReferenceTypeImpl retType = null; synchronized (this) { if (typesByID != null) { retType = (ReferenceTypeImpl)typesByID.get(kk); } if (retType == null) { retType = addReferenceType(kk); } } return retType; } private void initReferenceTypes() { typesByID = new HashMap(); typesBySignature = new ArrayList(); } private synchronized ReferenceTypeImpl addReferenceType(Klass kk) { if (typesByID == null) { initReferenceTypes(); } ReferenceTypeImpl newRefType = null; if (kk instanceof ObjArrayKlass || kk instanceof TypeArrayKlass) { newRefType = new ArrayTypeImpl(this, (ArrayKlass)kk); } else if (kk instanceof InstanceKlass) { if (kk.isInterface()) { newRefType = new InterfaceTypeImpl(this, (InstanceKlass)kk); } else { newRefType = new ClassTypeImpl(this, (InstanceKlass)kk); } } else { throw new RuntimeException("should not reach here:" + kk); } typesByID.put(kk, newRefType); typesBySignature.add(newRefType); return newRefType; } ThreadGroup threadGroupForJDI() { return threadGroupForJDI; } public void redefineClasses(Map classToBytes) { throwNotReadOnlyException("VirtualMachineImpl.redefineClasses()"); } private List getAllThreads() { if (allThreads == null) { allThreads = new ArrayList(10); // Might be enough, might not be for (sun.jvm.hotspot.runtime.JavaThread thread = saVM.getThreads().first(); thread != null; thread = thread.next()) { // refer to JvmtiEnv::GetAllThreads in jvmtiEnv.cpp. // filter out the hidden-from-external-view threads. if (thread.isHiddenFromExternalView() == false) { ThreadReferenceImpl myThread = threadMirror(thread); allThreads.add(myThread); } } } return allThreads; } public List allThreads() { //fixme jjh return Collections.unmodifiableList(getAllThreads()); } public void suspend() { throwNotReadOnlyException("VirtualMachineImpl.suspend()"); } public void resume() { throwNotReadOnlyException("VirtualMachineImpl.resume()"); } public List topLevelThreadGroups() { //fixme jjh // The doc for ThreadGroup says that The top-level thread group // is the only thread group whose parent is null. This means there is // only one top level thread group. There will be a thread in this // group so we will just find a thread whose threadgroup has no parent // and that will be it. if (topLevelGroups == null) { topLevelGroups = new ArrayList(1); Iterator myIt = getAllThreads().iterator(); while (myIt.hasNext()) { ThreadReferenceImpl myThread = (ThreadReferenceImpl)myIt.next(); ThreadGroupReference myGroup = myThread.threadGroup(); ThreadGroupReference myParent = myGroup.parent(); if (myGroup.parent() == null) { topLevelGroups.add(myGroup); break; } } } return Collections.unmodifiableList(topLevelGroups); } public EventQueue eventQueue() { throwNotReadOnlyException("VirtualMachine.eventQueue()"); return null; } public EventRequestManager eventRequestManager() { throwNotReadOnlyException("VirtualMachineImpl.eventRequestManager()"); return null; } public BooleanValue mirrorOf(boolean value) { return new BooleanValueImpl(this,value); } public ByteValue mirrorOf(byte value) { return new ByteValueImpl(this,value); } public CharValue mirrorOf(char value) { return new CharValueImpl(this,value); } public ShortValue mirrorOf(short value) { return new ShortValueImpl(this,value); } public IntegerValue mirrorOf(int value) { return new IntegerValueImpl(this,value); } public LongValue mirrorOf(long value) { return new LongValueImpl(this,value); } public FloatValue mirrorOf(float value) { return new FloatValueImpl(this,value); } public DoubleValue mirrorOf(double value) { return new DoubleValueImpl(this,value); } public StringReference mirrorOf(String value) { throwNotReadOnlyException("VirtualMachinestop.mirrorOf(String)"); return null; } public VoidValue mirrorOfVoid() { if (voidVal == null) { voidVal = new VoidValueImpl(this); } return voidVal; } public Process process() { throwNotReadOnlyException("VirtualMachine.process"); return null; } // dispose observer for Class re-use. refer to ConnectorImpl. private Observer disposeObserver; // ConnectorImpl loaded by a different class loader can not access it. // i.e., runtime package of <ConnectorImpl, L1> is not the same that of // <VirtualMachineImpl, L2> when L1 != L2. So, package private method // can be called reflectively after using setAccessible(true). void setDisposeObserver(Observer observer) { disposeObserver = observer; } private void notifyDispose() { if (Assert.ASSERTS_ENABLED) { Assert.that(disposeObserver != null, "null VM.dispose observer"); } disposeObserver.update(null, null); } public void dispose() { saAgent.detach(); notifyDispose(); } public void exit(int exitCode) { throwNotReadOnlyException("VirtualMachine.exit(int)"); } public boolean canBeModified() { return false; } public boolean canWatchFieldModification() { return false; } public boolean canWatchFieldAccess() { return false; } public boolean canGetBytecodes() { return true; } public boolean canGetSyntheticAttribute() { return true; } // FIXME: For now, all monitor capabilities are disabled public boolean canGetOwnedMonitorInfo() { return false; } public boolean canGetCurrentContendedMonitor() { return false; } public boolean canGetMonitorInfo() { return false; } // because this SA works only with 1.5 and update releases // this should always succeed unlike JVMDI/JDI. public boolean canGet1_5LanguageFeatures() { return true; } public boolean canUseInstanceFilters() { return false; } public boolean canRedefineClasses() { return false; } public boolean canAddMethod() { return false; } public boolean canUnrestrictedlyRedefineClasses() { return false; } public boolean canPopFrames() { return false; } public boolean canGetSourceDebugExtension() { // We can use InstanceKlass.getSourceDebugExtension only if // ClassFileParser parsed the info. But, ClassFileParser parses // SourceDebugExtension attribute only if corresponding JVMDI/TI // capability is set to true. Currently, vmStructs does not expose // JVMDI/TI capabilities and hence we conservatively assume false. return false; } public boolean canRequestVMDeathEvent() { return false; } // new method since 1.6 public boolean canForceEarlyReturn() { return false; } // new method since 1.6 public boolean canGetConstantPool() { return true; } // new method since 1.6 public boolean canGetClassFileVersion() { return true; } // new method since 1.6. public boolean canGetMethodReturnValues() { return false; } // new method since 1.6 // Real body will be supplied later. public boolean canGetInstanceInfo() { return true; } // new method since 1.6 public boolean canUseSourceNameFilters() { return false; } // new method since 1.6. public boolean canRequestMonitorEvents() { return false; } // new method since 1.6. public boolean canGetMonitorFrameInfo() { return true; } // new method since 1.6 // Real body will be supplied later. public long[] instanceCounts(List classes) { if (!canGetInstanceInfo()) { throw new UnsupportedOperationException( "target does not support getting instances"); } final long[] retValue = new long[classes.size()] ; final Klass [] klassArray = new Klass[classes.size()]; boolean allAbstractClasses = true; for (int i=0; i < classes.size(); i++) { ReferenceTypeImpl rti = (ReferenceTypeImpl)classes.get(i); klassArray[i] = rti.ref(); retValue[i]=0; if (!(rti.isAbstract() || ((ReferenceType)rti instanceof InterfaceType))) { allAbstractClasses = false; } } if (allAbstractClasses) { return retValue; } final int size = classes.size(); saObjectHeap.iterate(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { for (int i=0; i < size; i++) { if (klassArray[i].equals(oop.getKlass())) { retValue[i]++; break; } } return false; } }); return retValue; } private List getPath (String pathName) { String cp = saVM.getSystemProperty(pathName); String pathSep = saVM.getSystemProperty("path.separator"); ArrayList al = new ArrayList(); StringTokenizer st = new StringTokenizer(cp, pathSep); while (st.hasMoreTokens()) { al.add(st.nextToken()); } al.trimToSize(); return al; } public List classPath() { return getPath("java.class.path"); } public List bootClassPath() { return getPath("sun.boot.class.path"); } public String baseDirectory() { return saVM.getSystemProperty("user.dir"); } public void setDefaultStratum(String stratum) { defaultStratum = stratum; } public String getDefaultStratum() { return defaultStratum; } public String description() { return java.text.MessageFormat.format(java.util.ResourceBundle. getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"), "" + vmmgr.majorInterfaceVersion(), "" + vmmgr.minorInterfaceVersion(), name()); } public String version() { return saVM.getSystemProperty("java.version"); } public String name() { StringBuffer sb = new StringBuffer(); sb.append("JVM version "); sb.append(version()); sb.append(" ("); sb.append(saVM.getSystemProperty("java.vm.name")); sb.append(", "); sb.append(saVM.getSystemProperty("java.vm.info")); sb.append(")"); return sb.toString(); } // from interface Mirror public VirtualMachine virtualMachine() { return this; } public String toString() { return name(); } public void setDebugTraceMode(int traceFlags) { // spec. says output is implementation dependent // and trace mode may be ignored. we ignore it :-) } // heap walking API // capability check public boolean canWalkHeap() { return true; } // return a list of all objects in heap public List/*<ObjectReference>*/ allObjects() { final List objects = new ArrayList(0); saObjectHeap.iterate( new DefaultHeapVisitor() { public boolean doObj(Oop oop) { objects.add(objectMirror(oop)); return false; } }); return objects; } // equivalent to objectsByType(type, true) public List/*<ObjectReference>*/ objectsByType(ReferenceType type) { return objectsByType(type, true); } // returns objects of type exactly equal to given type private List/*<ObjectReference>*/ objectsByExactType(ReferenceType type) { final List objects = new ArrayList(0); final Klass givenKls = ((ReferenceTypeImpl)type).ref(); saObjectHeap.iterate(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { if (givenKls.equals(oop.getKlass())) { objects.add(objectMirror(oop)); } return false; } }); return objects; } // returns objects of given type as well as it's subtypes private List/*<ObjectReference>*/ objectsBySubType(ReferenceType type) { final List objects = new ArrayList(0); final ReferenceType givenType = type; saObjectHeap.iterate(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { ReferenceTypeImpl curType = (ReferenceTypeImpl) referenceType(oop.getKlass()); if (curType.isAssignableTo(givenType)) { objects.add(objectMirror(oop)); } return false; } }); return objects; } // includeSubtypes - do you want to include subclass/subtype instances of given // ReferenceType or do we want objects of exact type only? public List/*<ObjectReference>*/ objectsByType(ReferenceType type, boolean includeSubtypes) { Klass kls = ((ReferenceTypeImpl)type).ref(); if (kls instanceof InstanceKlass) { InstanceKlass ik = (InstanceKlass) kls; // if the Klass is final or if there are no subklasses loaded yet if (ik.getAccessFlagsObj().isFinal() || ik.getSubklassKlass() == null) { includeSubtypes = false; } } else { // no subtypes for primitive array types ArrayTypeImpl arrayType = (ArrayTypeImpl) type; try { Type componentType = arrayType.componentType(); if (componentType instanceof PrimitiveType) { includeSubtypes = false; } } catch (ClassNotLoadedException cnle) { // ignore. component type not yet loaded } } if (includeSubtypes) { return objectsBySubType(type); } else { return objectsByExactType(type); } } Type findBootType(String signature) throws ClassNotLoadedException { List types = allClasses(); Iterator iter = types.iterator(); while (iter.hasNext()) { ReferenceType type = (ReferenceType)iter.next(); if ((type.classLoader() == null) && (type.signature().equals(signature))) { return type; } } JNITypeParser parser = new JNITypeParser(signature); throw new ClassNotLoadedException(parser.typeName(), "Type " + parser.typeName() + " not loaded"); } BooleanType theBooleanType() { if (theBooleanType == null) { synchronized(this) { if (theBooleanType == null) { theBooleanType = new BooleanTypeImpl(this); } } } return theBooleanType; } ByteType theByteType() { if (theByteType == null) { synchronized(this) { if (theByteType == null) { theByteType = new ByteTypeImpl(this); } } } return theByteType; } CharType theCharType() { if (theCharType == null) { synchronized(this) { if (theCharType == null) { theCharType = new CharTypeImpl(this); } } } return theCharType; } ShortType theShortType() { if (theShortType == null) { synchronized(this) { if (theShortType == null) { theShortType = new ShortTypeImpl(this); } } } return theShortType; } IntegerType theIntegerType() { if (theIntegerType == null) { synchronized(this) { if (theIntegerType == null) { theIntegerType = new IntegerTypeImpl(this); } } } return theIntegerType; } LongType theLongType() { if (theLongType == null) { synchronized(this) { if (theLongType == null) { theLongType = new LongTypeImpl(this); } } } return theLongType; } FloatType theFloatType() { if (theFloatType == null) { synchronized(this) { if (theFloatType == null) { theFloatType = new FloatTypeImpl(this); } } } return theFloatType; } DoubleType theDoubleType() { if (theDoubleType == null) { synchronized(this) { if (theDoubleType == null) { theDoubleType = new DoubleTypeImpl(this); } } } return theDoubleType; } VoidType theVoidType() { if (theVoidType == null) { synchronized(this) { if (theVoidType == null) { theVoidType = new VoidTypeImpl(this); } } } return theVoidType; } PrimitiveType primitiveTypeMirror(char tag) { switch (tag) { case 'Z': return theBooleanType(); case 'B': return theByteType(); case 'C': return theCharType(); case 'S': return theShortType(); case 'I': return theIntegerType(); case 'J': return theLongType(); case 'F': return theFloatType(); case 'D': return theDoubleType(); default: throw new IllegalArgumentException("Unrecognized primitive tag " + tag); } } private void processQueue() { Reference ref; while ((ref = referenceQueue.poll()) != null) { SoftObjectReference softRef = (SoftObjectReference)ref; removeObjectMirror(softRef); } } // Address value is used as uniqueID by ObjectReferenceImpl long getAddressValue(Oop obj) { return vm.saVM.getDebugger().getAddressValue(obj.getHandle()); } synchronized ObjectReferenceImpl objectMirror(Oop key) { // Handle any queue elements that are not strongly reachable processQueue(); if (key == null) { return null; } ObjectReferenceImpl object = null; /* * Attempt to retrieve an existing object object reference */ SoftObjectReference ref = (SoftObjectReference)objectsByID.get(key); if (ref != null) { object = ref.object(); } /* * If the object wasn't in the table, or it's soft reference was * cleared, create a new instance. */ if (object == null) { if (key instanceof Instance) { // look for well-known classes Symbol className = key.getKlass().getName(); if (Assert.ASSERTS_ENABLED) { Assert.that(className != null, "Null class name"); } Instance inst = (Instance) key; if (className.equals(javaLangString)) { object = new StringReferenceImpl(this, inst); } else if (className.equals(javaLangThread)) { object = new ThreadReferenceImpl(this, inst); } else if (className.equals(javaLangThreadGroup)) { object = new ThreadGroupReferenceImpl(this, inst); } else if (className.equals(javaLangClass)) { object = new ClassObjectReferenceImpl(this, inst); } else if (className.equals(javaLangClassLoader)) { object = new ClassLoaderReferenceImpl(this, inst); } else { // not a well-known class. But the base class may be // one of the known classes. Klass kls = key.getKlass().getSuper(); while (kls != null) { className = kls.getName(); // java.lang.Class and java.lang.String are final classes if (className.equals(javaLangThread)) { object = new ThreadReferenceImpl(this, inst); break; } else if(className.equals(javaLangThreadGroup)) { object = new ThreadGroupReferenceImpl(this, inst); break; } else if (className.equals(javaLangClassLoader)) { object = new ClassLoaderReferenceImpl(this, inst); break; } kls = kls.getSuper(); } if (object == null) { // create generic object reference object = new ObjectReferenceImpl(this, inst); } } } else if (key instanceof TypeArray) { object = new ArrayReferenceImpl(this, (Array) key); } else if (key instanceof ObjArray) { object = new ArrayReferenceImpl(this, (Array) key); } else { throw new RuntimeException("unexpected object type " + key); } ref = new SoftObjectReference(key, object, referenceQueue); /* * If there was no previous entry in the table, we add one here * If the previous entry was cleared, we replace it here. */ objectsByID.put(key, ref); } else { ref.incrementCount(); } return object; } synchronized void removeObjectMirror(SoftObjectReference ref) { /* * This will remove the soft reference if it has not been * replaced in the cache. */ objectsByID.remove(ref.key()); } StringReferenceImpl stringMirror(Instance id) { return (StringReferenceImpl) objectMirror(id); } ArrayReferenceImpl arrayMirror(Array id) { return (ArrayReferenceImpl) objectMirror(id); } ThreadReferenceImpl threadMirror(Instance id) { return (ThreadReferenceImpl) objectMirror(id); } ThreadReferenceImpl threadMirror(JavaThread jt) { return (ThreadReferenceImpl) objectMirror(jt.getThreadObj()); } ThreadGroupReferenceImpl threadGroupMirror(Instance id) { return (ThreadGroupReferenceImpl) objectMirror(id); } ClassLoaderReferenceImpl classLoaderMirror(Instance id) { return (ClassLoaderReferenceImpl) objectMirror(id); } ClassObjectReferenceImpl classObjectMirror(Instance id) { return (ClassObjectReferenceImpl) objectMirror(id); } // Use of soft refs and caching stuff here has to be re-examined. // It might not make sense for JDI - SA. static private class SoftObjectReference extends SoftReference { int count; Object key; SoftObjectReference(Object key, ObjectReferenceImpl mirror, ReferenceQueue queue) { super(mirror, queue); this.count = 1; this.key = key; } int count() { return count; } void incrementCount() { count++; } Object key() { return key; } ObjectReferenceImpl object() { return (ObjectReferenceImpl)get(); } } }