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+
26+package com.sun.tools.jdi;
27+
28+import com.sun.jdi.*;
29+
30+import java.util.*;
31+import java.util.ArrayList;
32+
33+public 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+}