0
|
1 /*
|
|
2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.jdi;
|
|
26
|
|
27 import java.io.*;
|
|
28 import com.sun.jdi.*;
|
|
29
|
|
30 import sun.jvm.hotspot.debugger.Address;
|
|
31 import sun.jvm.hotspot.debugger.OopHandle;
|
|
32 import sun.jvm.hotspot.oops.Oop;
|
|
33 import sun.jvm.hotspot.oops.Mark;
|
|
34 import sun.jvm.hotspot.oops.Instance;
|
|
35 import sun.jvm.hotspot.oops.Array;
|
|
36 import sun.jvm.hotspot.oops.OopUtilities;
|
|
37 import sun.jvm.hotspot.oops.Klass;
|
|
38 import sun.jvm.hotspot.oops.DefaultHeapVisitor;
|
|
39 import sun.jvm.hotspot.runtime.JavaThread;
|
|
40 import sun.jvm.hotspot.runtime.JavaVFrame;
|
|
41 import sun.jvm.hotspot.runtime.MonitorInfo;
|
|
42 import sun.jvm.hotspot.runtime.ObjectMonitor;
|
|
43 import sun.jvm.hotspot.runtime.Threads;
|
|
44 import sun.jvm.hotspot.utilities.Assert;
|
|
45
|
|
46 import java.util.*;
|
|
47
|
|
48 public class ObjectReferenceImpl extends ValueImpl implements ObjectReference {
|
|
49 private Oop saObject;
|
|
50 private long myID;
|
|
51 private boolean monitorInfoCached = false;
|
|
52 private ThreadReferenceImpl owningThread = null;
|
|
53 private List waitingThreads = null; // List<ThreadReferenceImpl>
|
|
54 private int entryCount = 0;
|
|
55
|
|
56 private static long nextID = 0L;
|
|
57 private static synchronized long nextID() {
|
|
58 return nextID++;
|
|
59 }
|
|
60
|
|
61 ObjectReferenceImpl(VirtualMachine aVm, sun.jvm.hotspot.oops.Oop oRef) {
|
|
62 super(aVm);
|
|
63 saObject = oRef;
|
|
64 myID = nextID();
|
|
65 }
|
|
66
|
|
67 protected Oop ref() {
|
|
68 return saObject;
|
|
69 }
|
|
70
|
|
71 public Type type() {
|
|
72 return referenceType();
|
|
73 }
|
|
74
|
|
75 public ReferenceType referenceType() {
|
|
76 Klass myKlass = ref().getKlass();
|
|
77 return vm.referenceType(myKlass);
|
|
78 }
|
|
79
|
|
80 public Value getValue(Field sig) {
|
|
81 List list = new ArrayList(1);
|
|
82 list.add(sig);
|
|
83 Map map = getValues(list);
|
|
84 return(Value)map.get(sig);
|
|
85 }
|
|
86
|
|
87 public Map getValues(List theFields) {
|
|
88 //validateMirrors(theFields);
|
|
89
|
|
90 List staticFields = new ArrayList(0);
|
|
91 int size = theFields.size();
|
|
92 List instanceFields = new ArrayList(size);
|
|
93
|
|
94 for (int i=0; i<size; i++) {
|
|
95 sun.jvm.hotspot.jdi.FieldImpl field =
|
|
96 (sun.jvm.hotspot.jdi.FieldImpl)theFields.get(i);
|
|
97
|
|
98 // Make sure the field is valid
|
|
99 ((ReferenceTypeImpl)referenceType()).validateFieldAccess(field);
|
|
100
|
|
101 // FIX ME! We need to do some sanity checking
|
|
102 // here; make sure the field belongs to this
|
|
103 // object.
|
|
104 if (field.isStatic()) {
|
|
105 staticFields.add(field);
|
|
106 } else {
|
|
107 instanceFields.add(field);
|
|
108 }
|
|
109 }
|
|
110
|
|
111 // Look up static field(s) first to mimic the JDI implementation
|
|
112 Map map;
|
|
113 if (staticFields.size() > 0) {
|
|
114 map = referenceType().getValues(staticFields);
|
|
115 } else {
|
|
116 map = new HashMap(size);
|
|
117 }
|
|
118
|
|
119 // Then get instance field(s)
|
|
120 size = instanceFields.size();
|
|
121 for (int ii=0; ii<size; ii++){
|
|
122 FieldImpl fieldImpl = (FieldImpl)instanceFields.get(ii);
|
|
123 map.put(fieldImpl, fieldImpl.getValue(saObject));
|
|
124 }
|
|
125
|
|
126 return map;
|
|
127 }
|
|
128
|
|
129 public void setValue(Field field, Value value)
|
|
130 throws InvalidTypeException, ClassNotLoadedException {
|
|
131 vm.throwNotReadOnlyException("ObjectReference.setValue(...)");
|
|
132 }
|
|
133
|
|
134 public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
|
|
135 List arguments, int options)
|
|
136 throws InvalidTypeException,
|
|
137 IncompatibleThreadStateException,
|
|
138 InvocationException,
|
|
139 ClassNotLoadedException {
|
|
140 vm.throwNotReadOnlyException("ObjectReference.invokeMethod(...)");
|
|
141 return null;
|
|
142 }
|
|
143
|
|
144 public void disableCollection() {
|
|
145 vm.throwNotReadOnlyException("ObjectReference.disableCollection()");
|
|
146 }
|
|
147
|
|
148 public void enableCollection() {
|
|
149 vm.throwNotReadOnlyException("ObjectReference.enableCollection()");
|
|
150 }
|
|
151
|
|
152 public boolean isCollected() {
|
|
153 vm.throwNotReadOnlyException("ObjectReference.isCollected()");
|
|
154 return false;
|
|
155 }
|
|
156
|
|
157 public long uniqueID() {
|
|
158 return myID;
|
|
159 }
|
|
160
|
|
161 public List waitingThreads() throws IncompatibleThreadStateException {
|
|
162 if (vm.canGetMonitorInfo() == false) {
|
|
163 throw new UnsupportedOperationException();
|
|
164 }
|
|
165
|
|
166 if (! monitorInfoCached) {
|
|
167 computeMonitorInfo();
|
|
168 }
|
|
169 return waitingThreads;
|
|
170 }
|
|
171
|
|
172
|
|
173 public ThreadReference owningThread() throws IncompatibleThreadStateException {
|
|
174 if (vm.canGetMonitorInfo() == false) {
|
|
175 throw new UnsupportedOperationException();
|
|
176 }
|
|
177
|
|
178 if (! monitorInfoCached) {
|
|
179 computeMonitorInfo();
|
|
180 }
|
|
181 return owningThread;
|
|
182 }
|
|
183
|
|
184
|
|
185 public int entryCount() throws IncompatibleThreadStateException {
|
|
186 if (vm.canGetMonitorInfo() == false) {
|
|
187 throw new UnsupportedOperationException();
|
|
188 }
|
|
189
|
|
190 if (! monitorInfoCached) {
|
|
191 computeMonitorInfo();
|
|
192 }
|
|
193 return entryCount;
|
|
194 }
|
|
195
|
|
196 // new method since 1.6.
|
|
197 // Real body will be supplied later.
|
|
198 public List referringObjects(long maxReferrers) {
|
|
199 if (!vm.canGetInstanceInfo()) {
|
|
200 throw new UnsupportedOperationException(
|
|
201 "target does not support getting instances");
|
|
202 }
|
|
203 if (maxReferrers < 0) {
|
|
204 throw new IllegalArgumentException("maxReferrers is less than zero: "
|
|
205 + maxReferrers);
|
|
206 }
|
|
207 final ObjectReference obj = this;
|
|
208 final List objects = new ArrayList(0);
|
|
209 final long max = maxReferrers;
|
|
210 vm.saObjectHeap().iterate(new DefaultHeapVisitor() {
|
|
211 private long refCount = 0;
|
|
212 public boolean doObj(Oop oop) {
|
|
213 try {
|
|
214 ObjectReference objref = vm.objectMirror(oop);
|
|
215 List fields = objref.referenceType().allFields();
|
|
216 for (int i=0; i < fields.size(); i++) {
|
|
217 Field fld = (Field)fields.get(i);
|
|
218 if (objref.getValue(fld).equals(obj) && !objects.contains(objref)) {
|
|
219 objects.add(objref);
|
|
220 refCount++;
|
|
221 }
|
|
222 }
|
|
223 if (max > 0 && refCount >= max) {
|
|
224 return true;
|
|
225 }
|
|
226 } catch (RuntimeException x) {
|
|
227 // Ignore RuntimeException thrown from vm.objectMirror(oop)
|
|
228 // for bad oop. It is possible to see some bad oop
|
|
229 // because heap might be iterating at no safepoint.
|
|
230 }
|
|
231 return false;
|
|
232
|
|
233 }
|
|
234 });
|
|
235 return objects;
|
|
236 }
|
|
237
|
|
238 // refer to JvmtiEnvBase::count_locked_objects.
|
|
239 // Count the number of objects for a lightweight monitor. The obj
|
|
240 // parameter is object that owns the monitor so this routine will
|
|
241 // count the number of times the same object was locked by frames
|
|
242 // in JavaThread. i.e., we count total number of times the same
|
|
243 // object is (lightweight) locked by given thread.
|
|
244 private int countLockedObjects(JavaThread jt, Oop obj) {
|
|
245 int res = 0;
|
|
246 JavaVFrame frame = jt.getLastJavaVFrameDbg();
|
|
247 while (frame != null) {
|
|
248 List monitors = frame.getMonitors();
|
|
249 OopHandle givenHandle = obj.getHandle();
|
|
250 for (Iterator itr = monitors.iterator(); itr.hasNext();) {
|
|
251 MonitorInfo mi = (MonitorInfo) itr.next();
|
|
252 if (givenHandle.equals(mi.owner())) {
|
|
253 res++;
|
|
254 }
|
|
255 }
|
|
256 frame = (JavaVFrame) frame.javaSender();
|
|
257 }
|
|
258 return res;
|
|
259 }
|
|
260
|
|
261 // wrappers on same named method of Threads class
|
|
262 // returns List<JavaThread>
|
|
263 private List getPendingThreads(ObjectMonitor mon) {
|
|
264 return vm.saVM().getThreads().getPendingThreads(mon);
|
|
265 }
|
|
266
|
|
267 // returns List<JavaThread>
|
|
268 private List getWaitingThreads(ObjectMonitor mon) {
|
|
269 return vm.saVM().getThreads().getWaitingThreads(mon);
|
|
270 }
|
|
271
|
|
272 private JavaThread owningThreadFromMonitor(Address addr) {
|
|
273 return vm.saVM().getThreads().owningThreadFromMonitor(addr);
|
|
274 }
|
|
275
|
|
276 // refer to JvmtiEnv::GetObjectMonitorUsage
|
|
277 private void computeMonitorInfo() {
|
|
278 monitorInfoCached = true;
|
|
279 Mark mark = saObject.getMark();
|
|
280 ObjectMonitor mon = null;
|
|
281 Address owner = null;
|
|
282 // check for heavyweight monitor
|
|
283 if (! mark.hasMonitor()) {
|
|
284 // check for lightweight monitor
|
|
285 if (mark.hasLocker()) {
|
|
286 owner = mark.locker().getAddress(); // save the address of the Lock word
|
|
287 }
|
|
288 // implied else: no owner
|
|
289 } else {
|
|
290 // this object has a heavyweight monitor
|
|
291 mon = mark.monitor();
|
|
292
|
|
293 // The owner field of a heavyweight monitor may be NULL for no
|
|
294 // owner, a JavaThread * or it may still be the address of the
|
|
295 // Lock word in a JavaThread's stack. A monitor can be inflated
|
|
296 // by a non-owning JavaThread, but only the owning JavaThread
|
|
297 // can change the owner field from the Lock word to the
|
|
298 // JavaThread * and it may not have done that yet.
|
|
299 owner = mon.owner();
|
|
300 }
|
|
301
|
|
302 // find the owning thread
|
|
303 if (owner != null) {
|
|
304 owningThread = vm.threadMirror(owningThreadFromMonitor(owner));
|
|
305 }
|
|
306
|
|
307 // compute entryCount
|
|
308 if (owningThread != null) {
|
|
309 if (owningThread.getJavaThread().getAddress().equals(owner)) {
|
|
310 // the owner field is the JavaThread *
|
|
311 if (Assert.ASSERTS_ENABLED) {
|
|
312 Assert.that(false, "must have heavyweight monitor with JavaThread * owner");
|
|
313 }
|
|
314 entryCount = (int) mark.monitor().recursions() + 1;
|
|
315 } else {
|
|
316 // The owner field is the Lock word on the JavaThread's stack
|
|
317 // so the recursions field is not valid. We have to count the
|
|
318 // number of recursive monitor entries the hard way.
|
|
319 entryCount = countLockedObjects(owningThread.getJavaThread(), saObject);
|
|
320 }
|
|
321 }
|
|
322
|
|
323 // find the contenders & waiters
|
|
324 waitingThreads = new ArrayList();
|
|
325 if (mon != null) {
|
|
326 // this object has a heavyweight monitor. threads could
|
|
327 // be contenders or waiters
|
|
328 // add all contenders
|
|
329 List pendingThreads = getPendingThreads(mon);
|
|
330 // convert the JavaThreads to ThreadReferenceImpls
|
|
331 for (Iterator itrPend = pendingThreads.iterator(); itrPend.hasNext();) {
|
|
332 waitingThreads.add(vm.threadMirror((JavaThread) itrPend.next()));
|
|
333 }
|
|
334
|
|
335 // add all waiters (threads in Object.wait())
|
|
336 // note that we don't do this JVMTI way. To do it JVMTI way,
|
|
337 // we would need to access ObjectWaiter list maintained in
|
|
338 // ObjectMonitor::_queue. But we don't have this struct exposed
|
|
339 // in vmStructs. We do waiters list in a way similar to getting
|
|
340 // pending threads list
|
|
341 List objWaitingThreads = getWaitingThreads(mon);
|
|
342 // convert the JavaThreads to ThreadReferenceImpls
|
|
343 for (Iterator itrWait = objWaitingThreads.iterator(); itrWait.hasNext();) {
|
|
344 waitingThreads.add(vm.threadMirror((JavaThread) itrWait.next()));
|
|
345 }
|
|
346 }
|
|
347 }
|
|
348
|
|
349 public boolean equals(Object obj) {
|
|
350 if ((obj != null) && (obj instanceof ObjectReferenceImpl)) {
|
|
351 ObjectReferenceImpl other = (ObjectReferenceImpl)obj;
|
|
352 return (ref().equals(other.ref())) &&
|
|
353 super.equals(obj);
|
|
354 } else {
|
|
355 return false;
|
|
356 }
|
|
357 }
|
|
358
|
|
359 public int hashCode() {
|
|
360 return saObject.hashCode();
|
|
361 }
|
|
362
|
|
363 public String toString() {
|
|
364 return "instance of " + referenceType().name() + "(id=" + uniqueID() + ")";
|
|
365 }
|
|
366 }
|