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