Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
38920 views
1
/*
2
* Copyright (c) 1998, 2015, 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 & VirtualMachine.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<Field, Value> map = getValues(list);
167
return 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
* Method must be in this object's class, a superclass, or
282
* implemented interface
283
*/
284
ReferenceTypeImpl declType = (ReferenceTypeImpl)method.declaringType();
285
if (!declType.isAssignableFrom(this)) {
286
throw new IllegalArgumentException("Invalid method");
287
}
288
289
if (declType instanceof ClassTypeImpl) {
290
validateClassMethodInvocation(method, options);
291
} else if (declType instanceof InterfaceTypeImpl) {
292
validateIfaceMethodInvocation(method, options);
293
} else {
294
throw new InvalidTypeException();
295
}
296
}
297
298
void validateClassMethodInvocation(Method method, int options)
299
throws InvalidTypeException,
300
InvocationException {
301
302
ClassTypeImpl clazz = invokableReferenceType(method);
303
304
/*
305
* Method must be a non-constructor
306
*/
307
if (method.isConstructor()) {
308
throw new IllegalArgumentException("Cannot invoke constructor");
309
}
310
311
/*
312
* For nonvirtual invokes, method must have a body
313
*/
314
if (isNonVirtual(options)) {
315
if (method.isAbstract()) {
316
throw new IllegalArgumentException("Abstract method");
317
}
318
}
319
320
/*
321
* Get the class containing the method that will be invoked.
322
* This class is needed only for proper validation of the
323
* method argument types.
324
*/
325
ClassTypeImpl invokedClass;
326
if (isNonVirtual(options)) {
327
// No overrides in non-virtual invokes
328
invokedClass = clazz;
329
} else {
330
/*
331
* For virtual invokes, find any override of the method.
332
* Since we are looking for a method with a real body, we
333
* don't need to bother with interfaces/abstract methods.
334
*/
335
Method invoker = clazz.concreteMethodByName(method.name(),
336
method.signature());
337
// invoker is supposed to be non-null under normal circumstances
338
invokedClass = (ClassTypeImpl)invoker.declaringType();
339
}
340
/* The above code is left over from previous versions.
341
* We haven't had time to divine the intent. jjh, 7/31/2003
342
*/
343
}
344
345
void validateIfaceMethodInvocation(Method method, int options)
346
throws InvalidTypeException,
347
InvocationException {
348
/*
349
* Only default methods allowed for nonvirtual invokes
350
*/
351
if (isNonVirtual(options) && !method.isDefault()) {
352
throw new IllegalArgumentException("Not a default method");
353
}
354
}
355
356
PacketStream sendInvokeCommand(final ThreadReferenceImpl thread,
357
final ClassTypeImpl refType,
358
final MethodImpl method,
359
final ValueImpl[] args,
360
final int options) {
361
CommandSender sender =
362
new CommandSender() {
363
public PacketStream send() {
364
return JDWP.ObjectReference.InvokeMethod.enqueueCommand(
365
vm, ObjectReferenceImpl.this,
366
thread, refType,
367
method.ref(), args, options);
368
}
369
};
370
371
PacketStream stream;
372
if ((options & INVOKE_SINGLE_THREADED) != 0) {
373
stream = thread.sendResumingCommand(sender);
374
} else {
375
stream = vm.sendResumingCommand(sender);
376
}
377
return stream;
378
}
379
380
public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
381
List<? extends Value> origArguments, int options)
382
throws InvalidTypeException,
383
IncompatibleThreadStateException,
384
InvocationException,
385
ClassNotLoadedException {
386
validateMirror(threadIntf);
387
validateMirror(methodIntf);
388
validateMirrorsOrNulls(origArguments);
389
390
MethodImpl method = (MethodImpl)methodIntf;
391
ThreadReferenceImpl thread = (ThreadReferenceImpl)threadIntf;
392
393
if (method.isStatic()) {
394
if (referenceType() instanceof InterfaceType) {
395
InterfaceType type = (InterfaceType)referenceType();
396
return type.invokeMethod(thread, method, origArguments, options);
397
} else if (referenceType() instanceof ClassType) {
398
ClassType type = (ClassType)referenceType();
399
return type.invokeMethod(thread, method, origArguments, options);
400
} else {
401
throw new IllegalArgumentException("Invalid type for static method invocation");
402
}
403
}
404
405
validateMethodInvocation(method, options);
406
407
List<Value> arguments = method.validateAndPrepareArgumentsForInvoke(
408
origArguments);
409
410
ValueImpl[] args = arguments.toArray(new ValueImpl[0]);
411
JDWP.ObjectReference.InvokeMethod ret;
412
try {
413
PacketStream stream =
414
sendInvokeCommand(thread, invokableReferenceType(method),
415
method, args, options);
416
ret = JDWP.ObjectReference.InvokeMethod.waitForReply(vm, stream);
417
} catch (JDWPException exc) {
418
if (exc.errorCode() == JDWP.Error.INVALID_THREAD) {
419
throw new IncompatibleThreadStateException();
420
} else {
421
throw exc.toJDIException();
422
}
423
}
424
425
/*
426
* There is an implict VM-wide suspend at the conclusion
427
* of a normal (non-single-threaded) method invoke
428
*/
429
if ((options & INVOKE_SINGLE_THREADED) == 0) {
430
vm.notifySuspend();
431
}
432
433
if (ret.exception != null) {
434
throw new InvocationException(ret.exception);
435
} else {
436
return ret.returnValue;
437
}
438
}
439
440
/* leave synchronized to keep count accurate */
441
public synchronized void disableCollection() {
442
if (gcDisableCount == 0) {
443
try {
444
JDWP.ObjectReference.DisableCollection.process(vm, this);
445
} catch (JDWPException exc) {
446
throw exc.toJDIException();
447
}
448
}
449
gcDisableCount++;
450
}
451
452
/* leave synchronized to keep count accurate */
453
public synchronized void enableCollection() {
454
gcDisableCount--;
455
456
if (gcDisableCount == 0) {
457
try {
458
JDWP.ObjectReference.EnableCollection.process(vm, this);
459
} catch (JDWPException exc) {
460
// If already collected, no harm done, no exception
461
if (exc.errorCode() != JDWP.Error.INVALID_OBJECT) {
462
throw exc.toJDIException();
463
}
464
return;
465
}
466
}
467
}
468
469
public boolean isCollected() {
470
try {
471
return JDWP.ObjectReference.IsCollected.process(vm, this).
472
isCollected;
473
} catch (JDWPException exc) {
474
throw exc.toJDIException();
475
}
476
}
477
478
public long uniqueID() {
479
return ref();
480
}
481
482
JDWP.ObjectReference.MonitorInfo jdwpMonitorInfo()
483
throws IncompatibleThreadStateException {
484
JDWP.ObjectReference.MonitorInfo info = null;
485
try {
486
Cache local;
487
488
// getCache() and addlistener() must be synchronized
489
// so that no events are lost.
490
synchronized (vm.state()) {
491
local = getCache();
492
493
if (local != null) {
494
info = local.monitorInfo;
495
496
// Check if there will be something to cache
497
// and there is not already a listener
498
if (info == null && !vm.state().hasListener(this)) {
499
/* For other, less numerous objects, this is done
500
* in the constructor. Since there can be many
501
* ObjectReferences, the VM listener is installed
502
* and removed as needed.
503
* Listener must be installed before process()
504
*/
505
vm.state().addListener(this);
506
addedListener = true;
507
}
508
}
509
}
510
if (info == null) {
511
info = JDWP.ObjectReference.MonitorInfo.process(vm, this);
512
if (local != null) {
513
local.monitorInfo = info;
514
if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) {
515
vm.printTrace("ObjectReference " + uniqueID() +
516
" temporarily caching monitor info");
517
}
518
}
519
}
520
} catch (JDWPException exc) {
521
if (exc.errorCode() == JDWP.Error.THREAD_NOT_SUSPENDED) {
522
throw new IncompatibleThreadStateException();
523
} else {
524
throw exc.toJDIException();
525
}
526
}
527
return info;
528
}
529
530
public List<ThreadReference> waitingThreads() throws IncompatibleThreadStateException {
531
return Arrays.asList((ThreadReference[])jdwpMonitorInfo().waiters);
532
}
533
534
public ThreadReference owningThread() throws IncompatibleThreadStateException {
535
return jdwpMonitorInfo().owner;
536
}
537
538
public int entryCount() throws IncompatibleThreadStateException {
539
return jdwpMonitorInfo().entryCount;
540
}
541
542
543
public List<ObjectReference> referringObjects(long maxReferrers) {
544
if (!vm.canGetInstanceInfo()) {
545
throw new UnsupportedOperationException(
546
"target does not support getting referring objects");
547
}
548
549
if (maxReferrers < 0) {
550
throw new IllegalArgumentException("maxReferrers is less than zero: "
551
+ maxReferrers);
552
}
553
554
int intMax = (maxReferrers > Integer.MAX_VALUE)?
555
Integer.MAX_VALUE: (int)maxReferrers;
556
// JDWP can't currently handle more than this (in mustang)
557
558
try {
559
return Arrays.asList((ObjectReference[])JDWP.ObjectReference.ReferringObjects.
560
process(vm, this, intMax).referringObjects);
561
} catch (JDWPException exc) {
562
throw exc.toJDIException();
563
}
564
}
565
566
long ref() {
567
return ref;
568
}
569
570
boolean isClassObject() {
571
/*
572
* Don't need to worry about subclasses since java.lang.Class is final.
573
*/
574
return referenceType().name().equals("java.lang.Class");
575
}
576
577
ValueImpl prepareForAssignmentTo(ValueContainer destination)
578
throws InvalidTypeException,
579
ClassNotLoadedException {
580
581
validateAssignment(destination);
582
return this; // conversion never necessary
583
}
584
585
void validateAssignment(ValueContainer destination)
586
throws InvalidTypeException, ClassNotLoadedException {
587
588
/*
589
* Do these simpler checks before attempting a query of the destination's
590
* type which might cause a confusing ClassNotLoadedException if
591
* the destination is primitive or an array.
592
*/
593
/*
594
* TO DO: Centralize JNI signature knowledge
595
*/
596
if (destination.signature().length() == 1) {
597
throw new InvalidTypeException("Can't assign object value to primitive");
598
}
599
if ((destination.signature().charAt(0) == '[') &&
600
(type().signature().charAt(0) != '[')) {
601
throw new InvalidTypeException("Can't assign non-array value to an array");
602
}
603
if ("void".equals(destination.typeName())) {
604
throw new InvalidTypeException("Can't assign object value to a void");
605
}
606
607
// Validate assignment
608
ReferenceType destType = (ReferenceTypeImpl)destination.type();
609
ReferenceTypeImpl myType = (ReferenceTypeImpl)referenceType();
610
if (!myType.isAssignableTo(destType)) {
611
JNITypeParser parser = new JNITypeParser(destType.signature());
612
String destTypeName = parser.typeName();
613
throw new InvalidTypeException("Can't assign " +
614
type().name() +
615
" to " + destTypeName);
616
}
617
}
618
619
620
public String toString() {
621
return "instance of " + referenceType().name() + "(id=" + uniqueID() + ")";
622
}
623
624
byte typeValueKey() {
625
return JDWP.Tag.OBJECT;
626
}
627
628
private static boolean isNonVirtual(int options) {
629
return (options & INVOKE_NONVIRTUAL) != 0;
630
}
631
}
632
633