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