1 /* 2 * Copyright (c) 1998, 2019, 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.lang.ref.Reference; 29 import java.lang.ref.ReferenceQueue; 30 import java.lang.ref.SoftReference; 31 import java.text.MessageFormat; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.HashMap; 36 import java.util.HashSet; 37 import java.util.Iterator; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Set; 41 import java.util.function.Consumer; 42 43 import com.sun.jdi.BooleanType; 44 import com.sun.jdi.BooleanValue; 45 import com.sun.jdi.ByteType; 46 import com.sun.jdi.ByteValue; 47 import com.sun.jdi.CharType; 48 import com.sun.jdi.CharValue; 49 import com.sun.jdi.ClassLoaderReference; 50 import com.sun.jdi.ClassNotLoadedException; 51 import com.sun.jdi.DoubleType; 52 import com.sun.jdi.DoubleValue; 53 import com.sun.jdi.FloatType; 54 import com.sun.jdi.FloatValue; 55 import com.sun.jdi.IntegerType; 56 import com.sun.jdi.IntegerValue; 57 import com.sun.jdi.InternalException; 58 import com.sun.jdi.LongType; 59 import com.sun.jdi.LongValue; 60 import com.sun.jdi.ModuleReference; 61 import com.sun.jdi.ObjectCollectedException; 62 import com.sun.jdi.PathSearchingVirtualMachine; 63 import com.sun.jdi.PrimitiveType; 64 import com.sun.jdi.ReferenceType; 65 import com.sun.jdi.ShortType; 66 import com.sun.jdi.ShortValue; 67 import com.sun.jdi.StringReference; 68 import com.sun.jdi.ThreadGroupReference; 69 import com.sun.jdi.ThreadReference; 70 import com.sun.jdi.Type; 71 import com.sun.jdi.VMDisconnectedException; 72 import com.sun.jdi.VirtualMachine; 73 import com.sun.jdi.VirtualMachineManager; 74 import com.sun.jdi.VoidType; 75 import com.sun.jdi.VoidValue; 76 import com.sun.jdi.connect.spi.Connection; 77 import com.sun.jdi.event.EventQueue; 78 import com.sun.jdi.request.BreakpointRequest; 79 import com.sun.jdi.request.EventRequest; 80 import com.sun.jdi.request.EventRequestManager; 81 82 class VirtualMachineImpl extends MirrorImpl 83 implements PathSearchingVirtualMachine, ThreadListener { 84 // VM Level exported variables, these 85 // are unique to a given vm 86 public final int sizeofFieldRef; 87 public final int sizeofMethodRef; 88 public final int sizeofObjectRef; 89 public final int sizeofClassRef; 90 public final int sizeofFrameRef; 91 public final int sizeofModuleRef; 92 93 final int sequenceNumber; 94 95 private final TargetVM target; 96 private final EventQueueImpl eventQueue; 97 private final EventRequestManagerImpl internalEventRequestManager; 98 private final EventRequestManagerImpl eventRequestManager; 99 final VirtualMachineManagerImpl vmManager; 100 private final ThreadGroup threadGroupForJDI; 101 102 // Allow direct access to this field so that that tracing code slows down 103 // JDI as little as possible when not enabled. 104 int traceFlags = TRACE_NONE; 105 106 static int TRACE_RAW_SENDS = 0x01000000; 107 static int TRACE_RAW_RECEIVES = 0x02000000; 108 109 boolean traceReceives = false; // pre-compute because of frequency 110 111 // ReferenceType access - updated with class prepare and unload events 112 // Protected by "synchronized(this)". "retrievedAllTypes" may be 113 // tested unsynchronized (since once true, it stays true), but must 114 // be set synchronously 115 private Map<Long, ReferenceType> typesByID; 116 private Set<ReferenceType> typesBySignature; 117 private boolean retrievedAllTypes = false; 118 119 private Map<Long, ModuleReference> modulesByID; 120 121 // For other languages support 122 private String defaultStratum = null; 123 124 // ObjectReference cache 125 // "objectsByID" protected by "synchronized(this)". 126 private final Map<Long, SoftObjectReference> objectsByID = new HashMap<>(); 127 private final ReferenceQueue<ObjectReferenceImpl> referenceQueue = new ReferenceQueue<>(); 128 static private final int DISPOSE_THRESHOLD = 50; 129 private final List<SoftObjectReference> batchedDisposeRequests = 130 Collections.synchronizedList(new ArrayList<>(DISPOSE_THRESHOLD + 10)); 131 132 // These are cached once for the life of the VM 133 private JDWP.VirtualMachine.Version versionInfo; 134 private JDWP.VirtualMachine.ClassPaths pathInfo; 135 private JDWP.VirtualMachine.Capabilities capabilities = null; 136 private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew = null; 137 138 // Per-vm singletons for primitive types and for void. 139 // singleton-ness protected by "synchronized(this)". 140 private BooleanType theBooleanType; 141 private ByteType theByteType; 142 private CharType theCharType; 143 private ShortType theShortType; 144 private IntegerType theIntegerType; 145 private LongType theLongType; 146 private FloatType theFloatType; 147 private DoubleType theDoubleType; 148 149 private VoidType theVoidType; 150 151 private VoidValue voidVal; 152 153 // Launched debuggee process 154 private Process process; 155 156 // coordinates state changes and corresponding listener notifications 157 private VMState state = new VMState(this); 158 159 private Object initMonitor = new Object(); 160 private boolean initComplete = false; 161 private boolean shutdown = false; 162 163 private void notifyInitCompletion() { 164 synchronized(initMonitor) { 165 initComplete = true; 166 initMonitor.notifyAll(); 167 } 168 } 169 170 void waitInitCompletion() { 171 synchronized(initMonitor) { 172 while (!initComplete) { 173 try { 174 initMonitor.wait(); 175 } catch (InterruptedException e) { 176 // ignore 177 } 178 } 179 } 180 } 181 182 VMState state() { 183 return state; 184 } 185 186 /* 187 * ThreadListener implementation 188 */ 189 public boolean threadResumable(ThreadAction action) { 190 /* 191 * If any thread is resumed, the VM is considered not suspended. 192 * Just one thread is being resumed so pass it to thaw. 193 */ 194 state.thaw(action.thread()); 195 return true; 196 } 197 198 VirtualMachineImpl(VirtualMachineManager manager, 199 Connection connection, Process process, 200 int sequenceNumber) { 201 super(null); // Can't use super(this) 202 vm = this; 203 204 this.vmManager = (VirtualMachineManagerImpl)manager; 205 this.process = process; 206 this.sequenceNumber = sequenceNumber; 207 208 /* Create ThreadGroup to be used by all threads servicing 209 * this VM. 210 */ 211 threadGroupForJDI = new ThreadGroup(vmManager.mainGroupForJDI(), 212 "JDI [" + 213 this.hashCode() + "]"); 214 215 /* 216 * Set up a thread to communicate with the target VM over 217 * the specified transport. 218 */ 219 target = new TargetVM(this, connection); 220 221 /* 222 * Set up a thread to handle events processed internally 223 * the JDI implementation. 224 */ 225 EventQueueImpl internalEventQueue = new EventQueueImpl(this, target); 226 new InternalEventHandler(this, internalEventQueue); 227 /* 228 * Initialize client access to event setting and handling 229 */ 230 eventQueue = new EventQueueImpl(this, target); 231 eventRequestManager = new EventRequestManagerImpl(this); 232 233 target.start(); 234 235 /* 236 * Many ids are variably sized, depending on target VM. 237 * Find out the sizes right away. 238 */ 239 JDWP.VirtualMachine.IDSizes idSizes; 240 try { 241 idSizes = JDWP.VirtualMachine.IDSizes.process(vm); 242 } catch (JDWPException exc) { 243 throw exc.toJDIException(); 244 } 245 sizeofFieldRef = idSizes.fieldIDSize; 246 sizeofMethodRef = idSizes.methodIDSize; 247 sizeofObjectRef = idSizes.objectIDSize; 248 sizeofClassRef = idSizes.referenceTypeIDSize; 249 sizeofFrameRef = idSizes.frameIDSize; 250 sizeofModuleRef = idSizes.objectIDSize; 251 252 /** 253 * Set up requests needed by internal event handler. 254 * Make sure they are distinguished by creating them with 255 * an internal event request manager. 256 * 257 * Warning: create events only with SUSPEND_NONE policy. 258 * In the current implementation other policies will not 259 * be handled correctly when the event comes in. (notfiySuspend() 260 * will not be properly called, and if the event is combined 261 * with external events in the same set, suspend policy is not 262 * correctly determined for the internal vs. external event sets) 263 */ 264 internalEventRequestManager = new EventRequestManagerImpl(this); 265 EventRequest er = internalEventRequestManager.createClassPrepareRequest(); 266 er.setSuspendPolicy(EventRequest.SUSPEND_NONE); 267 er.enable(); 268 er = internalEventRequestManager.createClassUnloadRequest(); 269 er.setSuspendPolicy(EventRequest.SUSPEND_NONE); 270 er.enable(); 271 272 /* 273 * Tell other threads, notably TargetVM, that initialization 274 * is complete. 275 */ 276 notifyInitCompletion(); 277 } 278 279 EventRequestManagerImpl getInternalEventRequestManager() { 280 return internalEventRequestManager; 281 } 282 283 void validateVM() { 284 /* 285 * We no longer need to do this. The spec now says 286 * that a VMDisconnected _may_ be thrown in these 287 * cases, not that it _will_ be thrown. 288 * So, to simplify things we will just let the 289 * caller's of this method proceed with their business. 290 * If the debuggee is disconnected, either because it 291 * crashed or finished or something, or because the 292 * debugger called exit() or dispose(), then if 293 * we end up trying to communicate with the debuggee, 294 * code in TargetVM will throw a VMDisconnectedException. 295 * This means that if we can satisfy a request without 296 * talking to the debuggee, (eg, with cached data) then 297 * VMDisconnectedException will _not_ be thrown. 298 * if (shutdown) { 299 * throw new VMDisconnectedException(); 300 * } 301 */ 302 } 303 304 public boolean equals(Object obj) { 305 return this == obj; 306 } 307 308 public int hashCode() { 309 return System.identityHashCode(this); 310 } 311 312 public List<ModuleReference> allModules() { 313 validateVM(); 314 List<ModuleReference> modules = retrieveAllModules(); 315 return Collections.unmodifiableList(modules); 316 } 317 318 List<ReferenceType> classesBySignature(String signature) { 319 validateVM(); 320 List<ReferenceType> list; 321 if (retrievedAllTypes) { 322 list = findReferenceTypes(signature); 323 } else { 324 list = retrieveClassesBySignature(signature); 325 } 326 return Collections.unmodifiableList(list); 327 } 328 329 public List<ReferenceType> classesByName(String className) { 330 validateVM(); 331 String signature = JNITypeParser.typeNameToSignature(className); 332 List<ReferenceType> list; 333 if (retrievedAllTypes) { 334 list = findReferenceTypes(signature); 335 } else { 336 list = retrieveClassesBySignature(signature); 337 } 338 return Collections.unmodifiableList(list); 339 } 340 341 public List<ReferenceType> allClasses() { 342 validateVM(); 343 344 if (!retrievedAllTypes) { 345 retrieveAllClasses(); 346 } 347 ArrayList<ReferenceType> a; 348 synchronized (this) { 349 a = new ArrayList<>(typesBySignature); 350 } 351 return Collections.unmodifiableList(a); 352 } 353 354 /** 355 * Performs an action for each loaded type. 356 */ 357 public void forEachClass(Consumer<ReferenceType> action) { 358 for (ReferenceType type : allClasses()) { 359 try { 360 action.accept(type); 361 } catch (ObjectCollectedException ex) { 362 // Some classes might be unloaded and garbage collected since 363 // we retrieved the copy of all loaded classes and started 364 // iterating over them. In this case calling methods on such types 365 // might result in com.sun.jdi.ObjectCollectedException 366 // being thrown. We ignore such classes and keep iterating. 367 if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { 368 vm.printTrace("ObjectCollectedException was thrown while " + 369 "accessing unloaded class " + type.name()); 370 } 371 } 372 } 373 } 374 375 public void 376 redefineClasses(Map<? extends ReferenceType, byte[]> classToBytes) 377 { 378 int cnt = classToBytes.size(); 379 JDWP.VirtualMachine.RedefineClasses.ClassDef[] defs = 380 new JDWP.VirtualMachine.RedefineClasses.ClassDef[cnt]; 381 validateVM(); 382 if (!canRedefineClasses()) { 383 throw new UnsupportedOperationException(); 384 } 385 Iterator<?> it = classToBytes.entrySet().iterator(); 386 for (int i = 0; it.hasNext(); i++) { 387 @SuppressWarnings("rawtypes") 388 Map.Entry<?, ?> entry = (Map.Entry)it.next(); 389 ReferenceTypeImpl refType = (ReferenceTypeImpl)entry.getKey(); 390 validateMirror(refType); 391 defs[i] = new JDWP.VirtualMachine.RedefineClasses 392 .ClassDef(refType, (byte[])entry.getValue()); 393 } 394 395 // flush caches and disable caching until the next suspend 396 vm.state().thaw(); 397 398 try { 399 JDWP.VirtualMachine.RedefineClasses. 400 process(vm, defs); 401 } catch (JDWPException exc) { 402 switch (exc.errorCode()) { 403 case JDWP.Error.INVALID_CLASS_FORMAT : 404 throw new ClassFormatError( 405 "class not in class file format"); 406 case JDWP.Error.CIRCULAR_CLASS_DEFINITION : 407 throw new ClassCircularityError( 408 "circularity has been detected while initializing a class"); 409 case JDWP.Error.FAILS_VERIFICATION : 410 throw new VerifyError( 411 "verifier detected internal inconsistency or security problem"); 412 case JDWP.Error.UNSUPPORTED_VERSION : 413 throw new UnsupportedClassVersionError( 414 "version numbers of class are not supported"); 415 case JDWP.Error.ADD_METHOD_NOT_IMPLEMENTED: 416 throw new UnsupportedOperationException( 417 "add method not implemented"); 418 case JDWP.Error.SCHEMA_CHANGE_NOT_IMPLEMENTED : 419 throw new UnsupportedOperationException( 420 "schema change not implemented"); 421 case JDWP.Error.HIERARCHY_CHANGE_NOT_IMPLEMENTED: 422 throw new UnsupportedOperationException( 423 "hierarchy change not implemented"); 424 case JDWP.Error.DELETE_METHOD_NOT_IMPLEMENTED : 425 throw new UnsupportedOperationException( 426 "delete method not implemented"); 427 case JDWP.Error.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: 428 throw new UnsupportedOperationException( 429 "changes to class modifiers not implemented"); 430 case JDWP.Error.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED : 431 throw new UnsupportedOperationException( 432 "changes to method modifiers not implemented"); 433 case JDWP.Error.CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED : 434 throw new UnsupportedOperationException( 435 "changes to class attribute not implemented"); 436 case JDWP.Error.NAMES_DONT_MATCH : 437 throw new NoClassDefFoundError( 438 "class names do not match"); 439 default: 440 throw exc.toJDIException(); 441 } 442 } 443 444 // Delete any record of the breakpoints 445 List<BreakpointRequest> toDelete = new ArrayList<>(); 446 EventRequestManager erm = eventRequestManager(); 447 it = erm.breakpointRequests().iterator(); 448 while (it.hasNext()) { 449 BreakpointRequest req = (BreakpointRequest)it.next(); 450 if (classToBytes.containsKey(req.location().declaringType())) { 451 toDelete.add(req); 452 } 453 } 454 erm.deleteEventRequests(toDelete); 455 456 // Invalidate any information cached for the classes just redefined. 457 it = classToBytes.keySet().iterator(); 458 while (it.hasNext()) { 459 ReferenceTypeImpl rti = (ReferenceTypeImpl)it.next(); 460 rti.noticeRedefineClass(); 461 } 462 } 463 464 public List<ThreadReference> allThreads() { 465 validateVM(); 466 return state.allThreads(); 467 } 468 469 public List<ThreadGroupReference> topLevelThreadGroups() { 470 validateVM(); 471 return state.topLevelThreadGroups(); 472 } 473 474 /* 475 * Sends a command to the back end which is defined to do an 476 * implicit vm-wide resume. The VM can no longer be considered 477 * suspended, so certain cached data must be invalidated. 478 */ 479 PacketStream sendResumingCommand(CommandSender sender) { 480 return state.thawCommand(sender); 481 } 482 483 /* 484 * The VM has been suspended. Additional caching can be done 485 * as long as there are no pending resumes. 486 */ 487 void notifySuspend() { 488 state.freeze(); 489 } 490 491 public void suspend() { 492 validateVM(); 493 try { 494 JDWP.VirtualMachine.Suspend.process(vm); 495 } catch (JDWPException exc) { 496 throw exc.toJDIException(); 497 } 498 notifySuspend(); 499 } 500 501 public void resume() { 502 validateVM(); 503 CommandSender sender = 504 new CommandSender() { 505 public PacketStream send() { 506 return JDWP.VirtualMachine.Resume.enqueueCommand(vm); 507 } 508 }; 509 try { 510 PacketStream stream = state.thawCommand(sender); 511 JDWP.VirtualMachine.Resume.waitForReply(vm, stream); 512 } catch (VMDisconnectedException exc) { 513 /* 514 * If the debugger makes a VMDeathRequest with SUSPEND_ALL, 515 * then when it does an EventSet.resume after getting the 516 * VMDeathEvent, the normal flow of events is that the 517 * BE shuts down, but the waitForReply comes back ok. In this 518 * case, the run loop in TargetVM that is waiting for a packet 519 * gets an EOF because the socket closes. It generates a 520 * VMDisconnectedEvent and everyone is happy. 521 * However, sometimes, the BE gets shutdown before this 522 * waitForReply completes. In this case, TargetVM.waitForReply 523 * gets awakened with no reply and so gens a VMDisconnectedException 524 * which is not what we want. It might be possible to fix this 525 * in the BE, but it is ok to just ignore the VMDisconnectedException 526 * here. This will allow the VMDisconnectedEvent to be generated 527 * correctly. And, if the debugger should happen to make another 528 * request, it will get a VMDisconnectedException at that time. 529 */ 530 } catch (JDWPException exc) { 531 switch (exc.errorCode()) { 532 case JDWP.Error.VM_DEAD: 533 return; 534 default: 535 throw exc.toJDIException(); 536 } 537 } 538 } 539 540 public EventQueue eventQueue() { 541 /* 542 * No VM validation here. We allow access to the event queue 543 * after disconnection, so that there is access to the terminating 544 * events. 545 */ 546 return eventQueue; 547 } 548 549 public EventRequestManager eventRequestManager() { 550 validateVM(); 551 return eventRequestManager; 552 } 553 554 EventRequestManagerImpl eventRequestManagerImpl() { 555 return eventRequestManager; 556 } 557 558 public BooleanValue mirrorOf(boolean value) { 559 validateVM(); 560 return new BooleanValueImpl(this,value); 561 } 562 563 public ByteValue mirrorOf(byte value) { 564 validateVM(); 565 return new ByteValueImpl(this,value); 566 } 567 568 public CharValue mirrorOf(char value) { 569 validateVM(); 570 return new CharValueImpl(this,value); 571 } 572 573 public ShortValue mirrorOf(short value) { 574 validateVM(); 575 return new ShortValueImpl(this,value); 576 } 577 578 public IntegerValue mirrorOf(int value) { 579 validateVM(); 580 return new IntegerValueImpl(this,value); 581 } 582 583 public LongValue mirrorOf(long value) { 584 validateVM(); 585 return new LongValueImpl(this,value); 586 } 587 588 public FloatValue mirrorOf(float value) { 589 validateVM(); 590 return new FloatValueImpl(this,value); 591 } 592 593 public DoubleValue mirrorOf(double value) { 594 validateVM(); 595 return new DoubleValueImpl(this,value); 596 } 597 598 public StringReference mirrorOf(String value) { 599 validateVM(); 600 try { 601 return JDWP.VirtualMachine.CreateString. 602 process(vm, value).stringObject; 603 } catch (JDWPException exc) { 604 throw exc.toJDIException(); 605 } 606 } 607 608 public VoidValue mirrorOfVoid() { 609 if (voidVal == null) { 610 voidVal = new VoidValueImpl(this); 611 } 612 return voidVal; 613 } 614 615 public long[] instanceCounts(List<? extends ReferenceType> classes) { 616 if (!canGetInstanceInfo()) { 617 throw new UnsupportedOperationException( 618 "target does not support getting instances"); 619 } 620 long[] retValue ; 621 ReferenceTypeImpl[] rtArray = new ReferenceTypeImpl[classes.size()]; 622 int ii = 0; 623 for (ReferenceType rti: classes) { 624 validateMirror(rti); 625 rtArray[ii++] = (ReferenceTypeImpl)rti; 626 } 627 try { 628 retValue = JDWP.VirtualMachine.InstanceCounts. 629 process(vm, rtArray).counts; 630 } catch (JDWPException exc) { 631 throw exc.toJDIException(); 632 } 633 634 return retValue; 635 } 636 637 public void dispose() { 638 validateVM(); 639 shutdown = true; 640 try { 641 JDWP.VirtualMachine.Dispose.process(vm); 642 } catch (JDWPException exc) { 643 throw exc.toJDIException(); 644 } 645 target.stopListening(); 646 } 647 648 public void exit(int exitCode) { 649 validateVM(); 650 shutdown = true; 651 try { 652 JDWP.VirtualMachine.Exit.process(vm, exitCode); 653 } catch (JDWPException exc) { 654 throw exc.toJDIException(); 655 } 656 target.stopListening(); 657 } 658 659 public Process process() { 660 validateVM(); 661 return process; 662 } 663 664 private JDWP.VirtualMachine.Version versionInfo() { 665 try { 666 if (versionInfo == null) { 667 // Need not be synchronized since it is static information 668 versionInfo = JDWP.VirtualMachine.Version.process(vm); 669 } 670 return versionInfo; 671 } catch (JDWPException exc) { 672 throw exc.toJDIException(); 673 } 674 } 675 676 public String description() { 677 validateVM(); 678 679 return MessageFormat.format(vmManager.getString("version_format"), 680 "" + vmManager.majorInterfaceVersion(), 681 "" + vmManager.minorInterfaceVersion(), 682 versionInfo().description); 683 } 684 685 public String version() { 686 validateVM(); 687 return versionInfo().vmVersion; 688 } 689 690 public String name() { 691 validateVM(); 692 return versionInfo().vmName; 693 } 694 695 public boolean canWatchFieldModification() { 696 validateVM(); 697 return capabilities().canWatchFieldModification; 698 } 699 700 public boolean canWatchFieldAccess() { 701 validateVM(); 702 return capabilities().canWatchFieldAccess; 703 } 704 705 public boolean canGetBytecodes() { 706 validateVM(); 707 return capabilities().canGetBytecodes; 708 } 709 710 public boolean canGetSyntheticAttribute() { 711 validateVM(); 712 return capabilities().canGetSyntheticAttribute; 713 } 714 715 public boolean canGetOwnedMonitorInfo() { 716 validateVM(); 717 return capabilities().canGetOwnedMonitorInfo; 718 } 719 720 public boolean canGetCurrentContendedMonitor() { 721 validateVM(); 722 return capabilities().canGetCurrentContendedMonitor; 723 } 724 725 public boolean canGetMonitorInfo() { 726 validateVM(); 727 return capabilities().canGetMonitorInfo; 728 } 729 730 private boolean hasNewCapabilities() { 731 return versionInfo().jdwpMajor > 1 || 732 versionInfo().jdwpMinor >= 4; 733 } 734 735 boolean canGet1_5LanguageFeatures() { 736 return versionInfo().jdwpMajor > 1 || 737 versionInfo().jdwpMinor >= 5; 738 } 739 740 public boolean canUseInstanceFilters() { 741 validateVM(); 742 return hasNewCapabilities() && 743 capabilitiesNew().canUseInstanceFilters; 744 } 745 746 public boolean canRedefineClasses() { 747 validateVM(); 748 return hasNewCapabilities() && 749 capabilitiesNew().canRedefineClasses; 750 } 751 752 public boolean canAddMethod() { 753 validateVM(); 754 return hasNewCapabilities() && 755 capabilitiesNew().canAddMethod; 756 } 757 758 public boolean canUnrestrictedlyRedefineClasses() { 759 validateVM(); 760 return hasNewCapabilities() && 761 capabilitiesNew().canUnrestrictedlyRedefineClasses; 762 } 763 764 public boolean canPopFrames() { 765 validateVM(); 766 return hasNewCapabilities() && 767 capabilitiesNew().canPopFrames; 768 } 769 770 public boolean canGetMethodReturnValues() { 771 return versionInfo().jdwpMajor > 1 || 772 versionInfo().jdwpMinor >= 6; 773 } 774 775 public boolean canGetInstanceInfo() { 776 if (versionInfo().jdwpMajor > 1 || 777 versionInfo().jdwpMinor >= 6) { 778 validateVM(); 779 return hasNewCapabilities() && 780 capabilitiesNew().canGetInstanceInfo; 781 } else { 782 return false; 783 } 784 } 785 786 public boolean canUseSourceNameFilters() { 787 return versionInfo().jdwpMajor > 1 || 788 versionInfo().jdwpMinor >= 6; 789 } 790 791 public boolean canForceEarlyReturn() { 792 validateVM(); 793 return hasNewCapabilities() && 794 capabilitiesNew().canForceEarlyReturn; 795 } 796 797 public boolean canBeModified() { 798 return true; 799 } 800 801 public boolean canGetSourceDebugExtension() { 802 validateVM(); 803 return hasNewCapabilities() && 804 capabilitiesNew().canGetSourceDebugExtension; 805 } 806 807 public boolean canGetClassFileVersion() { 808 return versionInfo().jdwpMajor > 1 || 809 versionInfo().jdwpMinor >= 6; 810 } 811 812 public boolean canGetConstantPool() { 813 validateVM(); 814 return hasNewCapabilities() && 815 capabilitiesNew().canGetConstantPool; 816 } 817 818 public boolean canRequestVMDeathEvent() { 819 validateVM(); 820 return hasNewCapabilities() && 821 capabilitiesNew().canRequestVMDeathEvent; 822 } 823 824 public boolean canRequestMonitorEvents() { 825 validateVM(); 826 return hasNewCapabilities() && 827 capabilitiesNew().canRequestMonitorEvents; 828 } 829 830 public boolean canGetMonitorFrameInfo() { 831 validateVM(); 832 return hasNewCapabilities() && 833 capabilitiesNew().canGetMonitorFrameInfo; 834 } 835 836 public boolean canGetModuleInfo() { 837 validateVM(); 838 return versionInfo().jdwpMajor >= 9; 839 } 840 841 public void setDebugTraceMode(int traceFlags) { 842 validateVM(); 843 this.traceFlags = traceFlags; 844 this.traceReceives = (traceFlags & TRACE_RECEIVES) != 0; 845 } 846 847 void printTrace(String string) { 848 System.err.println("[JDI: " + string + "]"); 849 } 850 851 void printReceiveTrace(int depth, String string) { 852 StringBuilder sb = new StringBuilder("Receiving:"); 853 for (int i = depth; i > 0; --i) { 854 sb.append(" "); 855 } 856 sb.append(string); 857 printTrace(sb.toString()); 858 } 859 860 private synchronized ReferenceTypeImpl addReferenceType(long id, 861 int tag, 862 String signature) { 863 if (typesByID == null) { 864 initReferenceTypes(); 865 } 866 ReferenceTypeImpl type = null; 867 switch(tag) { 868 case JDWP.TypeTag.CLASS: 869 type = new ClassTypeImpl(vm, id); 870 break; 871 case JDWP.TypeTag.INTERFACE: 872 type = new InterfaceTypeImpl(vm, id); 873 break; 874 case JDWP.TypeTag.ARRAY: 875 type = new ArrayTypeImpl(vm, id); 876 break; 877 default: 878 throw new InternalException("Invalid reference type tag"); 879 } 880 881 if (signature == null && retrievedAllTypes) { 882 // do not cache if signature is not provided 883 return type; 884 } 885 886 typesByID.put(id, type); 887 typesBySignature.add(type); 888 889 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 890 vm.printTrace("Caching new ReferenceType, sig=" + signature + 891 ", id=" + id); 892 } 893 894 return type; 895 } 896 897 synchronized void removeReferenceType(String signature) { 898 if (typesByID == null) { 899 return; 900 } 901 /* 902 * There can be multiple classes with the same name. Since 903 * we can't differentiate here, we first remove all 904 * matching classes from our cache... 905 */ 906 Iterator<ReferenceType> iter = typesBySignature.iterator(); 907 int matches = 0; 908 while (iter.hasNext()) { 909 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 910 int comp = signature.compareTo(type.signature()); 911 if (comp == 0) { 912 matches++; 913 iter.remove(); 914 typesByID.remove(type.ref()); 915 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 916 vm.printTrace("Uncaching ReferenceType, sig=" + signature + 917 ", id=" + type.ref()); 918 } 919 // fix for 4359077, don't break out. list is no longer sorted 920 // in the order we think 921 } 922 } 923 924 /* 925 * ...and if there was more than one, re-retrieve the classes 926 * with that name 927 */ 928 if (matches > 1) { 929 retrieveClassesBySignature(signature); 930 } 931 } 932 933 private synchronized List<ReferenceType> findReferenceTypes(String signature) { 934 if (typesByID == null) { 935 return new ArrayList<>(0); 936 } 937 Iterator<ReferenceType> iter = typesBySignature.iterator(); 938 List<ReferenceType> list = new ArrayList<>(); 939 while (iter.hasNext()) { 940 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 941 int comp = signature.compareTo(type.signature()); 942 if (comp == 0) { 943 list.add(type); 944 // fix for 4359077, don't break out. list is no longer sorted 945 // in the order we think 946 } 947 } 948 return list; 949 } 950 951 private void initReferenceTypes() { 952 typesByID = new HashMap<>(300); 953 typesBySignature = new HashSet<>(); 954 } 955 956 ReferenceTypeImpl referenceType(long ref, byte tag) { 957 return referenceType(ref, tag, null); 958 } 959 960 ClassTypeImpl classType(long ref) { 961 return (ClassTypeImpl)referenceType(ref, JDWP.TypeTag.CLASS, null); 962 } 963 964 InterfaceTypeImpl interfaceType(long ref) { 965 return (InterfaceTypeImpl)referenceType(ref, JDWP.TypeTag.INTERFACE, null); 966 } 967 968 ArrayTypeImpl arrayType(long ref) { 969 return (ArrayTypeImpl)referenceType(ref, JDWP.TypeTag.ARRAY, null); 970 } 971 972 ReferenceTypeImpl referenceType(long id, int tag, String signature) { 973 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 974 StringBuilder sb = new StringBuilder(); 975 sb.append("Looking up "); 976 if (tag == JDWP.TypeTag.CLASS) { 977 sb.append("Class"); 978 } else if (tag == JDWP.TypeTag.INTERFACE) { 979 sb.append("Interface"); 980 } else if (tag == JDWP.TypeTag.ARRAY) { 981 sb.append("ArrayType"); 982 } else { 983 sb.append("UNKNOWN TAG: ").append(tag); 984 } 985 if (signature != null) { 986 sb.append(", signature='").append(signature).append('\''); 987 } 988 sb.append(", id=").append(id); 989 vm.printTrace(sb.toString()); 990 } 991 if (id == 0) { 992 return null; 993 } else { 994 ReferenceTypeImpl retType = null; 995 synchronized (this) { 996 if (typesByID != null) { 997 retType = (ReferenceTypeImpl)typesByID.get(id); 998 } 999 if (retType == null) { 1000 retType = addReferenceType(id, tag, signature); 1001 } 1002 if (signature != null) { 1003 retType.setSignature(signature); 1004 } 1005 } 1006 return retType; 1007 } 1008 } 1009 1010 private JDWP.VirtualMachine.Capabilities capabilities() { 1011 if (capabilities == null) { 1012 try { 1013 capabilities = JDWP.VirtualMachine 1014 .Capabilities.process(vm); 1015 } catch (JDWPException exc) { 1016 throw exc.toJDIException(); 1017 } 1018 } 1019 return capabilities; 1020 } 1021 1022 private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew() { 1023 if (capabilitiesNew == null) { 1024 try { 1025 capabilitiesNew = JDWP.VirtualMachine 1026 .CapabilitiesNew.process(vm); 1027 } catch (JDWPException exc) { 1028 throw exc.toJDIException(); 1029 } 1030 } 1031 return capabilitiesNew; 1032 } 1033 1034 private synchronized ModuleReference addModule(long id) { 1035 if (modulesByID == null) { 1036 modulesByID = new HashMap<>(77); 1037 } 1038 ModuleReference module = new ModuleReferenceImpl(vm, id); 1039 modulesByID.put(id, module); 1040 return module; 1041 } 1042 1043 ModuleReference getModule(long id) { 1044 if (id == 0) { 1045 return null; 1046 } else { 1047 ModuleReference module = null; 1048 synchronized (this) { 1049 if (modulesByID != null) { 1050 module = modulesByID.get(id); 1051 } 1052 if (module == null) { 1053 module = addModule(id); 1054 } 1055 } 1056 return module; 1057 } 1058 } 1059 1060 private synchronized List<ModuleReference> retrieveAllModules() { 1061 ModuleReferenceImpl[] reqModules; 1062 try { 1063 reqModules = JDWP.VirtualMachine.AllModules.process(vm).modules; 1064 } catch (JDWPException exc) { 1065 throw exc.toJDIException(); 1066 } 1067 ArrayList<ModuleReference> modules = new ArrayList<>(); 1068 for (int i = 0; i < reqModules.length; i++) { 1069 long moduleRef = reqModules[i].ref(); 1070 ModuleReference module = getModule(moduleRef); 1071 modules.add(module); 1072 } 1073 return modules; 1074 } 1075 1076 private List<ReferenceType> retrieveClassesBySignature(String signature) { 1077 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 1078 vm.printTrace("Retrieving matching ReferenceTypes, sig=" + signature); 1079 } 1080 JDWP.VirtualMachine.ClassesBySignature.ClassInfo[] cinfos; 1081 try { 1082 cinfos = JDWP.VirtualMachine.ClassesBySignature. 1083 process(vm, signature).classes; 1084 } catch (JDWPException exc) { 1085 throw exc.toJDIException(); 1086 } 1087 1088 int count = cinfos.length; 1089 List<ReferenceType> list = new ArrayList<>(count); 1090 1091 // Hold lock during processing to improve performance 1092 synchronized (this) { 1093 for (int i = 0; i < count; i++) { 1094 JDWP.VirtualMachine.ClassesBySignature.ClassInfo ci = 1095 cinfos[i]; 1096 ReferenceTypeImpl type = referenceType(ci.typeID, 1097 ci.refTypeTag, 1098 signature); 1099 type.setStatus(ci.status); 1100 list.add(type); 1101 } 1102 } 1103 return list; 1104 } 1105 1106 private void retrieveAllClasses1_4() { 1107 JDWP.VirtualMachine.AllClasses.ClassInfo[] cinfos; 1108 try { 1109 cinfos = JDWP.VirtualMachine.AllClasses.process(vm).classes; 1110 } catch (JDWPException exc) { 1111 throw exc.toJDIException(); 1112 } 1113 1114 // Hold lock during processing to improve performance 1115 // and to have safe check/set of retrievedAllTypes 1116 synchronized (this) { 1117 if (!retrievedAllTypes) { 1118 // Number of classes 1119 int count = cinfos.length; 1120 for (int i = 0; i < count; i++) { 1121 JDWP.VirtualMachine.AllClasses.ClassInfo ci = cinfos[i]; 1122 ReferenceTypeImpl type = referenceType(ci.typeID, 1123 ci.refTypeTag, 1124 ci.signature); 1125 type.setStatus(ci.status); 1126 } 1127 retrievedAllTypes = true; 1128 } 1129 } 1130 } 1131 1132 private void retrieveAllClasses() { 1133 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 1134 vm.printTrace("Retrieving all ReferenceTypes"); 1135 } 1136 1137 if (!vm.canGet1_5LanguageFeatures()) { 1138 retrieveAllClasses1_4(); 1139 return; 1140 } 1141 1142 /* 1143 * To save time (assuming the caller will be 1144 * using then) we will get the generic sigs too. 1145 */ 1146 JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo[] cinfos; 1147 try { 1148 cinfos = JDWP.VirtualMachine.AllClassesWithGeneric.process(vm).classes; 1149 } catch (JDWPException exc) { 1150 throw exc.toJDIException(); 1151 } 1152 1153 // Hold lock during processing to improve performance 1154 // and to have safe check/set of retrievedAllTypes 1155 synchronized (this) { 1156 if (!retrievedAllTypes) { 1157 // Number of classes 1158 int count = cinfos.length; 1159 for (int i = 0; i < count; i++) { 1160 JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo ci = 1161 cinfos[i]; 1162 ReferenceTypeImpl type = referenceType(ci.typeID, 1163 ci.refTypeTag, 1164 ci.signature); 1165 type.setGenericSignature(ci.genericSignature); 1166 type.setStatus(ci.status); 1167 } 1168 retrievedAllTypes = true; 1169 } 1170 } 1171 } 1172 1173 void sendToTarget(Packet packet) { 1174 target.send(packet); 1175 } 1176 1177 void waitForTargetReply(Packet packet) { 1178 target.waitForReply(packet); 1179 /* 1180 * If any object disposes have been batched up, send them now. 1181 */ 1182 processBatchedDisposes(); 1183 } 1184 1185 Type findBootType(String signature) throws ClassNotLoadedException { 1186 List<ReferenceType> types = retrieveClassesBySignature(signature); 1187 Iterator<ReferenceType> iter = types.iterator(); 1188 while (iter.hasNext()) { 1189 ReferenceType type = iter.next(); 1190 if (type.classLoader() == null) { 1191 return type; 1192 } 1193 } 1194 JNITypeParser parser = new JNITypeParser(signature); 1195 throw new ClassNotLoadedException(parser.typeName(), 1196 "Type " + parser.typeName() + " not loaded"); 1197 } 1198 1199 BooleanType theBooleanType() { 1200 if (theBooleanType == null) { 1201 synchronized(this) { 1202 if (theBooleanType == null) { 1203 theBooleanType = new BooleanTypeImpl(this); 1204 } 1205 } 1206 } 1207 return theBooleanType; 1208 } 1209 1210 ByteType theByteType() { 1211 if (theByteType == null) { 1212 synchronized(this) { 1213 if (theByteType == null) { 1214 theByteType = new ByteTypeImpl(this); 1215 } 1216 } 1217 } 1218 return theByteType; 1219 } 1220 1221 CharType theCharType() { 1222 if (theCharType == null) { 1223 synchronized(this) { 1224 if (theCharType == null) { 1225 theCharType = new CharTypeImpl(this); 1226 } 1227 } 1228 } 1229 return theCharType; 1230 } 1231 1232 ShortType theShortType() { 1233 if (theShortType == null) { 1234 synchronized(this) { 1235 if (theShortType == null) { 1236 theShortType = new ShortTypeImpl(this); 1237 } 1238 } 1239 } 1240 return theShortType; 1241 } 1242 1243 IntegerType theIntegerType() { 1244 if (theIntegerType == null) { 1245 synchronized(this) { 1246 if (theIntegerType == null) { 1247 theIntegerType = new IntegerTypeImpl(this); 1248 } 1249 } 1250 } 1251 return theIntegerType; 1252 } 1253 1254 LongType theLongType() { 1255 if (theLongType == null) { 1256 synchronized(this) { 1257 if (theLongType == null) { 1258 theLongType = new LongTypeImpl(this); 1259 } 1260 } 1261 } 1262 return theLongType; 1263 } 1264 1265 FloatType theFloatType() { 1266 if (theFloatType == null) { 1267 synchronized(this) { 1268 if (theFloatType == null) { 1269 theFloatType = new FloatTypeImpl(this); 1270 } 1271 } 1272 } 1273 return theFloatType; 1274 } 1275 1276 DoubleType theDoubleType() { 1277 if (theDoubleType == null) { 1278 synchronized(this) { 1279 if (theDoubleType == null) { 1280 theDoubleType = new DoubleTypeImpl(this); 1281 } 1282 } 1283 } 1284 return theDoubleType; 1285 } 1286 1287 VoidType theVoidType() { 1288 if (theVoidType == null) { 1289 synchronized(this) { 1290 if (theVoidType == null) { 1291 theVoidType = new VoidTypeImpl(this); 1292 } 1293 } 1294 } 1295 return theVoidType; 1296 } 1297 1298 PrimitiveType primitiveTypeMirror(byte tag) { 1299 switch (tag) { 1300 case JDWP.Tag.BOOLEAN: 1301 return theBooleanType(); 1302 case JDWP.Tag.BYTE: 1303 return theByteType(); 1304 case JDWP.Tag.CHAR: 1305 return theCharType(); 1306 case JDWP.Tag.SHORT: 1307 return theShortType(); 1308 case JDWP.Tag.INT: 1309 return theIntegerType(); 1310 case JDWP.Tag.LONG: 1311 return theLongType(); 1312 case JDWP.Tag.FLOAT: 1313 return theFloatType(); 1314 case JDWP.Tag.DOUBLE: 1315 return theDoubleType(); 1316 default: 1317 throw new IllegalArgumentException("Unrecognized primitive tag " + tag); 1318 } 1319 } 1320 1321 private void processBatchedDisposes() { 1322 if (shutdown) { 1323 return; 1324 } 1325 1326 JDWP.VirtualMachine.DisposeObjects.Request[] requests = null; 1327 synchronized(batchedDisposeRequests) { 1328 int size = batchedDisposeRequests.size(); 1329 if (size >= DISPOSE_THRESHOLD) { 1330 if ((traceFlags & TRACE_OBJREFS) != 0) { 1331 printTrace("Dispose threashold reached. Will dispose " 1332 + size + " object references..."); 1333 } 1334 requests = new JDWP.VirtualMachine.DisposeObjects.Request[size]; 1335 for (int i = 0; i < requests.length; i++) { 1336 SoftObjectReference ref = batchedDisposeRequests.get(i); 1337 if ((traceFlags & TRACE_OBJREFS) != 0) { 1338 printTrace("Disposing object " + ref.key().longValue() + 1339 " (ref count = " + ref.count() + ")"); 1340 } 1341 1342 // This is kludgy. We temporarily re-create an object 1343 // reference so that we can correctly pass its id to the 1344 // JDWP command. 1345 requests[i] = 1346 new JDWP.VirtualMachine.DisposeObjects.Request( 1347 new ObjectReferenceImpl(this, ref.key().longValue()), 1348 ref.count()); 1349 } 1350 batchedDisposeRequests.clear(); 1351 } 1352 } 1353 if (requests != null) { 1354 try { 1355 JDWP.VirtualMachine.DisposeObjects.process(vm, requests); 1356 } catch (JDWPException exc) { 1357 throw exc.toJDIException(); 1358 } 1359 } 1360 } 1361 1362 private void batchForDispose(SoftObjectReference ref) { 1363 if ((traceFlags & TRACE_OBJREFS) != 0) { 1364 printTrace("Batching object " + ref.key().longValue() + 1365 " for dispose (ref count = " + ref.count() + ")"); 1366 } 1367 batchedDisposeRequests.add(ref); 1368 } 1369 1370 private void processQueue() { 1371 Reference<?> ref; 1372 //if ((traceFlags & TRACE_OBJREFS) != 0) { 1373 // printTrace("Checking for softly reachable objects"); 1374 //} 1375 while ((ref = referenceQueue.poll()) != null) { 1376 SoftObjectReference softRef = (SoftObjectReference)ref; 1377 removeObjectMirror(softRef); 1378 batchForDispose(softRef); 1379 } 1380 } 1381 1382 synchronized ObjectReferenceImpl objectMirror(long id, int tag) { 1383 1384 // Handle any queue elements that are not strongly reachable 1385 processQueue(); 1386 1387 if (id == 0) { 1388 return null; 1389 } 1390 ObjectReferenceImpl object = null; 1391 Long key = id; 1392 1393 /* 1394 * Attempt to retrieve an existing object reference 1395 */ 1396 SoftObjectReference ref = objectsByID.get(key); 1397 if (ref != null) { 1398 object = ref.object(); 1399 } 1400 1401 /* 1402 * If the object wasn't in the table, or it's soft reference was 1403 * cleared, create a new instance. 1404 */ 1405 if (object == null) { 1406 switch (tag) { 1407 case JDWP.Tag.OBJECT: 1408 case JDWP.Tag.INLINE_OBJECT: 1409 object = new ObjectReferenceImpl(vm, id); 1410 break; 1411 case JDWP.Tag.STRING: 1412 object = new StringReferenceImpl(vm, id); 1413 break; 1414 case JDWP.Tag.ARRAY: 1415 object = new ArrayReferenceImpl(vm, id); 1416 break; 1417 case JDWP.Tag.THREAD: 1418 ThreadReferenceImpl thread = 1419 new ThreadReferenceImpl(vm, id); 1420 thread.addListener(this); 1421 object = thread; 1422 break; 1423 case JDWP.Tag.THREAD_GROUP: 1424 object = new ThreadGroupReferenceImpl(vm, id); 1425 break; 1426 case JDWP.Tag.CLASS_LOADER: 1427 object = new ClassLoaderReferenceImpl(vm, id); 1428 break; 1429 case JDWP.Tag.CLASS_OBJECT: 1430 object = new ClassObjectReferenceImpl(vm, id); 1431 break; 1432 default: 1433 throw new IllegalArgumentException("Invalid object tag: " + tag); 1434 } 1435 ref = new SoftObjectReference(key, object, referenceQueue); 1436 1437 /* 1438 * If there was no previous entry in the table, we add one here 1439 * If the previous entry was cleared, we replace it here. 1440 */ 1441 objectsByID.put(key, ref); 1442 if ((traceFlags & TRACE_OBJREFS) != 0) { 1443 printTrace("Creating new " + 1444 object.getClass().getName() + " (id = " + id + ")"); 1445 } 1446 } else { 1447 ref.incrementCount(); 1448 } 1449 1450 return object; 1451 } 1452 1453 synchronized void removeObjectMirror(ObjectReferenceImpl object) { 1454 // Handle any queue elements that are not strongly reachable 1455 processQueue(); 1456 1457 SoftObjectReference ref = objectsByID.remove(object.ref()); 1458 if (ref != null) { 1459 batchForDispose(ref); 1460 } else { 1461 /* 1462 * If there's a live ObjectReference about, it better be part 1463 * of the cache. 1464 */ 1465 throw new InternalException("ObjectReference " + object.ref() + 1466 " not found in object cache"); 1467 } 1468 } 1469 1470 synchronized void removeObjectMirror(SoftObjectReference ref) { 1471 /* 1472 * This will remove the soft reference if it has not been 1473 * replaced in the cache. 1474 */ 1475 objectsByID.remove(ref.key()); 1476 } 1477 1478 ObjectReferenceImpl objectMirror(long id) { 1479 return objectMirror(id, JDWP.Tag.OBJECT); 1480 } 1481 1482 StringReferenceImpl stringMirror(long id) { 1483 return (StringReferenceImpl)objectMirror(id, JDWP.Tag.STRING); 1484 } 1485 1486 ArrayReferenceImpl arrayMirror(long id) { 1487 return (ArrayReferenceImpl)objectMirror(id, JDWP.Tag.ARRAY); 1488 } 1489 1490 ThreadReferenceImpl threadMirror(long id) { 1491 return (ThreadReferenceImpl)objectMirror(id, JDWP.Tag.THREAD); 1492 } 1493 1494 ThreadGroupReferenceImpl threadGroupMirror(long id) { 1495 return (ThreadGroupReferenceImpl)objectMirror(id, 1496 JDWP.Tag.THREAD_GROUP); 1497 } 1498 1499 ClassLoaderReferenceImpl classLoaderMirror(long id) { 1500 return (ClassLoaderReferenceImpl)objectMirror(id, 1501 JDWP.Tag.CLASS_LOADER); 1502 } 1503 1504 ClassObjectReferenceImpl classObjectMirror(long id) { 1505 return (ClassObjectReferenceImpl)objectMirror(id, 1506 JDWP.Tag.CLASS_OBJECT); 1507 } 1508 1509 ModuleReferenceImpl moduleMirror(long id) { 1510 return (ModuleReferenceImpl)getModule(id); 1511 } 1512 1513 /* 1514 * Implementation of PathSearchingVirtualMachine 1515 */ 1516 private JDWP.VirtualMachine.ClassPaths getClasspath() { 1517 if (pathInfo == null) { 1518 try { 1519 pathInfo = JDWP.VirtualMachine.ClassPaths.process(vm); 1520 } catch (JDWPException exc) { 1521 throw exc.toJDIException(); 1522 } 1523 } 1524 return pathInfo; 1525 } 1526 1527 public List<String> classPath() { 1528 return Arrays.asList(getClasspath().classpaths); 1529 } 1530 1531 public List<String> bootClassPath() { 1532 return Collections.emptyList(); 1533 } 1534 1535 public String baseDirectory() { 1536 return getClasspath().baseDir; 1537 } 1538 1539 public void setDefaultStratum(String stratum) { 1540 defaultStratum = stratum; 1541 if (stratum == null) { 1542 stratum = ""; 1543 } 1544 try { 1545 JDWP.VirtualMachine.SetDefaultStratum.process(vm, 1546 stratum); 1547 } catch (JDWPException exc) { 1548 throw exc.toJDIException(); 1549 } 1550 } 1551 1552 public String getDefaultStratum() { 1553 return defaultStratum; 1554 } 1555 1556 ThreadGroup threadGroupForJDI() { 1557 return threadGroupForJDI; 1558 } 1559 1560 static private class SoftObjectReference extends SoftReference<ObjectReferenceImpl> { 1561 int count; 1562 Long key; 1563 1564 SoftObjectReference(Long key, ObjectReferenceImpl mirror, 1565 ReferenceQueue<ObjectReferenceImpl> queue) { 1566 super(mirror, queue); 1567 this.count = 1; 1568 this.key = key; 1569 } 1570 1571 int count() { 1572 return count; 1573 } 1574 1575 void incrementCount() { 1576 count++; 1577 } 1578 1579 Long key() { 1580 return key; 1581 } 1582 1583 ObjectReferenceImpl object() { 1584 return get(); 1585 } 1586 } 1587 }