1 /*
   2  * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.jdi;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Collection;
  30 import java.util.Iterator;
  31 import java.util.NoSuchElementException;
  32 import java.util.Spliterator;
  33 import java.util.Spliterators;
  34 
  35 import com.sun.jdi.Field;
  36 import com.sun.jdi.InternalException;
  37 import com.sun.jdi.Locatable;
  38 import com.sun.jdi.Location;
  39 import com.sun.jdi.Method;
  40 import com.sun.jdi.ObjectReference;
  41 import com.sun.jdi.ReferenceType;
  42 import com.sun.jdi.ThreadReference;
  43 import com.sun.jdi.VMDisconnectedException;
  44 import com.sun.jdi.Value;
  45 import com.sun.jdi.VirtualMachine;
  46 import com.sun.jdi.event.AccessWatchpointEvent;
  47 import com.sun.jdi.event.BreakpointEvent;
  48 import com.sun.jdi.event.ClassPrepareEvent;
  49 import com.sun.jdi.event.ClassUnloadEvent;
  50 import com.sun.jdi.event.Event;
  51 import com.sun.jdi.event.EventIterator;
  52 import com.sun.jdi.event.EventSet;
  53 import com.sun.jdi.event.ExceptionEvent;
  54 import com.sun.jdi.event.MethodEntryEvent;
  55 import com.sun.jdi.event.MethodExitEvent;
  56 import com.sun.jdi.event.ModificationWatchpointEvent;
  57 import com.sun.jdi.event.MonitorContendedEnterEvent;
  58 import com.sun.jdi.event.MonitorContendedEnteredEvent;
  59 import com.sun.jdi.event.MonitorWaitEvent;
  60 import com.sun.jdi.event.MonitorWaitedEvent;
  61 import com.sun.jdi.event.StepEvent;
  62 import com.sun.jdi.event.ThreadDeathEvent;
  63 import com.sun.jdi.event.ThreadStartEvent;
  64 import com.sun.jdi.event.VMDeathEvent;
  65 import com.sun.jdi.event.VMDisconnectEvent;
  66 import com.sun.jdi.event.VMStartEvent;
  67 import com.sun.jdi.event.WatchpointEvent;
  68 import com.sun.jdi.request.EventRequest;
  69 
  70 enum EventDestination {UNKNOWN_EVENT, INTERNAL_EVENT, CLIENT_EVENT};
  71 
  72 /*
  73  * An EventSet is normally created by the transport reader thread when
  74  * it reads a JDWP Composite command.  The constructor doesn't unpack
  75  * the events contained in the Composite command and create EventImpls
  76  * for them because that process might involve calling back into the back-end
  77  * which should not be done by the transport reader thread.  Instead,
  78  * the raw bytes of the packet are read and stored in the EventSet.
  79  * The EventSet is then added to each EventQueue. When an EventSet is
  80  * removed from an EventQueue, the EventSetImpl.build() method is called.
  81  * This method reads the packet bytes and creates the actual EventImpl objects.
  82  * build() also filters out events for our internal handler and puts them in
  83  * their own EventSet.  This means that the EventImpls that are in the EventSet
  84  * that is on the queues are all for client requests.
  85  */
  86 public class EventSetImpl extends ArrayList<Event> implements EventSet {
  87     private static final long serialVersionUID = -4857338819787924570L;
  88     private VirtualMachineImpl vm; // we implement Mirror
  89     private Packet pkt;
  90     private byte suspendPolicy;
  91     private EventSetImpl internalEventSet;
  92 
  93     public String toString() {
  94         String string = "event set, policy:" + suspendPolicy +
  95                         ", count:" + this.size() + " = {";
  96         boolean first = true;
  97         for (Event event : this) {
  98             if (!first) {
  99                 string += ", ";
 100             }
 101             string += event.toString();
 102             first = false;
 103         }
 104         string += "}";
 105         return string;
 106     }
 107 
 108     abstract class EventImpl extends MirrorImpl implements Event {
 109 
 110         private final byte eventCmd;
 111         private final int requestID;
 112         // This is set only for client requests, not internal requests.
 113         private final EventRequest request;
 114 
 115         /**
 116          * Constructor for events.
 117          */
 118         protected EventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
 119                             int requestID) {
 120             super(EventSetImpl.this.vm);
 121             this.eventCmd = evt.eventKind();
 122             this.requestID = requestID;
 123             EventRequestManagerImpl ermi = EventSetImpl.this.
 124                 vm.eventRequestManagerImpl();
 125             this.request =  ermi.request(eventCmd, requestID);
 126         }
 127 
 128         /*
 129          * Override superclass back to default equality
 130          */
 131         public boolean equals(Object obj) {
 132             return this == obj;
 133         }
 134 
 135         public int hashCode() {
 136             return System.identityHashCode(this);
 137         }
 138 
 139         /**
 140          * Constructor for VM disconnected events.
 141          */
 142         protected EventImpl(byte eventCmd) {
 143             super(EventSetImpl.this.vm);
 144             this.eventCmd = eventCmd;
 145             this.requestID = 0;
 146             this.request = null;
 147         }
 148 
 149         public EventRequest request() {
 150             return request;
 151         }
 152 
 153         int requestID() {
 154             return requestID;
 155         }
 156 
 157         EventDestination destination() {
 158             /*
 159              * We need to decide if this event is for
 160              * 1. an internal request
 161              * 2. a client request that is no longer available, ie
 162              *    it has been deleted, or disabled and re-enabled
 163              *    which gives it a new ID.
 164              * 3. a current client request that is disabled
 165              * 4. a current enabled client request.
 166              *
 167              * We will filter this set into a set
 168              * that contains only 1s for our internal queue
 169              * and a set that contains only 4s for our client queue.
 170              * If we get an EventSet that contains only 2 and 3
 171              * then we have to resume it if it is not SUSPEND_NONE
 172              * because no one else will.
 173              */
 174             if (requestID == 0) {
 175                 /* An unsolicited event.  These have traditionally
 176                  * been treated as client events.
 177                  */
 178                 return EventDestination.CLIENT_EVENT;
 179             }
 180 
 181             // Is this an event for a current client request?
 182             if (request == null) {
 183                 // Nope.  Is it an event for an internal request?
 184                 EventRequestManagerImpl ermi = this.vm.getInternalEventRequestManager();
 185                 if (ermi.request(eventCmd, requestID) != null) {
 186                     // Yep
 187                     return EventDestination.INTERNAL_EVENT;
 188                 }
 189                 return EventDestination.UNKNOWN_EVENT;
 190             }
 191 
 192             // We found a client request
 193             if (request.isEnabled()) {
 194                 return EventDestination.CLIENT_EVENT;
 195             }
 196             return EventDestination.UNKNOWN_EVENT;
 197         }
 198 
 199         abstract String eventName();
 200 
 201         public String toString() {
 202             return eventName();
 203         }
 204 
 205     }
 206 
 207     abstract class ThreadedEventImpl extends EventImpl {
 208         private ThreadReference thread;
 209 
 210         ThreadedEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
 211                           int requestID, ThreadReference thread) {
 212             super(evt, requestID);
 213             this.thread = thread;
 214         }
 215 
 216         public ThreadReference thread() {
 217             return thread;
 218         }
 219 
 220         public String toString() {
 221             return eventName() + " in thread " + thread.name();
 222         }
 223     }
 224 
 225     abstract class LocatableEventImpl extends ThreadedEventImpl
 226                                       implements Locatable {
 227         private Location location;
 228 
 229         LocatableEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
 230                            int requestID,
 231                            ThreadReference thread, Location location) {
 232             super(evt, requestID, thread);
 233             this.location = location;
 234         }
 235 
 236         public Location location() {
 237             return location;
 238         }
 239 
 240         /**
 241          * For MethodEntry and MethodExit
 242          */
 243         public Method method() {
 244             return location.method();
 245         }
 246 
 247         public String toString() {
 248             return eventName() + "@" +
 249                    ((location() == null) ? " null" : location().toString()) +
 250                    " in thread " + thread().name();
 251         }
 252     }
 253 
 254     class BreakpointEventImpl extends LocatableEventImpl
 255                               implements BreakpointEvent {
 256         BreakpointEventImpl(JDWP.Event.Composite.Events.Breakpoint evt) {
 257             super(evt, evt.requestID, evt.thread, evt.location);
 258         }
 259 
 260         String eventName() {
 261             return "BreakpointEvent";
 262         }
 263     }
 264 
 265     class StepEventImpl extends LocatableEventImpl implements StepEvent {
 266         StepEventImpl(JDWP.Event.Composite.Events.SingleStep evt) {
 267             super(evt, evt.requestID, evt.thread, evt.location);
 268         }
 269 
 270         String eventName() {
 271             return "StepEvent";
 272         }
 273     }
 274 
 275     class MethodEntryEventImpl extends LocatableEventImpl
 276                                implements MethodEntryEvent {
 277         MethodEntryEventImpl(JDWP.Event.Composite.Events.MethodEntry evt) {
 278             super(evt, evt.requestID, evt.thread, evt.location);
 279         }
 280 
 281         String eventName() {
 282             return "MethodEntryEvent";
 283         }
 284     }
 285 
 286     class MethodExitEventImpl extends LocatableEventImpl
 287                             implements MethodExitEvent {
 288         private Value returnVal = null;
 289 
 290         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExit evt) {
 291             super(evt, evt.requestID, evt.thread, evt.location);
 292         }
 293 
 294         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExitWithReturnValue evt) {
 295             super(evt, evt.requestID, evt.thread, evt.location);
 296             returnVal = evt.value;
 297         }
 298 
 299         String eventName() {
 300             return "MethodExitEvent";
 301         }
 302 
 303         public Value returnValue() {
 304             if (!this.vm.canGetMethodReturnValues()) {
 305                 throw new UnsupportedOperationException(
 306                 "target does not support return values in MethodExit events");
 307             }
 308             return returnVal;
 309         }
 310 
 311     }
 312 
 313     class MonitorContendedEnterEventImpl extends LocatableEventImpl
 314                             implements MonitorContendedEnterEvent {
 315         private ObjectReference monitor = null;
 316 
 317         MonitorContendedEnterEventImpl(JDWP.Event.Composite.Events.MonitorContendedEnter evt) {
 318             super(evt, evt.requestID, evt.thread, evt.location);
 319             this.monitor = evt.object;
 320         }
 321 
 322         String eventName() {
 323             return "MonitorContendedEnter";
 324         }
 325 
 326         public ObjectReference  monitor() {
 327             return monitor;
 328         };
 329 
 330     }
 331 
 332     class MonitorContendedEnteredEventImpl extends LocatableEventImpl
 333                             implements MonitorContendedEnteredEvent {
 334         private ObjectReference monitor = null;
 335 
 336         MonitorContendedEnteredEventImpl(JDWP.Event.Composite.Events.MonitorContendedEntered evt) {
 337             super(evt, evt.requestID, evt.thread, evt.location);
 338             this.monitor = evt.object;
 339         }
 340 
 341         String eventName() {
 342             return "MonitorContendedEntered";
 343         }
 344 
 345         public ObjectReference  monitor() {
 346             return monitor;
 347         };
 348 
 349     }
 350 
 351     class MonitorWaitEventImpl extends LocatableEventImpl
 352                             implements MonitorWaitEvent {
 353         private ObjectReference monitor = null;
 354         private long timeout;
 355 
 356         MonitorWaitEventImpl(JDWP.Event.Composite.Events.MonitorWait evt) {
 357             super(evt, evt.requestID, evt.thread, evt.location);
 358             this.monitor = evt.object;
 359             this.timeout = evt.timeout;
 360         }
 361 
 362         String eventName() {
 363             return "MonitorWait";
 364         }
 365 
 366         public ObjectReference  monitor() {
 367             return monitor;
 368         };
 369 
 370         public long timeout() {
 371             return timeout;
 372         }
 373     }
 374 
 375     class MonitorWaitedEventImpl extends LocatableEventImpl
 376                             implements MonitorWaitedEvent {
 377         private ObjectReference monitor = null;
 378         private boolean timed_out;
 379 
 380         MonitorWaitedEventImpl(JDWP.Event.Composite.Events.MonitorWaited evt) {
 381             super(evt, evt.requestID, evt.thread, evt.location);
 382             this.monitor = evt.object;
 383             this.timed_out = evt.timed_out;
 384         }
 385 
 386         String eventName() {
 387             return "MonitorWaited";
 388         }
 389 
 390         public ObjectReference  monitor() {
 391             return monitor;
 392         };
 393 
 394         public boolean timedout() {
 395             return timed_out;
 396         }
 397     }
 398 
 399     class ClassPrepareEventImpl extends ThreadedEventImpl
 400                             implements ClassPrepareEvent {
 401         private ReferenceType referenceType;
 402 
 403         ClassPrepareEventImpl(JDWP.Event.Composite.Events.ClassPrepare evt) {
 404             super(evt, evt.requestID, evt.thread);
 405             referenceType = this.vm.referenceType(evt.typeID, evt.refTypeTag,
 406                                                   evt.signature);
 407             ((ReferenceTypeImpl)referenceType).setStatus(evt.status);
 408         }
 409 
 410         public ReferenceType referenceType() {
 411             return referenceType;
 412         }
 413 
 414         String eventName() {
 415             return "ClassPrepareEvent";
 416         }
 417     }
 418 
 419     class ClassUnloadEventImpl extends EventImpl implements ClassUnloadEvent {
 420         private String classSignature;
 421 
 422         ClassUnloadEventImpl(JDWP.Event.Composite.Events.ClassUnload evt) {
 423             super(evt, evt.requestID);
 424             this.classSignature = evt.signature;
 425         }
 426 
 427         public String className() {
 428             int index = classSignature.indexOf(";");
 429             if (index == classSignature.length()) {
 430                 // trim leading 'L' and trailing ';'
 431                 return classSignature.substring(1, classSignature.length() - 1)
 432                                      .replace('/', '.');
 433             } else {
 434                 // type descriptor of a hidden class is "L" + N + ";" + "/" + <suffix>
 435                 // the class name is mapped to: N.replace('/', '.') + "/" + <suffix>
 436                 return classSignature.substring(1, index)
 437                                      .replace('/', '.')
 438                        + classSignature.substring(index+1);  // skip ';'
 439             }
 440         }
 441 
 442         public String classSignature() {
 443             return classSignature;
 444         }
 445 
 446         String eventName() {
 447             return "ClassUnloadEvent";
 448         }
 449     }
 450 
 451     class ExceptionEventImpl extends LocatableEventImpl
 452                                              implements ExceptionEvent {
 453         private ObjectReference exception;
 454         private Location catchLocation;
 455 
 456         ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt) {
 457             super(evt, evt.requestID, evt.thread, evt.location);
 458             this.exception = evt.exception;
 459             this.catchLocation = evt.catchLocation;
 460         }
 461 
 462         public ObjectReference exception() {
 463             return exception;
 464         }
 465 
 466         public Location catchLocation() {
 467             return catchLocation;
 468         }
 469 
 470         String eventName() {
 471             return "ExceptionEvent";
 472         }
 473     }
 474 
 475     class ThreadDeathEventImpl extends ThreadedEventImpl
 476                                         implements ThreadDeathEvent {
 477         ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) {
 478             super(evt, evt.requestID, evt.thread);
 479         }
 480 
 481         String eventName() {
 482             return "ThreadDeathEvent";
 483         }
 484     }
 485 
 486     class ThreadStartEventImpl extends ThreadedEventImpl
 487                                         implements ThreadStartEvent {
 488         ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) {
 489             super(evt, evt.requestID, evt.thread);
 490         }
 491 
 492         String eventName() {
 493             return "ThreadStartEvent";
 494         }
 495     }
 496 
 497     class VMStartEventImpl extends ThreadedEventImpl
 498                                         implements VMStartEvent {
 499         VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) {
 500             super(evt, evt.requestID, evt.thread);
 501         }
 502 
 503         String eventName() {
 504             return "VMStartEvent";
 505         }
 506     }
 507 
 508     class VMDeathEventImpl extends EventImpl implements VMDeathEvent {
 509 
 510         VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) {
 511             super(evt, evt.requestID);
 512         }
 513 
 514         String eventName() {
 515             return "VMDeathEvent";
 516         }
 517     }
 518 
 519     class VMDisconnectEventImpl extends EventImpl
 520                                          implements VMDisconnectEvent {
 521 
 522         VMDisconnectEventImpl() {
 523             super((byte)JDWP.EventKind.VM_DISCONNECTED);
 524         }
 525 
 526         String eventName() {
 527             return "VMDisconnectEvent";
 528         }
 529     }
 530 
 531     abstract class WatchpointEventImpl extends LocatableEventImpl
 532                                             implements WatchpointEvent {
 533         private final ReferenceTypeImpl refType;
 534         private final long fieldID;
 535         private final ObjectReference object;
 536         private Field field = null;
 537 
 538         WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
 539                             int requestID,
 540                             ThreadReference thread, Location location,
 541                             byte refTypeTag, long typeID, long fieldID,
 542                             ObjectReference object) {
 543             super(evt, requestID, thread, location);
 544             this.refType = this.vm.referenceType(typeID, refTypeTag);
 545             this.fieldID = fieldID;
 546             this.object = object;
 547         }
 548 
 549         public Field field() {
 550             if (field == null) {
 551                 field = refType.getFieldMirror(fieldID);
 552             }
 553             return field;
 554         }
 555 
 556         public ObjectReference object() {
 557             return object;
 558         }
 559 
 560         public Value valueCurrent() {
 561             if (object == null) {
 562                 return refType.getValue(field());
 563             } else {
 564                 return object.getValue(field());
 565             }
 566         }
 567     }
 568 
 569     class AccessWatchpointEventImpl extends WatchpointEventImpl
 570                                             implements AccessWatchpointEvent {
 571 
 572         AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt) {
 573             super(evt, evt.requestID, evt.thread, evt.location,
 574                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
 575         }
 576 
 577         String eventName() {
 578             return "AccessWatchpoint";
 579         }
 580     }
 581 
 582     class ModificationWatchpointEventImpl extends WatchpointEventImpl
 583                            implements ModificationWatchpointEvent {
 584         Value newValue;
 585 
 586         ModificationWatchpointEventImpl(
 587                         JDWP.Event.Composite.Events.FieldModification evt) {
 588             super(evt, evt.requestID, evt.thread, evt.location,
 589                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
 590             this.newValue = evt.valueToBe;
 591         }
 592 
 593         public Value valueToBe() {
 594             return newValue;
 595         }
 596 
 597         String eventName() {
 598             return "ModificationWatchpoint";
 599         }
 600     }
 601 
 602     /**
 603      * Events are constructed on the thread which reads all data from the
 604      * transport. This means that the packet cannot be converted to real
 605      * JDI objects as that may involve further communications with the
 606      * back end which would deadlock.
 607      *
 608      * Hence the {@link #build()} method below called by EventQueue.
 609      */
 610     EventSetImpl(VirtualMachine aVm, Packet pkt) {
 611         super();
 612 
 613         // From "MirrorImpl":
 614         // Yes, its a bit of a hack. But by doing it this
 615         // way, this is the only place we have to change
 616         // typing to substitute a new impl.
 617         vm = (VirtualMachineImpl)aVm;
 618 
 619         this.pkt = pkt;
 620     }
 621 
 622     /**
 623      * Constructor for special events like VM disconnected
 624      */
 625     EventSetImpl(VirtualMachine aVm, byte eventCmd) {
 626         this(aVm, null);
 627         suspendPolicy = JDWP.SuspendPolicy.NONE;
 628         switch (eventCmd) {
 629             case JDWP.EventKind.VM_DISCONNECTED:
 630                 addEvent(new VMDisconnectEventImpl());
 631                 break;
 632 
 633             default:
 634                 throw new InternalException("Bad singleton event code");
 635         }
 636     }
 637 
 638     private void addEvent(EventImpl evt) {
 639         // Note that this class has a public add method that throws
 640         // an exception so that clients can't modify the EventSet
 641         super.add(evt);
 642     }
 643 
 644     /*
 645      * Complete the construction of an EventSet.  This is called from
 646      * an event handler thread.  It upacks the JDWP events inside
 647      * the packet and creates EventImpls for them.  The EventSet is already
 648      * on EventQueues when this is called, so it has to be synch.
 649      */
 650     synchronized void build() {
 651         if (pkt == null) {
 652             return;
 653         }
 654         PacketStream ps = new PacketStream(vm, pkt);
 655         JDWP.Event.Composite compEvt = new JDWP.Event.Composite(vm, ps);
 656         suspendPolicy = compEvt.suspendPolicy;
 657         if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
 658             switch(suspendPolicy) {
 659                 case JDWP.SuspendPolicy.ALL:
 660                     vm.printTrace("EventSet: SUSPEND_ALL");
 661                     break;
 662 
 663                 case JDWP.SuspendPolicy.EVENT_THREAD:
 664                     vm.printTrace("EventSet: SUSPEND_EVENT_THREAD");
 665                     break;
 666 
 667                 case JDWP.SuspendPolicy.NONE:
 668                     vm.printTrace("EventSet: SUSPEND_NONE");
 669                     break;
 670             }
 671         }
 672 
 673         ThreadReference fix6485605 = null;
 674         for (int i = 0; i < compEvt.events.length; i++) {
 675             EventImpl evt = createEvent(compEvt.events[i]);
 676             if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
 677                 try {
 678                     vm.printTrace("Event: " + evt);
 679                 } catch (VMDisconnectedException ee) {
 680                     // ignore - see bug 6502716
 681                 }
 682             }
 683 
 684             switch (evt.destination()) {
 685                 case UNKNOWN_EVENT:
 686                     // Ignore disabled, deleted, unknown events, but
 687                     // save the thread if there is one since we might
 688                     // have to resume it.  Note that events for different
 689                     // threads can't be in the same event set.
 690                     if (evt instanceof ThreadedEventImpl &&
 691                         suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
 692                         fix6485605 = ((ThreadedEventImpl)evt).thread();
 693                     }
 694                     continue;
 695                 case CLIENT_EVENT:
 696                     addEvent(evt);
 697                     break;
 698                 case INTERNAL_EVENT:
 699                     if (internalEventSet == null) {
 700                         internalEventSet = new EventSetImpl(this.vm, null);
 701                     }
 702                     internalEventSet.addEvent(evt);
 703                     break;
 704                 default:
 705                     throw new InternalException("Invalid event destination");
 706             }
 707         }
 708         pkt = null; // No longer needed - free it up
 709 
 710         // Avoid hangs described in 6296125, 6293795
 711         if (super.size() == 0) {
 712             // This set has no client events.  If we don't do
 713             // needed resumes, no one else is going to.
 714             if (suspendPolicy == JDWP.SuspendPolicy.ALL) {
 715                 vm.resume();
 716             } else if (suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
 717                 // See bug 6485605.
 718                 if (fix6485605 != null) {
 719                     fix6485605.resume();
 720                 } else {
 721                     // apparently, there is nothing to resume.
 722                 }
 723             }
 724             suspendPolicy = JDWP.SuspendPolicy.NONE;
 725 
 726         }
 727 
 728     }
 729 
 730     /**
 731      * Filter out internal events
 732      */
 733     EventSet userFilter() {
 734         return this;
 735     }
 736 
 737     /**
 738      * Filter out user events.
 739      */
 740     EventSet internalFilter() {
 741         return this.internalEventSet;
 742     }
 743 
 744     EventImpl createEvent(JDWP.Event.Composite.Events evt) {
 745         JDWP.Event.Composite.Events.EventsCommon comm = evt.aEventsCommon;
 746         switch (evt.eventKind) {
 747             case JDWP.EventKind.THREAD_START:
 748                 return new ThreadStartEventImpl(
 749                       (JDWP.Event.Composite.Events.ThreadStart)comm);
 750 
 751             case JDWP.EventKind.THREAD_END:
 752                 return new ThreadDeathEventImpl(
 753                       (JDWP.Event.Composite.Events.ThreadDeath)comm);
 754 
 755             case JDWP.EventKind.EXCEPTION:
 756                 return new ExceptionEventImpl(
 757                       (JDWP.Event.Composite.Events.Exception)comm);
 758 
 759             case JDWP.EventKind.BREAKPOINT:
 760                 return new BreakpointEventImpl(
 761                       (JDWP.Event.Composite.Events.Breakpoint)comm);
 762 
 763             case JDWP.EventKind.METHOD_ENTRY:
 764                 return new MethodEntryEventImpl(
 765                       (JDWP.Event.Composite.Events.MethodEntry)comm);
 766 
 767             case JDWP.EventKind.METHOD_EXIT:
 768                 return new MethodExitEventImpl(
 769                       (JDWP.Event.Composite.Events.MethodExit)comm);
 770 
 771             case JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
 772                 return new MethodExitEventImpl(
 773                       (JDWP.Event.Composite.Events.MethodExitWithReturnValue)comm);
 774 
 775             case JDWP.EventKind.FIELD_ACCESS:
 776                 return new AccessWatchpointEventImpl(
 777                       (JDWP.Event.Composite.Events.FieldAccess)comm);
 778 
 779             case JDWP.EventKind.FIELD_MODIFICATION:
 780                 return new ModificationWatchpointEventImpl(
 781                       (JDWP.Event.Composite.Events.FieldModification)comm);
 782 
 783             case JDWP.EventKind.SINGLE_STEP:
 784                 return new StepEventImpl(
 785                       (JDWP.Event.Composite.Events.SingleStep)comm);
 786 
 787             case JDWP.EventKind.CLASS_PREPARE:
 788                 return new ClassPrepareEventImpl(
 789                       (JDWP.Event.Composite.Events.ClassPrepare)comm);
 790 
 791             case JDWP.EventKind.CLASS_UNLOAD:
 792                 return new ClassUnloadEventImpl(
 793                       (JDWP.Event.Composite.Events.ClassUnload)comm);
 794 
 795             case JDWP.EventKind.MONITOR_CONTENDED_ENTER:
 796                 return new MonitorContendedEnterEventImpl(
 797                       (JDWP.Event.Composite.Events.MonitorContendedEnter)comm);
 798 
 799             case JDWP.EventKind.MONITOR_CONTENDED_ENTERED:
 800                 return new MonitorContendedEnteredEventImpl(
 801                       (JDWP.Event.Composite.Events.MonitorContendedEntered)comm);
 802 
 803             case JDWP.EventKind.MONITOR_WAIT:
 804                 return new MonitorWaitEventImpl(
 805                       (JDWP.Event.Composite.Events.MonitorWait)comm);
 806 
 807             case JDWP.EventKind.MONITOR_WAITED:
 808                 return new MonitorWaitedEventImpl(
 809                       (JDWP.Event.Composite.Events.MonitorWaited)comm);
 810 
 811             case JDWP.EventKind.VM_START:
 812                 return new VMStartEventImpl(
 813                       (JDWP.Event.Composite.Events.VMStart)comm);
 814 
 815             case JDWP.EventKind.VM_DEATH:
 816                 return new VMDeathEventImpl(
 817                       (JDWP.Event.Composite.Events.VMDeath)comm);
 818 
 819             default:
 820                 // Ignore unknown event types
 821                 System.err.println("Ignoring event cmd " +
 822                                    evt.eventKind + " from the VM");
 823                 return null;
 824         }
 825     }
 826 
 827     public VirtualMachine virtualMachine() {
 828         return vm;
 829     }
 830 
 831     public int suspendPolicy() {
 832         return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy);
 833     }
 834 
 835     private ThreadReference eventThread() {
 836         for (Event event : this) {
 837             if (event instanceof ThreadedEventImpl) {
 838                 return ((ThreadedEventImpl)event).thread();
 839             }
 840         }
 841         return null;
 842     }
 843 
 844     public void resume() {
 845         switch (suspendPolicy()) {
 846             case EventRequest.SUSPEND_ALL:
 847                 vm.resume();
 848                 break;
 849             case EventRequest.SUSPEND_EVENT_THREAD:
 850                 ThreadReference thread = eventThread();
 851                 if (thread == null) {
 852                     throw new InternalException("Inconsistent suspend policy");
 853                 }
 854                 thread.resume();
 855                 break;
 856             case EventRequest.SUSPEND_NONE:
 857                 // Do nothing
 858                 break;
 859             default:
 860                 throw new InternalException("Invalid suspend policy");
 861         }
 862     }
 863 
 864     public Iterator<Event> iterator() {
 865         return new Itr();
 866     }
 867 
 868     public EventIterator eventIterator() {
 869         return new Itr();
 870     }
 871 
 872     public class Itr implements EventIterator {
 873         /**
 874          * Index of element to be returned by subsequent call to next.
 875          */
 876         int cursor = 0;
 877 
 878         public boolean hasNext() {
 879             return cursor != size();
 880         }
 881 
 882         public Event next() {
 883             try {
 884                 Event nxt = get(cursor);
 885                 ++cursor;
 886                 return nxt;
 887             } catch(IndexOutOfBoundsException e) {
 888                 throw new NoSuchElementException();
 889             }
 890         }
 891 
 892         public Event nextEvent() {
 893             return next();
 894         }
 895 
 896         public void remove() {
 897             throw new UnsupportedOperationException();
 898         }
 899     }
 900 
 901     @Override
 902     public Spliterator<Event> spliterator() {
 903         return Spliterators.spliterator(this, Spliterator.DISTINCT);
 904     }
 905 
 906     /* below make this unmodifiable */
 907 
 908     public boolean add(Event o){
 909         throw new UnsupportedOperationException();
 910     }
 911     public boolean remove(Object o) {
 912         throw new UnsupportedOperationException();
 913     }
 914     public boolean addAll(Collection<? extends Event> coll) {
 915         throw new UnsupportedOperationException();
 916     }
 917     public boolean removeAll(Collection<?> coll) {
 918         throw new UnsupportedOperationException();
 919     }
 920     public boolean retainAll(Collection<?> coll) {
 921         throw new UnsupportedOperationException();
 922     }
 923     public void clear() {
 924         throw new UnsupportedOperationException();
 925     }
 926 }