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 public List<ReferenceType> classesByName(String className) { 319 validateVM(); 320 String signature = JNITypeParser.typeNameToSignature(className); 321 List<ReferenceType> list; 322 if (retrievedAllTypes) { 323 list = findReferenceTypes(signature); 324 } else { 325 list = retrieveClassesBySignature(signature); 326 } 327 return Collections.unmodifiableList(list); 328 } 329 330 public List<ReferenceType> allClasses() { 331 validateVM(); 332 333 if (!retrievedAllTypes) { 334 retrieveAllClasses(); 335 } 336 ArrayList<ReferenceType> a; 337 synchronized (this) { 338 a = new ArrayList<>(typesBySignature); 339 } 340 return Collections.unmodifiableList(a); 341 } 342 343 /** 344 * Performs an action for each loaded type. 345 */ 346 public void forEachClass(Consumer<ReferenceType> action) { 347 for (ReferenceType type : allClasses()) { 348 try { 349 action.accept(type); 350 } catch (ObjectCollectedException ex) { 351 // Some classes might be unloaded and garbage collected since 352 // we retrieved the copy of all loaded classes and started 353 // iterating over them. In this case calling methods on such types 354 // might result in com.sun.jdi.ObjectCollectedException 355 // being thrown. We ignore such classes and keep iterating. 356 if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { 357 vm.printTrace("ObjectCollectedException was thrown while " + 358 "accessing unloaded class " + type.name()); 359 } 360 } 361 } 362 } 363 364 public void 365 redefineClasses(Map<? extends ReferenceType, byte[]> classToBytes) 366 { 367 int cnt = classToBytes.size(); 368 JDWP.VirtualMachine.RedefineClasses.ClassDef[] defs = 369 new JDWP.VirtualMachine.RedefineClasses.ClassDef[cnt]; 370 validateVM(); 371 if (!canRedefineClasses()) { 372 throw new UnsupportedOperationException(); 373 } 374 Iterator<?> it = classToBytes.entrySet().iterator(); 375 for (int i = 0; it.hasNext(); i++) { 376 @SuppressWarnings("rawtypes") 377 Map.Entry<?, ?> entry = (Map.Entry)it.next(); 378 ReferenceTypeImpl refType = (ReferenceTypeImpl)entry.getKey(); 379 validateMirror(refType); 380 defs[i] = new JDWP.VirtualMachine.RedefineClasses 381 .ClassDef(refType, (byte[])entry.getValue()); 382 } 383 384 // flush caches and disable caching until the next suspend 385 vm.state().thaw(); 386 387 try { 388 JDWP.VirtualMachine.RedefineClasses. 389 process(vm, defs); 390 } catch (JDWPException exc) { 391 switch (exc.errorCode()) { 392 case JDWP.Error.INVALID_CLASS_FORMAT : 393 throw new ClassFormatError( 394 "class not in class file format"); 395 case JDWP.Error.CIRCULAR_CLASS_DEFINITION : 396 throw new ClassCircularityError( 397 "circularity has been detected while initializing a class"); 398 case JDWP.Error.FAILS_VERIFICATION : 399 throw new VerifyError( 400 "verifier detected internal inconsistency or security problem"); 401 case JDWP.Error.UNSUPPORTED_VERSION : 402 throw new UnsupportedClassVersionError( 403 "version numbers of class are not supported"); 404 case JDWP.Error.ADD_METHOD_NOT_IMPLEMENTED: 405 throw new UnsupportedOperationException( 406 "add method not implemented"); 407 case JDWP.Error.SCHEMA_CHANGE_NOT_IMPLEMENTED : 408 throw new UnsupportedOperationException( 409 "schema change not implemented"); 410 case JDWP.Error.HIERARCHY_CHANGE_NOT_IMPLEMENTED: 411 throw new UnsupportedOperationException( 412 "hierarchy change not implemented"); 413 case JDWP.Error.DELETE_METHOD_NOT_IMPLEMENTED : 414 throw new UnsupportedOperationException( 415 "delete method not implemented"); 416 case JDWP.Error.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: 417 throw new UnsupportedOperationException( 418 "changes to class modifiers not implemented"); 419 case JDWP.Error.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED : 420 throw new UnsupportedOperationException( 421 "changes to method modifiers not implemented"); 422 case JDWP.Error.CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED : 423 throw new UnsupportedOperationException( 424 "changes to class attribute not implemented"); 425 case JDWP.Error.NAMES_DONT_MATCH : 426 throw new NoClassDefFoundError( 427 "class names do not match"); 428 default: 429 throw exc.toJDIException(); 430 } 431 } 432 433 // Delete any record of the breakpoints 434 List<BreakpointRequest> toDelete = new ArrayList<>(); 435 EventRequestManager erm = eventRequestManager(); 436 it = erm.breakpointRequests().iterator(); 437 while (it.hasNext()) { 438 BreakpointRequest req = (BreakpointRequest)it.next(); 439 if (classToBytes.containsKey(req.location().declaringType())) { 440 toDelete.add(req); 441 } 442 } 443 erm.deleteEventRequests(toDelete); 444 445 // Invalidate any information cached for the classes just redefined. 446 it = classToBytes.keySet().iterator(); 447 while (it.hasNext()) { 448 ReferenceTypeImpl rti = (ReferenceTypeImpl)it.next(); 449 rti.noticeRedefineClass(); 450 } 451 } 452 453 public List<ThreadReference> allThreads() { 454 validateVM(); 455 return state.allThreads(); 456 } 457 458 public List<ThreadGroupReference> topLevelThreadGroups() { 459 validateVM(); 460 return state.topLevelThreadGroups(); 461 } 462 463 /* 464 * Sends a command to the back end which is defined to do an 465 * implicit vm-wide resume. The VM can no longer be considered 466 * suspended, so certain cached data must be invalidated. 467 */ 468 PacketStream sendResumingCommand(CommandSender sender) { 469 return state.thawCommand(sender); 470 } 471 472 /* 473 * The VM has been suspended. Additional caching can be done 474 * as long as there are no pending resumes. 475 */ 476 void notifySuspend() { 477 state.freeze(); 478 } 479 480 public void suspend() { 481 validateVM(); 482 try { 483 JDWP.VirtualMachine.Suspend.process(vm); 484 } catch (JDWPException exc) { 485 throw exc.toJDIException(); 486 } 487 notifySuspend(); 488 } 489 490 public void resume() { 491 validateVM(); 492 CommandSender sender = 493 new CommandSender() { 494 public PacketStream send() { 495 return JDWP.VirtualMachine.Resume.enqueueCommand(vm); 496 } 497 }; 498 try { 499 PacketStream stream = state.thawCommand(sender); 500 JDWP.VirtualMachine.Resume.waitForReply(vm, stream); 501 } catch (VMDisconnectedException exc) { 502 /* 503 * If the debugger makes a VMDeathRequest with SUSPEND_ALL, 504 * then when it does an EventSet.resume after getting the 505 * VMDeathEvent, the normal flow of events is that the 506 * BE shuts down, but the waitForReply comes back ok. In this 507 * case, the run loop in TargetVM that is waiting for a packet 508 * gets an EOF because the socket closes. It generates a 509 * VMDisconnectedEvent and everyone is happy. 510 * However, sometimes, the BE gets shutdown before this 511 * waitForReply completes. In this case, TargetVM.waitForReply 512 * gets awakened with no reply and so gens a VMDisconnectedException 513 * which is not what we want. It might be possible to fix this 514 * in the BE, but it is ok to just ignore the VMDisconnectedException 515 * here. This will allow the VMDisconnectedEvent to be generated 516 * correctly. And, if the debugger should happen to make another 517 * request, it will get a VMDisconnectedException at that time. 518 */ 519 } catch (JDWPException exc) { 520 switch (exc.errorCode()) { 521 case JDWP.Error.VM_DEAD: 522 return; 523 default: 524 throw exc.toJDIException(); 525 } 526 } 527 } 528 529 public EventQueue eventQueue() { 530 /* 531 * No VM validation here. We allow access to the event queue 532 * after disconnection, so that there is access to the terminating 533 * events. 534 */ 535 return eventQueue; 536 } 537 538 public EventRequestManager eventRequestManager() { 539 validateVM(); 540 return eventRequestManager; 541 } 542 543 EventRequestManagerImpl eventRequestManagerImpl() { 544 return eventRequestManager; 545 } 546 547 public BooleanValue mirrorOf(boolean value) { 548 validateVM(); 549 return new BooleanValueImpl(this,value); 550 } 551 552 public ByteValue mirrorOf(byte value) { 553 validateVM(); 554 return new ByteValueImpl(this,value); 555 } 556 557 public CharValue mirrorOf(char value) { 558 validateVM(); 559 return new CharValueImpl(this,value); 560 } 561 562 public ShortValue mirrorOf(short value) { 563 validateVM(); 564 return new ShortValueImpl(this,value); 565 } 566 567 public IntegerValue mirrorOf(int value) { 568 validateVM(); 569 return new IntegerValueImpl(this,value); 570 } 571 572 public LongValue mirrorOf(long value) { 573 validateVM(); 574 return new LongValueImpl(this,value); 575 } 576 577 public FloatValue mirrorOf(float value) { 578 validateVM(); 579 return new FloatValueImpl(this,value); 580 } 581 582 public DoubleValue mirrorOf(double value) { 583 validateVM(); 584 return new DoubleValueImpl(this,value); 585 } 586 587 public StringReference mirrorOf(String value) { 588 validateVM(); 589 try { 590 return JDWP.VirtualMachine.CreateString. 591 process(vm, value).stringObject; 592 } catch (JDWPException exc) { 593 throw exc.toJDIException(); 594 } 595 } 596 597 public VoidValue mirrorOfVoid() { 598 if (voidVal == null) { 599 voidVal = new VoidValueImpl(this); 600 } 601 return voidVal; 602 } 603 604 public long[] instanceCounts(List<? extends ReferenceType> classes) { 605 if (!canGetInstanceInfo()) { 606 throw new UnsupportedOperationException( 607 "target does not support getting instances"); 608 } 609 long[] retValue ; 610 ReferenceTypeImpl[] rtArray = new ReferenceTypeImpl[classes.size()]; 611 int ii = 0; 612 for (ReferenceType rti: classes) { 613 validateMirror(rti); 614 rtArray[ii++] = (ReferenceTypeImpl)rti; 615 } 616 try { 617 retValue = JDWP.VirtualMachine.InstanceCounts. 618 process(vm, rtArray).counts; 619 } catch (JDWPException exc) { 620 throw exc.toJDIException(); 621 } 622 623 return retValue; 624 } 625 626 public void dispose() { 627 validateVM(); 628 shutdown = true; 629 try { 630 JDWP.VirtualMachine.Dispose.process(vm); 631 } catch (JDWPException exc) { 632 throw exc.toJDIException(); 633 } 634 target.stopListening(); 635 } 636 637 public void exit(int exitCode) { 638 validateVM(); 639 shutdown = true; 640 try { 641 JDWP.VirtualMachine.Exit.process(vm, exitCode); 642 } catch (JDWPException exc) { 643 throw exc.toJDIException(); 644 } 645 target.stopListening(); 646 } 647 648 public Process process() { 649 validateVM(); 650 return process; 651 } 652 653 private JDWP.VirtualMachine.Version versionInfo() { 654 try { 655 if (versionInfo == null) { 656 // Need not be synchronized since it is static information 657 versionInfo = JDWP.VirtualMachine.Version.process(vm); 658 } 659 return versionInfo; 660 } catch (JDWPException exc) { 661 throw exc.toJDIException(); 662 } 663 } 664 665 public String description() { 666 validateVM(); 667 668 return MessageFormat.format(vmManager.getString("version_format"), 669 "" + vmManager.majorInterfaceVersion(), 670 "" + vmManager.minorInterfaceVersion(), 671 versionInfo().description); 672 } 673 674 public String version() { 675 validateVM(); 676 return versionInfo().vmVersion; 677 } 678 679 public String name() { 680 validateVM(); 681 return versionInfo().vmName; 682 } 683 684 public boolean canWatchFieldModification() { 685 validateVM(); 686 return capabilities().canWatchFieldModification; 687 } 688 689 public boolean canWatchFieldAccess() { 690 validateVM(); 691 return capabilities().canWatchFieldAccess; 692 } 693 694 public boolean canGetBytecodes() { 695 validateVM(); 696 return capabilities().canGetBytecodes; 697 } 698 699 public boolean canGetSyntheticAttribute() { 700 validateVM(); 701 return capabilities().canGetSyntheticAttribute; 702 } 703 704 public boolean canGetOwnedMonitorInfo() { 705 validateVM(); 706 return capabilities().canGetOwnedMonitorInfo; 707 } 708 709 public boolean canGetCurrentContendedMonitor() { 710 validateVM(); 711 return capabilities().canGetCurrentContendedMonitor; 712 } 713 714 public boolean canGetMonitorInfo() { 715 validateVM(); 716 return capabilities().canGetMonitorInfo; 717 } 718 719 private boolean hasNewCapabilities() { 720 return versionInfo().jdwpMajor > 1 || 721 versionInfo().jdwpMinor >= 4; 722 } 723 724 boolean canGet1_5LanguageFeatures() { 725 return versionInfo().jdwpMajor > 1 || 726 versionInfo().jdwpMinor >= 5; 727 } 728 729 public boolean canUseInstanceFilters() { 730 validateVM(); 731 return hasNewCapabilities() && 732 capabilitiesNew().canUseInstanceFilters; 733 } 734 735 public boolean canRedefineClasses() { 736 validateVM(); 737 return hasNewCapabilities() && 738 capabilitiesNew().canRedefineClasses; 739 } 740 741 public boolean canAddMethod() { 742 validateVM(); 743 return hasNewCapabilities() && 744 capabilitiesNew().canAddMethod; 745 } 746 747 public boolean canUnrestrictedlyRedefineClasses() { 748 validateVM(); 749 return hasNewCapabilities() && 750 capabilitiesNew().canUnrestrictedlyRedefineClasses; 751 } 752 753 public boolean canPopFrames() { 754 validateVM(); 755 return hasNewCapabilities() && 756 capabilitiesNew().canPopFrames; 757 } 758 759 public boolean canGetMethodReturnValues() { 760 return versionInfo().jdwpMajor > 1 || 761 versionInfo().jdwpMinor >= 6; 762 } 763 764 public boolean canGetInstanceInfo() { 765 if (versionInfo().jdwpMajor > 1 || 766 versionInfo().jdwpMinor >= 6) { 767 validateVM(); 768 return hasNewCapabilities() && 769 capabilitiesNew().canGetInstanceInfo; 770 } else { 771 return false; 772 } 773 } 774 775 public boolean canUseSourceNameFilters() { 776 return versionInfo().jdwpMajor > 1 || 777 versionInfo().jdwpMinor >= 6; 778 } 779 780 public boolean canForceEarlyReturn() { 781 validateVM(); 782 return hasNewCapabilities() && 783 capabilitiesNew().canForceEarlyReturn; 784 } 785 786 public boolean canBeModified() { 787 return true; 788 } 789 790 public boolean canGetSourceDebugExtension() { 791 validateVM(); 792 return hasNewCapabilities() && 793 capabilitiesNew().canGetSourceDebugExtension; 794 } 795 796 public boolean canGetClassFileVersion() { 797 return versionInfo().jdwpMajor > 1 || 798 versionInfo().jdwpMinor >= 6; 799 } 800 801 public boolean canGetConstantPool() { 802 validateVM(); 803 return hasNewCapabilities() && 804 capabilitiesNew().canGetConstantPool; 805 } 806 807 public boolean canRequestVMDeathEvent() { 808 validateVM(); 809 return hasNewCapabilities() && 810 capabilitiesNew().canRequestVMDeathEvent; 811 } 812 813 public boolean canRequestMonitorEvents() { 814 validateVM(); 815 return hasNewCapabilities() && 816 capabilitiesNew().canRequestMonitorEvents; 817 } 818 819 public boolean canGetMonitorFrameInfo() { 820 validateVM(); 821 return hasNewCapabilities() && 822 capabilitiesNew().canGetMonitorFrameInfo; 823 } 824 825 public boolean canGetModuleInfo() { 826 validateVM(); 827 return versionInfo().jdwpMajor >= 9; 828 } 829 830 public void setDebugTraceMode(int traceFlags) { 831 validateVM(); 832 this.traceFlags = traceFlags; 833 this.traceReceives = (traceFlags & TRACE_RECEIVES) != 0; 834 } 835 836 void printTrace(String string) { 837 System.err.println("[JDI: " + string + "]"); 838 } 839 840 void printReceiveTrace(int depth, String string) { 841 StringBuilder sb = new StringBuilder("Receiving:"); 842 for (int i = depth; i > 0; --i) { 843 sb.append(" "); 844 } 845 sb.append(string); 846 printTrace(sb.toString()); 847 } 848 849 private synchronized ReferenceTypeImpl addReferenceType(long id, 850 int tag, 851 String signature) { 852 if (typesByID == null) { 853 initReferenceTypes(); 854 } 855 ReferenceTypeImpl type = null; 856 switch(tag) { 857 case JDWP.TypeTag.CLASS: 858 type = new ClassTypeImpl(vm, id); 859 break; 860 case JDWP.TypeTag.INTERFACE: 861 type = new InterfaceTypeImpl(vm, id); 862 break; 863 case JDWP.TypeTag.ARRAY: 864 type = new ArrayTypeImpl(vm, id); 865 break; 866 default: 867 throw new InternalException("Invalid reference type tag"); 868 } 869 870 if (signature == null && retrievedAllTypes) { 871 // do not cache if signature is not provided 872 return type; 873 } 874 875 typesByID.put(id, type); 876 typesBySignature.add(type); 877 878 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 879 vm.printTrace("Caching new ReferenceType, sig=" + signature + 880 ", id=" + id); 881 } 882 883 return type; 884 } 885 886 synchronized void removeReferenceType(String signature) { 887 if (typesByID == null) { 888 return; 889 } 890 /* 891 * There can be multiple classes with the same name. Since 892 * we can't differentiate here, we first remove all 893 * matching classes from our cache... 894 */ 895 Iterator<ReferenceType> iter = typesBySignature.iterator(); 896 int matches = 0; 897 while (iter.hasNext()) { 898 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 899 int comp = signature.compareTo(type.signature()); 900 if (comp == 0) { 901 matches++; 902 iter.remove(); 903 typesByID.remove(type.ref()); 904 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 905 vm.printTrace("Uncaching ReferenceType, sig=" + signature + 906 ", id=" + type.ref()); 907 } 908 // fix for 4359077, don't break out. list is no longer sorted 909 // in the order we think 910 } 911 } 912 913 /* 914 * ...and if there was more than one, re-retrieve the classes 915 * with that name 916 */ 917 if (matches > 1) { 918 retrieveClassesBySignature(signature); 919 } 920 } 921 922 private synchronized List<ReferenceType> findReferenceTypes(String signature) { 923 if (typesByID == null) { 924 return new ArrayList<>(0); 925 } 926 Iterator<ReferenceType> iter = typesBySignature.iterator(); 927 List<ReferenceType> list = new ArrayList<>(); 928 while (iter.hasNext()) { 929 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 930 int comp = signature.compareTo(type.signature()); 931 if (comp == 0) { 932 list.add(type); 933 // fix for 4359077, don't break out. list is no longer sorted 934 // in the order we think 935 } 936 } 937 return list; 938 } 939 940 private void initReferenceTypes() { 941 typesByID = new HashMap<>(300); 942 typesBySignature = new HashSet<>(); 943 } 944 945 ReferenceTypeImpl referenceType(long ref, byte tag) { 946 return referenceType(ref, tag, null); 947 } 948 949 ClassTypeImpl classType(long ref) { 950 return (ClassTypeImpl)referenceType(ref, JDWP.TypeTag.CLASS, null); 951 } 952 953 InterfaceTypeImpl interfaceType(long ref) { 954 return (InterfaceTypeImpl)referenceType(ref, JDWP.TypeTag.INTERFACE, null); 955 } 956 957 ArrayTypeImpl arrayType(long ref) { 958 return (ArrayTypeImpl)referenceType(ref, JDWP.TypeTag.ARRAY, null); 959 } 960 961 ReferenceTypeImpl referenceType(long id, int tag, String signature) { 962 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 963 StringBuilder sb = new StringBuilder(); 964 sb.append("Looking up "); 965 if (tag == JDWP.TypeTag.CLASS) { 966 sb.append("Class"); 967 } else if (tag == JDWP.TypeTag.INTERFACE) { 968 sb.append("Interface"); 969 } else if (tag == JDWP.TypeTag.ARRAY) { 970 sb.append("ArrayType"); 971 } else { 972 sb.append("UNKNOWN TAG: ").append(tag); 973 } 974 if (signature != null) { 975 sb.append(", signature='").append(signature).append('\''); 976 } 977 sb.append(", id=").append(id); 978 vm.printTrace(sb.toString()); 979 } 980 if (id == 0) { 981 return null; 982 } else { 983 ReferenceTypeImpl retType = null; 984 synchronized (this) { 985 if (typesByID != null) { 986 retType = (ReferenceTypeImpl)typesByID.get(id); 987 } 988 if (retType == null) { 989 retType = addReferenceType(id, tag, signature); 990 } 991 if (signature != null) { 992 retType.setSignature(signature); 993 } 994 } 995 return retType; 996 } 997 } 998 999 private JDWP.VirtualMachine.Capabilities capabilities() { 1000 if (capabilities == null) { 1001 try { 1002 capabilities = JDWP.VirtualMachine 1003 .Capabilities.process(vm); 1004 } catch (JDWPException exc) { 1005 throw exc.toJDIException(); 1006 } 1007 } 1008 return capabilities; 1009 } 1010 1011 private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew() { 1012 if (capabilitiesNew == null) { 1013 try { 1014 capabilitiesNew = JDWP.VirtualMachine 1015 .CapabilitiesNew.process(vm); 1016 } catch (JDWPException exc) { 1017 throw exc.toJDIException(); 1018 } 1019 } 1020 return capabilitiesNew; 1021 } 1022 1023 private synchronized ModuleReference addModule(long id) { 1024 if (modulesByID == null) { 1025 modulesByID = new HashMap<>(77); 1026 } 1027 ModuleReference module = new ModuleReferenceImpl(vm, id); 1028 modulesByID.put(id, module); 1029 return module; 1030 } 1031 1032 ModuleReference getModule(long id) { 1033 if (id == 0) { 1034 return null; 1035 } else { 1036 ModuleReference module = null; 1037 synchronized (this) { 1038 if (modulesByID != null) { 1039 module = modulesByID.get(id); 1040 } 1041 if (module == null) { 1042 module = addModule(id); 1043 } 1044 } 1045 return module; 1046 } 1047 } 1048 1049 private synchronized List<ModuleReference> retrieveAllModules() { 1050 ModuleReferenceImpl[] reqModules; 1051 try { 1052 reqModules = JDWP.VirtualMachine.AllModules.process(vm).modules; 1053 } catch (JDWPException exc) { 1054 throw exc.toJDIException(); 1055 } 1056 ArrayList<ModuleReference> modules = new ArrayList<>(); 1057 for (int i = 0; i < reqModules.length; i++) { 1058 long moduleRef = reqModules[i].ref(); 1059 ModuleReference module = getModule(moduleRef); 1060 modules.add(module); 1061 } 1062 return modules; 1063 } 1064 1065 private List<ReferenceType> retrieveClassesBySignature(String signature) { 1066 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 1067 vm.printTrace("Retrieving matching ReferenceTypes, sig=" + signature); 1068 } 1069 JDWP.VirtualMachine.ClassesBySignature.ClassInfo[] cinfos; 1070 try { 1071 cinfos = JDWP.VirtualMachine.ClassesBySignature. 1072 process(vm, signature).classes; 1073 } catch (JDWPException exc) { 1074 throw exc.toJDIException(); 1075 } 1076 1077 int count = cinfos.length; 1078 List<ReferenceType> list = new ArrayList<>(count); 1079 1080 // Hold lock during processing to improve performance 1081 synchronized (this) { 1082 for (int i = 0; i < count; i++) { 1083 JDWP.VirtualMachine.ClassesBySignature.ClassInfo ci = 1084 cinfos[i]; 1085 ReferenceTypeImpl type = referenceType(ci.typeID, 1086 ci.refTypeTag, 1087 signature); 1088 type.setStatus(ci.status); 1089 list.add(type); 1090 } 1091 } 1092 return list; 1093 } 1094 1095 private void retrieveAllClasses1_4() { 1096 JDWP.VirtualMachine.AllClasses.ClassInfo[] cinfos; 1097 try { 1098 cinfos = JDWP.VirtualMachine.AllClasses.process(vm).classes; 1099 } catch (JDWPException exc) { 1100 throw exc.toJDIException(); 1101 } 1102 1103 // Hold lock during processing to improve performance 1104 // and to have safe check/set of retrievedAllTypes 1105 synchronized (this) { 1106 if (!retrievedAllTypes) { 1107 // Number of classes 1108 int count = cinfos.length; 1109 for (int i = 0; i < count; i++) { 1110 JDWP.VirtualMachine.AllClasses.ClassInfo ci = cinfos[i]; 1111 ReferenceTypeImpl type = referenceType(ci.typeID, 1112 ci.refTypeTag, 1113 ci.signature); 1114 type.setStatus(ci.status); 1115 } 1116 retrievedAllTypes = true; 1117 } 1118 } 1119 } 1120 1121 private void retrieveAllClasses() { 1122 if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) { 1123 vm.printTrace("Retrieving all ReferenceTypes"); 1124 } 1125 1126 if (!vm.canGet1_5LanguageFeatures()) { 1127 retrieveAllClasses1_4(); 1128 return; 1129 } 1130 1131 /* 1132 * To save time (assuming the caller will be 1133 * using then) we will get the generic sigs too. 1134 */ 1135 JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo[] cinfos; 1136 try { 1137 cinfos = JDWP.VirtualMachine.AllClassesWithGeneric.process(vm).classes; 1138 } catch (JDWPException exc) { 1139 throw exc.toJDIException(); 1140 } 1141 1142 // Hold lock during processing to improve performance 1143 // and to have safe check/set of retrievedAllTypes 1144 synchronized (this) { 1145 if (!retrievedAllTypes) { 1146 // Number of classes 1147 int count = cinfos.length; 1148 for (int i = 0; i < count; i++) { 1149 JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo ci = 1150 cinfos[i]; 1151 ReferenceTypeImpl type = referenceType(ci.typeID, 1152 ci.refTypeTag, 1153 ci.signature); 1154 type.setGenericSignature(ci.genericSignature); 1155 type.setStatus(ci.status); 1156 } 1157 retrievedAllTypes = true; 1158 } 1159 } 1160 } 1161 1162 void sendToTarget(Packet packet) { 1163 target.send(packet); 1164 } 1165 1166 void waitForTargetReply(Packet packet) { 1167 target.waitForReply(packet); 1168 /* 1169 * If any object disposes have been batched up, send them now. 1170 */ 1171 processBatchedDisposes(); 1172 } 1173 1174 Type findBootType(String signature) throws ClassNotLoadedException { 1175 List<ReferenceType> types = retrieveClassesBySignature(signature); 1176 Iterator<ReferenceType> iter = types.iterator(); 1177 while (iter.hasNext()) { 1178 ReferenceType type = iter.next(); 1179 if (type.classLoader() == null) { 1180 return type; 1181 } 1182 } 1183 JNITypeParser parser = new JNITypeParser(signature); 1184 throw new ClassNotLoadedException(parser.typeName(), 1185 "Type " + parser.typeName() + " not loaded"); 1186 } 1187 1188 BooleanType theBooleanType() { 1189 if (theBooleanType == null) { 1190 synchronized(this) { 1191 if (theBooleanType == null) { 1192 theBooleanType = new BooleanTypeImpl(this); 1193 } 1194 } 1195 } 1196 return theBooleanType; 1197 } 1198 1199 ByteType theByteType() { 1200 if (theByteType == null) { 1201 synchronized(this) { 1202 if (theByteType == null) { 1203 theByteType = new ByteTypeImpl(this); 1204 } 1205 } 1206 } 1207 return theByteType; 1208 } 1209 1210 CharType theCharType() { 1211 if (theCharType == null) { 1212 synchronized(this) { 1213 if (theCharType == null) { 1214 theCharType = new CharTypeImpl(this); 1215 } 1216 } 1217 } 1218 return theCharType; 1219 } 1220 1221 ShortType theShortType() { 1222 if (theShortType == null) { 1223 synchronized(this) { 1224 if (theShortType == null) { 1225 theShortType = new ShortTypeImpl(this); 1226 } 1227 } 1228 } 1229 return theShortType; 1230 } 1231 1232 IntegerType theIntegerType() { 1233 if (theIntegerType == null) { 1234 synchronized(this) { 1235 if (theIntegerType == null) { 1236 theIntegerType = new IntegerTypeImpl(this); 1237 } 1238 } 1239 } 1240 return theIntegerType; 1241 } 1242 1243 LongType theLongType() { 1244 if (theLongType == null) { 1245 synchronized(this) { 1246 if (theLongType == null) { 1247 theLongType = new LongTypeImpl(this); 1248 } 1249 } 1250 } 1251 return theLongType; 1252 } 1253 1254 FloatType theFloatType() { 1255 if (theFloatType == null) { 1256 synchronized(this) { 1257 if (theFloatType == null) { 1258 theFloatType = new FloatTypeImpl(this); 1259 } 1260 } 1261 } 1262 return theFloatType; 1263 } 1264 1265 DoubleType theDoubleType() { 1266 if (theDoubleType == null) { 1267 synchronized(this) { 1268 if (theDoubleType == null) { 1269 theDoubleType = new DoubleTypeImpl(this); 1270 } 1271 } 1272 } 1273 return theDoubleType; 1274 } 1275 1276 VoidType theVoidType() { 1277 if (theVoidType == null) { 1278 synchronized(this) { 1279 if (theVoidType == null) { 1280 theVoidType = new VoidTypeImpl(this); 1281 } 1282 } 1283 } 1284 return theVoidType; 1285 } 1286 1287 PrimitiveType primitiveTypeMirror(byte tag) { 1288 switch (tag) { 1289 case JDWP.Tag.BOOLEAN: 1290 return theBooleanType(); 1291 case JDWP.Tag.BYTE: 1292 return theByteType(); 1293 case JDWP.Tag.CHAR: 1294 return theCharType(); 1295 case JDWP.Tag.SHORT: 1296 return theShortType(); 1297 case JDWP.Tag.INT: 1298 return theIntegerType(); 1299 case JDWP.Tag.LONG: 1300 return theLongType(); 1301 case JDWP.Tag.FLOAT: 1302 return theFloatType(); 1303 case JDWP.Tag.DOUBLE: 1304 return theDoubleType(); 1305 default: 1306 throw new IllegalArgumentException("Unrecognized primitive tag " + tag); 1307 } 1308 } 1309 1310 private void processBatchedDisposes() { 1311 if (shutdown) { 1312 return; 1313 } 1314 1315 JDWP.VirtualMachine.DisposeObjects.Request[] requests = null; 1316 synchronized(batchedDisposeRequests) { 1317 int size = batchedDisposeRequests.size(); 1318 if (size >= DISPOSE_THRESHOLD) { 1319 if ((traceFlags & TRACE_OBJREFS) != 0) { 1320 printTrace("Dispose threashold reached. Will dispose " 1321 + size + " object references..."); 1322 } 1323 requests = new JDWP.VirtualMachine.DisposeObjects.Request[size]; 1324 for (int i = 0; i < requests.length; i++) { 1325 SoftObjectReference ref = batchedDisposeRequests.get(i); 1326 if ((traceFlags & TRACE_OBJREFS) != 0) { 1327 printTrace("Disposing object " + ref.key().longValue() + 1328 " (ref count = " + ref.count() + ")"); 1329 } 1330 1331 // This is kludgy. We temporarily re-create an object 1332 // reference so that we can correctly pass its id to the 1333 // JDWP command. 1334 requests[i] = 1335 new JDWP.VirtualMachine.DisposeObjects.Request( 1336 new ObjectReferenceImpl(this, ref.key().longValue()), 1337 ref.count()); 1338 } 1339 batchedDisposeRequests.clear(); 1340 } 1341 } 1342 if (requests != null) { 1343 try { 1344 JDWP.VirtualMachine.DisposeObjects.process(vm, requests); 1345 } catch (JDWPException exc) { 1346 throw exc.toJDIException(); 1347 } 1348 } 1349 } 1350 1351 private void batchForDispose(SoftObjectReference ref) { 1352 if ((traceFlags & TRACE_OBJREFS) != 0) { 1353 printTrace("Batching object " + ref.key().longValue() + 1354 " for dispose (ref count = " + ref.count() + ")"); 1355 } 1356 batchedDisposeRequests.add(ref); 1357 } 1358 1359 private void processQueue() { 1360 Reference<?> ref; 1361 //if ((traceFlags & TRACE_OBJREFS) != 0) { 1362 // printTrace("Checking for softly reachable objects"); 1363 //} 1364 while ((ref = referenceQueue.poll()) != null) { 1365 SoftObjectReference softRef = (SoftObjectReference)ref; 1366 removeObjectMirror(softRef); 1367 batchForDispose(softRef); 1368 } 1369 } 1370 1371 synchronized ObjectReferenceImpl objectMirror(long id, int tag) { 1372 1373 // Handle any queue elements that are not strongly reachable 1374 processQueue(); 1375 1376 if (id == 0) { 1377 return null; 1378 } 1379 ObjectReferenceImpl object = null; 1380 Long key = id; 1381 1382 /* 1383 * Attempt to retrieve an existing object reference 1384 */ 1385 SoftObjectReference ref = objectsByID.get(key); 1386 if (ref != null) { 1387 object = ref.object(); 1388 } 1389 1390 /* 1391 * If the object wasn't in the table, or it's soft reference was 1392 * cleared, create a new instance. 1393 */ 1394 if (object == null) { 1395 switch (tag) { 1396 case JDWP.Tag.OBJECT: 1397 object = new ObjectReferenceImpl(vm, id); 1398 break; 1399 case JDWP.Tag.STRING: 1400 object = new StringReferenceImpl(vm, id); 1401 break; 1402 case JDWP.Tag.ARRAY: 1403 object = new ArrayReferenceImpl(vm, id); 1404 break; 1405 case JDWP.Tag.THREAD: 1406 ThreadReferenceImpl thread = 1407 new ThreadReferenceImpl(vm, id); 1408 thread.addListener(this); 1409 object = thread; 1410 break; 1411 case JDWP.Tag.THREAD_GROUP: 1412 object = new ThreadGroupReferenceImpl(vm, id); 1413 break; 1414 case JDWP.Tag.CLASS_LOADER: 1415 object = new ClassLoaderReferenceImpl(vm, id); 1416 break; 1417 case JDWP.Tag.CLASS_OBJECT: 1418 object = new ClassObjectReferenceImpl(vm, id); 1419 break; 1420 default: 1421 throw new IllegalArgumentException("Invalid object tag: " + tag); 1422 } 1423 ref = new SoftObjectReference(key, object, referenceQueue); 1424 1425 /* 1426 * If there was no previous entry in the table, we add one here 1427 * If the previous entry was cleared, we replace it here. 1428 */ 1429 objectsByID.put(key, ref); 1430 if ((traceFlags & TRACE_OBJREFS) != 0) { 1431 printTrace("Creating new " + 1432 object.getClass().getName() + " (id = " + id + ")"); 1433 } 1434 } else { 1435 ref.incrementCount(); 1436 } 1437 1438 return object; 1439 } 1440 1441 synchronized void removeObjectMirror(ObjectReferenceImpl object) { 1442 // Handle any queue elements that are not strongly reachable 1443 processQueue(); 1444 1445 SoftObjectReference ref = objectsByID.remove(object.ref()); 1446 if (ref != null) { 1447 batchForDispose(ref); 1448 } else { 1449 /* 1450 * If there's a live ObjectReference about, it better be part 1451 * of the cache. 1452 */ 1453 throw new InternalException("ObjectReference " + object.ref() + 1454 " not found in object cache"); 1455 } 1456 } 1457 1458 synchronized void removeObjectMirror(SoftObjectReference ref) { 1459 /* 1460 * This will remove the soft reference if it has not been 1461 * replaced in the cache. 1462 */ 1463 objectsByID.remove(ref.key()); 1464 } 1465 1466 ObjectReferenceImpl objectMirror(long id) { 1467 return objectMirror(id, JDWP.Tag.OBJECT); 1468 } 1469 1470 StringReferenceImpl stringMirror(long id) { 1471 return (StringReferenceImpl)objectMirror(id, JDWP.Tag.STRING); 1472 } 1473 1474 ArrayReferenceImpl arrayMirror(long id) { 1475 return (ArrayReferenceImpl)objectMirror(id, JDWP.Tag.ARRAY); 1476 } 1477 1478 ThreadReferenceImpl threadMirror(long id) { 1479 return (ThreadReferenceImpl)objectMirror(id, JDWP.Tag.THREAD); 1480 } 1481 1482 ThreadGroupReferenceImpl threadGroupMirror(long id) { 1483 return (ThreadGroupReferenceImpl)objectMirror(id, 1484 JDWP.Tag.THREAD_GROUP); 1485 } 1486 1487 ClassLoaderReferenceImpl classLoaderMirror(long id) { 1488 return (ClassLoaderReferenceImpl)objectMirror(id, 1489 JDWP.Tag.CLASS_LOADER); 1490 } 1491 1492 ClassObjectReferenceImpl classObjectMirror(long id) { 1493 return (ClassObjectReferenceImpl)objectMirror(id, 1494 JDWP.Tag.CLASS_OBJECT); 1495 } 1496 1497 ModuleReferenceImpl moduleMirror(long id) { 1498 return (ModuleReferenceImpl)getModule(id); 1499 } 1500 1501 /* 1502 * Implementation of PathSearchingVirtualMachine 1503 */ 1504 private JDWP.VirtualMachine.ClassPaths getClasspath() { 1505 if (pathInfo == null) { 1506 try { 1507 pathInfo = JDWP.VirtualMachine.ClassPaths.process(vm); 1508 } catch (JDWPException exc) { 1509 throw exc.toJDIException(); 1510 } 1511 } 1512 return pathInfo; 1513 } 1514 1515 public List<String> classPath() { 1516 return Arrays.asList(getClasspath().classpaths); 1517 } 1518 1519 public List<String> bootClassPath() { 1520 return Collections.emptyList(); 1521 } 1522 1523 public String baseDirectory() { 1524 return getClasspath().baseDir; 1525 } 1526 1527 public void setDefaultStratum(String stratum) { 1528 defaultStratum = stratum; 1529 if (stratum == null) { 1530 stratum = ""; 1531 } 1532 try { 1533 JDWP.VirtualMachine.SetDefaultStratum.process(vm, 1534 stratum); 1535 } catch (JDWPException exc) { 1536 throw exc.toJDIException(); 1537 } 1538 } 1539 1540 public String getDefaultStratum() { 1541 return defaultStratum; 1542 } 1543 1544 ThreadGroup threadGroupForJDI() { 1545 return threadGroupForJDI; 1546 } 1547 1548 static private class SoftObjectReference extends SoftReference<ObjectReferenceImpl> { 1549 int count; 1550 Long key; 1551 1552 SoftObjectReference(Long key, ObjectReferenceImpl mirror, 1553 ReferenceQueue<ObjectReferenceImpl> queue) { 1554 super(mirror, queue); 1555 this.count = 1; 1556 this.key = key; 1557 } 1558 1559 int count() { 1560 return count; 1561 } 1562 1563 void incrementCount() { 1564 count++; 1565 } 1566 1567 Long key() { 1568 return key; 1569 } 1570 1571 ObjectReferenceImpl object() { 1572 return get(); 1573 } 1574 } 1575 }