History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/jdi/ObjectReferenceImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/jdi/ObjectReferenceImpl.java+603−0
@@ -0,0 +1,603 @@
1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.jdi;
27
28import com.sun.jdi.*;
29
30import java.util.*;
31import java.util.ArrayList;
32
33public class ObjectReferenceImpl extends ValueImpl
34 implements ObjectReference, VMListener {
35
36 protected long ref;
37 private ReferenceType type = null;
38 private int gcDisableCount = 0;
39 boolean addedListener = false;
40
41 // This is cached only while the VM is suspended
42 protected static class Cache {
43 JDWP.ObjectReference.MonitorInfo monitorInfo = null;
44 }
45
46 private static final Cache noInitCache = new Cache();
47 private static final Cache markerCache = new Cache();
48 private Cache cache = noInitCache;
49
50 private void disableCache() {
51 synchronized (vm.state()) {
52 cache = null;
53 }
54 }
55
56 private void enableCache() {
57 synchronized (vm.state()) {
58 cache = markerCache;
59 }
60 }
61
62 // Override in subclasses
63 protected Cache newCache() {
64 return new Cache();
65 }
66
67 protected Cache getCache() {
68 synchronized (vm.state()) {
69 if (cache == noInitCache) {
70 if (vm.state().isSuspended()) {
71 // Set cache now, otherwise newly created objects are
72 // not cached until resuspend
73 enableCache();
74 } else {
75 disableCache();
76 }
77 }
78 if (cache == markerCache) {
79 cache = newCache();
80 }
81 return cache;
82 }
83 }
84
85 // Return the ClassTypeImpl upon which to invoke a method.
86 // By default it is our very own referenceType() but subclasses
87 // can override.
88 protected ClassTypeImpl invokableReferenceType(Method method) {
89 return (ClassTypeImpl)referenceType();
90 }
91
92 ObjectReferenceImpl(VirtualMachine aVm,long aRef) {
93 super(aVm);
94
95 ref = aRef;
96 }
97
98 protected String description() {
99 return "ObjectReference " + uniqueID();
100 }
101
102 /*
103 * VMListener implementation
104 */
105 public boolean vmSuspended(VMAction action) {
106 enableCache();
107 return true;
108 }
109
110 public boolean vmNotSuspended(VMAction action) {
111 // make sure that cache and listener management are synchronized
112 synchronized (vm.state()) {
113 if (cache != null && (vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
114 vm.printTrace("Clearing temporary cache for " + description());
115 }
116 disableCache();
117 if (addedListener) {
118 /*
119 * If a listener was added (i.e. this is not a
120 * ObjectReference that adds a listener on startup),
121 * remove it here.
122 */
123 addedListener = false;
124 return false; // false says remove
125 } else {
126 return true;
127 }
128 }
129 }
130
131 public boolean equals(Object obj) {
132 if ((obj != null) && (obj instanceof ObjectReferenceImpl)) {
133 ObjectReferenceImpl other = (ObjectReferenceImpl)obj;
134 return (ref() == other.ref()) &&
135 super.equals(obj);
136 } else {
137 return false;
138 }
139 }
140
141 public int hashCode() {
142 return(int)ref();
143 }
144
145 public Type type() {
146 return referenceType();
147 }
148
149 public ReferenceType referenceType() {
150 if (type == null) {
151 try {
152 JDWP.ObjectReference.ReferenceType rtinfo =
153 JDWP.ObjectReference.ReferenceType.process(vm, this);
154 type = vm.referenceType(rtinfo.typeID,
155 rtinfo.refTypeTag);
156 } catch (JDWPException exc) {
157 throw exc.toJDIException();
158 }
159 }
160 return type;
161 }
162
163 public Value getValue(Field sig) {
164 List<Field> list = new ArrayList<Field>(1);
165 list.add(sig);
166 Map map = getValues(list);
167 return(Value)map.get(sig);
168 }
169
170 public Map<Field,Value> getValues(List<? extends Field> theFields) {
171 validateMirrors(theFields);
172
173 List<Field> staticFields = new ArrayList<Field>(0);
174 int size = theFields.size();
175 List<Field> instanceFields = new ArrayList<Field>(size);
176
177 for (int i=0; i<size; i++) {
178 Field field = (Field)theFields.get(i);
179
180 // Make sure the field is valid
181 ((ReferenceTypeImpl)referenceType()).validateFieldAccess(field);
182
183 // FIX ME! We need to do some sanity checking
184 // here; make sure the field belongs to this
185 // object.
186 if (field.isStatic())
187 staticFields.add(field);
188 else {
189 instanceFields.add(field);
190 }
191 }
192
193 Map<Field, Value> map;
194 if (staticFields.size() > 0) {
195 map = referenceType().getValues(staticFields);
196 } else {
197 map = new HashMap<Field, Value>(size);
198 }
199
200 size = instanceFields.size();
201
202 JDWP.ObjectReference.GetValues.Field[] queryFields =
203 new JDWP.ObjectReference.GetValues.Field[size];
204 for (int i=0; i<size; i++) {
205 FieldImpl field = (FieldImpl)instanceFields.get(i);/* thanks OTI */
206 queryFields[i] = new JDWP.ObjectReference.GetValues.Field(
207 field.ref());
208 }
209 ValueImpl[] values;
210 try {
211 values = JDWP.ObjectReference.GetValues.
212 process(vm, this, queryFields).values;
213 } catch (JDWPException exc) {
214 throw exc.toJDIException();
215 }
216
217 if (size != values.length) {
218 throw new InternalException(
219 "Wrong number of values returned from target VM");
220 }
221 for (int i=0; i<size; i++) {
222 FieldImpl field = (FieldImpl)instanceFields.get(i);
223 map.put(field, values[i]);
224 }
225
226 return map;
227 }
228
229 public void setValue(Field field, Value value)
230 throws InvalidTypeException, ClassNotLoadedException {
231
232 validateMirror(field);
233 validateMirrorOrNull(value);
234
235 // Make sure the field is valid
236 ((ReferenceTypeImpl)referenceType()).validateFieldSet(field);
237
238 if (field.isStatic()) {
239 ReferenceType type = referenceType();
240 if (type instanceof ClassType) {
241 ((ClassType)type).setValue(field, value);
242 return;
243 } else {
244 throw new IllegalArgumentException(
245 "Invalid type for static field set");
246 }
247 }
248
249 try {
250 JDWP.ObjectReference.SetValues.FieldValue[] fvals =
251 new JDWP.ObjectReference.SetValues.FieldValue[1];
252 fvals[0] = new JDWP.ObjectReference.SetValues.FieldValue(
253 ((FieldImpl)field).ref(),
254 // Validate and convert if necessary
255 ValueImpl.prepareForAssignment(value,
256 (FieldImpl)field));
257 try {
258 JDWP.ObjectReference.SetValues.process(vm, this, fvals);
259 } catch (JDWPException exc) {
260 throw exc.toJDIException();
261 }
262 } catch (ClassNotLoadedException e) {
263 /*
264 * Since we got this exception,
265 * the field type must be a reference type. The value
266 * we're trying to set is null, but if the field's
267 * class has not yet been loaded through the enclosing
268 * class loader, then setting to null is essentially a
269 * no-op, and we should allow it without an exception.
270 */
271 if (value != null) {
272 throw e;
273 }
274 }
275 }
276
277 void validateMethodInvocation(Method method, int options)
278 throws InvalidTypeException,
279 InvocationException {
280
281 /*
282 * Method must be in this object's class, a superclass, or
283 * implemented interface
284 */
285 ReferenceTypeImpl declType = (ReferenceTypeImpl)method.declaringType();
286 if (!declType.isAssignableFrom(this)) {
287 throw new IllegalArgumentException("Invalid method");
288 }
289
290 ClassTypeImpl clazz = invokableReferenceType(method);
291
292 /*
293 * Method must be a non-constructor
294 */
295 if (method.isConstructor()) {
296 throw new IllegalArgumentException("Cannot invoke constructor");
297 }
298
299 /*
300 * For nonvirtual invokes, method must have a body
301 */
302 if ((options & INVOKE_NONVIRTUAL) != 0) {
303 if (method.declaringType() instanceof InterfaceType) {
304 throw new IllegalArgumentException("Interface method");
305 } else if (method.isAbstract()) {
306 throw new IllegalArgumentException("Abstract method");
307 }
308 }
309
310 /*
311 * Get the class containing the method that will be invoked.
312 * This class is needed only for proper validation of the
313 * method argument types.
314 */
315 ClassTypeImpl invokedClass;
316 if ((options & INVOKE_NONVIRTUAL) != 0) {
317 // No overrides in non-virtual invokes
318 invokedClass = clazz;
319 } else {
320 /*
321 * For virtual invokes, find any override of the method.
322 * Since we are looking for a method with a real body, we
323 * don't need to bother with interfaces/abstract methods.
324 */
325 Method invoker = clazz.concreteMethodByName(method.name(),
326 method.signature());
327 // isAssignableFrom check above guarantees non-null
328 invokedClass = (ClassTypeImpl)invoker.declaringType();
329 }
330 /* The above code is left over from previous versions.
331 * We haven't had time to divine the intent. jjh, 7/31/2003
332 */
333 }
334
335 PacketStream sendInvokeCommand(final ThreadReferenceImpl thread,
336 final ClassTypeImpl refType,
337 final MethodImpl method,
338 final ValueImpl[] args,
339 final int options) {
340 CommandSender sender =
341 new CommandSender() {
342 public PacketStream send() {
343 return JDWP.ObjectReference.InvokeMethod.enqueueCommand(
344 vm, ObjectReferenceImpl.this,
345 thread, refType,
346 method.ref(), args, options);
347 }
348 };
349
350 PacketStream stream;
351 if ((options & INVOKE_SINGLE_THREADED) != 0) {
352 stream = thread.sendResumingCommand(sender);
353 } else {
354 stream = vm.sendResumingCommand(sender);
355 }
356 return stream;
357 }
358
359 public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
360 List<? extends Value> origArguments, int options)
361 throws InvalidTypeException,
362 IncompatibleThreadStateException,
363 InvocationException,
364 ClassNotLoadedException {
365 validateMirror(threadIntf);
366 validateMirror(methodIntf);
367 validateMirrorsOrNulls(origArguments);
368
369 MethodImpl method = (MethodImpl)methodIntf;
370 ThreadReferenceImpl thread = (ThreadReferenceImpl)threadIntf;
371
372 if (method.isStatic()) {
373 if (referenceType() instanceof ClassType) {
374 ClassType type = (ClassType)referenceType();
375 return type.invokeMethod(thread, method, origArguments, options);
376 } else {
377 throw new IllegalArgumentException("Invalid type for static method invocation");
378 }
379 }
380
381 validateMethodInvocation(method, options);
382
383 List<Value> arguments = method.validateAndPrepareArgumentsForInvoke(
384 origArguments);
385
386 ValueImpl[] args = arguments.toArray(new ValueImpl[0]);
387 JDWP.ObjectReference.InvokeMethod ret;
388 try {
389 PacketStream stream =
390 sendInvokeCommand(thread, invokableReferenceType(method),
391 method, args, options);
392 ret = JDWP.ObjectReference.InvokeMethod.waitForReply(vm, stream);
393 } catch (JDWPException exc) {
394 if (exc.errorCode() == JDWP.Error.INVALID_THREAD) {
395 throw new IncompatibleThreadStateException();
396 } else {
397 throw exc.toJDIException();
398 }
399 }
400
401 /*
402 * There is an implict VM-wide suspend at the conclusion
403 * of a normal (non-single-threaded) method invoke
404 */
405 if ((options & INVOKE_SINGLE_THREADED) == 0) {
406 vm.notifySuspend();
407 }
408
409 if (ret.exception != null) {
410 throw new InvocationException(ret.exception);
411 } else {
412 return ret.returnValue;
413 }
414 }
415
416 /* leave synchronized to keep count accurate */
417 public synchronized void disableCollection() {
418 if (gcDisableCount == 0) {
419 try {
420 JDWP.ObjectReference.DisableCollection.process(vm, this);
421 } catch (JDWPException exc) {
422 throw exc.toJDIException();
423 }
424 }
425 gcDisableCount++;
426 }
427
428 /* leave synchronized to keep count accurate */
429 public synchronized void enableCollection() {
430 gcDisableCount--;
431
432 if (gcDisableCount == 0) {
433 try {
434 JDWP.ObjectReference.EnableCollection.process(vm, this);
435 } catch (JDWPException exc) {
436 // If already collected, no harm done, no exception
437 if (exc.errorCode() != JDWP.Error.INVALID_OBJECT) {
438 throw exc.toJDIException();
439 }
440 return;
441 }
442 }
443 }
444
445 public boolean isCollected() {
446 try {
447 return JDWP.ObjectReference.IsCollected.process(vm, this).
448 isCollected;
449 } catch (JDWPException exc) {
450 throw exc.toJDIException();
451 }
452 }
453
454 public long uniqueID() {
455 return ref();
456 }
457
458 JDWP.ObjectReference.MonitorInfo jdwpMonitorInfo()
459 throws IncompatibleThreadStateException {
460 JDWP.ObjectReference.MonitorInfo info = null;
461 try {
462 Cache local;
463
464 // getCache() and addlistener() must be synchronized
465 // so that no events are lost.
466 synchronized (vm.state()) {
467 local = getCache();
468
469 if (local != null) {
470 info = local.monitorInfo;
471
472 // Check if there will be something to cache
473 // and there is not already a listener
474 if (info == null && !vm.state().hasListener(this)) {
475 /* For other, less numerous objects, this is done
476 * in the constructor. Since there can be many
477 * ObjectReferences, the VM listener is installed
478 * and removed as needed.
479 * Listener must be installed before process()
480 */
481 vm.state().addListener(this);
482 addedListener = true;
483 }
484 }
485 }
486 if (info == null) {
487 info = JDWP.ObjectReference.MonitorInfo.process(vm, this);
488 if (local != null) {
489 local.monitorInfo = info;
490 if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
491 vm.printTrace("ObjectReference " + uniqueID() +
492 " temporarily caching monitor info");
493 }
494 }
495 }
496 } catch (JDWPException exc) {
497 if (exc.errorCode() == JDWP.Error.THREAD_NOT_SUSPENDED) {
498 throw new IncompatibleThreadStateException();
499 } else {
500 throw exc.toJDIException();
501 }
502 }
503 return info;
504 }
505
506 public List<ThreadReference> waitingThreads() throws IncompatibleThreadStateException {
507 return Arrays.asList((ThreadReference[])jdwpMonitorInfo().waiters);
508 }
509
510 public ThreadReference owningThread() throws IncompatibleThreadStateException {
511 return jdwpMonitorInfo().owner;
512 }
513
514 public int entryCount() throws IncompatibleThreadStateException {
515 return jdwpMonitorInfo().entryCount;
516 }
517
518
519 public List<ObjectReference> referringObjects(long maxReferrers) {
520 if (!vm.canGetInstanceInfo()) {
521 throw new UnsupportedOperationException(
522 "target does not support getting referring objects");
523 }
524
525 if (maxReferrers < 0) {
526 throw new IllegalArgumentException("maxReferrers is less than zero: "
527 + maxReferrers);
528 }
529
530 int intMax = (maxReferrers > Integer.MAX_VALUE)?
531 Integer.MAX_VALUE: (int)maxReferrers;
532 // JDWP can't currently handle more than this (in mustang)
533
534 try {
535 return Arrays.asList((ObjectReference[])JDWP.ObjectReference.ReferringObjects.
536 process(vm, this, intMax).referringObjects);
537 } catch (JDWPException exc) {
538 throw exc.toJDIException();
539 }
540 }
541
542 long ref() {
543 return ref;
544 }
545
546 boolean isClassObject() {
547 /*
548 * Don't need to worry about subclasses since java.lang.Class is final.
549 */
550 return referenceType().name().equals("java.lang.Class");
551 }
552
553 ValueImpl prepareForAssignmentTo(ValueContainer destination)
554 throws InvalidTypeException,
555 ClassNotLoadedException {
556
557 validateAssignment(destination);
558 return this; // conversion never necessary
559 }
560
561 void validateAssignment(ValueContainer destination)
562 throws InvalidTypeException, ClassNotLoadedException {
563
564 /*
565 * Do these simpler checks before attempting a query of the destination's
566 * type which might cause a confusing ClassNotLoadedException if
567 * the destination is primitive or an array.
568 */
569 /*
570 * TO DO: Centralize JNI signature knowledge
571 */
572 if (destination.signature().length() == 1) {
573 throw new InvalidTypeException("Can't assign object value to primitive");
574 }
575 if ((destination.signature().charAt(0) == '[') &&
576 (type().signature().charAt(0) != '[')) {
577 throw new InvalidTypeException("Can't assign non-array value to an array");
578 }
579 if ("void".equals(destination.typeName())) {
580 throw new InvalidTypeException("Can't assign object value to a void");
581 }
582
583 // Validate assignment
584 ReferenceType destType = (ReferenceTypeImpl)destination.type();
585 ReferenceTypeImpl myType = (ReferenceTypeImpl)referenceType();
586 if (!myType.isAssignableTo(destType)) {
587 JNITypeParser parser = new JNITypeParser(destType.signature());
588 String destTypeName = parser.typeName();
589 throw new InvalidTypeException("Can't assign " +
590 type().name() +
591 " to " + destTypeName);
592 }
593 }
594
595
596 public String toString() {
597 return "instance of " + referenceType().name() + "(id=" + uniqueID() + ")";
598 }
599
600 byte typeValueKey() {
601 return JDWP.Tag.OBJECT;
602 }
603}