1 /*
   2  * Copyright (c) 1998, 2017, 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             return classSignature.substring(1, classSignature.length()-1)
 429                 .replace('/', '.');
 430         }
 431 
 432         public String classSignature() {
 433             return classSignature;
 434         }
 435 
 436         String eventName() {
 437             return "ClassUnloadEvent";
 438         }
 439     }
 440 
 441     class ExceptionEventImpl extends LocatableEventImpl
 442                                              implements ExceptionEvent {
 443         private ObjectReference exception;
 444         private Location catchLocation;
 445 
 446         ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt) {
 447             super(evt, evt.requestID, evt.thread, evt.location);
 448             this.exception = evt.exception;
 449             this.catchLocation = evt.catchLocation;
 450         }
 451 
 452         public ObjectReference exception() {
 453             return exception;
 454         }
 455 
 456         public Location catchLocation() {
 457             return catchLocation;
 458         }
 459 
 460         String eventName() {
 461             return "ExceptionEvent";
 462         }
 463     }
 464 
 465     class ThreadDeathEventImpl extends ThreadedEventImpl
 466                                         implements ThreadDeathEvent {
 467         ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) {
 468             super(evt, evt.requestID, evt.thread);
 469         }
 470 
 471         String eventName() {
 472             return "ThreadDeathEvent";
 473         }
 474     }
 475 
 476     class ThreadStartEventImpl extends ThreadedEventImpl
 477                                         implements ThreadStartEvent {
 478         ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) {
 479             super(evt, evt.requestID, evt.thread);
 480         }
 481 
 482         String eventName() {
 483             return "ThreadStartEvent";
 484         }
 485     }
 486 
 487     class VMStartEventImpl extends ThreadedEventImpl
 488                                         implements VMStartEvent {
 489         VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) {
 490             super(evt, evt.requestID, evt.thread);
 491         }
 492 
 493         String eventName() {
 494             return "VMStartEvent";
 495         }
 496     }
 497 
 498     class VMDeathEventImpl extends EventImpl implements VMDeathEvent {
 499 
 500         VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) {
 501             super(evt, evt.requestID);
 502         }
 503 
 504         String eventName() {
 505             return "VMDeathEvent";
 506         }
 507     }
 508 
 509     class VMDisconnectEventImpl extends EventImpl
 510                                          implements VMDisconnectEvent {
 511 
 512         VMDisconnectEventImpl() {
 513             super((byte)JDWP.EventKind.VM_DISCONNECTED);
 514         }
 515 
 516         String eventName() {
 517             return "VMDisconnectEvent";
 518         }
 519     }
 520 
 521     abstract class WatchpointEventImpl extends LocatableEventImpl
 522                                             implements WatchpointEvent {
 523         private final ReferenceTypeImpl refType;
 524         private final long fieldID;
 525         private final ObjectReference object;
 526         private Field field = null;
 527 
 528         WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
 529                             int requestID,
 530                             ThreadReference thread, Location location,
 531                             byte refTypeTag, long typeID, long fieldID,
 532                             ObjectReference object) {
 533             super(evt, requestID, thread, location);
 534             this.refType = this.vm.referenceType(typeID, refTypeTag);
 535             this.fieldID = fieldID;
 536             this.object = object;
 537         }
 538 
 539         public Field field() {
 540             if (field == null) {
 541                 field = refType.getFieldMirror(fieldID);
 542             }
 543             return field;
 544         }
 545 
 546         public ObjectReference object() {
 547             return object;
 548         }
 549 
 550         public Value valueCurrent() {
 551             if (object == null) {
 552                 return refType.getValue(field());
 553             } else {
 554                 return object.getValue(field());
 555             }
 556         }
 557     }
 558 
 559     class AccessWatchpointEventImpl extends WatchpointEventImpl
 560                                             implements AccessWatchpointEvent {
 561 
 562         AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt) {
 563             super(evt, evt.requestID, evt.thread, evt.location,
 564                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
 565         }
 566 
 567         String eventName() {
 568             return "AccessWatchpoint";
 569         }
 570     }
 571 
 572     class ModificationWatchpointEventImpl extends WatchpointEventImpl
 573                            implements ModificationWatchpointEvent {
 574         Value newValue;
 575 
 576         ModificationWatchpointEventImpl(
 577                         JDWP.Event.Composite.Events.FieldModification evt) {
 578             super(evt, evt.requestID, evt.thread, evt.location,
 579                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
 580             this.newValue = evt.valueToBe;
 581         }
 582 
 583         public Value valueToBe() {
 584             return newValue;
 585         }
 586 
 587         String eventName() {
 588             return "ModificationWatchpoint";
 589         }
 590     }
 591 
 592     /**
 593      * Events are constructed on the thread which reads all data from the
 594      * transport. This means that the packet cannot be converted to real
 595      * JDI objects as that may involve further communications with the
 596      * back end which would deadlock.
 597      *
 598      * Hence the {@link #build()} method below called by EventQueue.
 599      */
 600     EventSetImpl(VirtualMachine aVm, Packet pkt) {
 601         super();
 602 
 603         // From "MirrorImpl":
 604         // Yes, its a bit of a hack. But by doing it this
 605         // way, this is the only place we have to change
 606         // typing to substitute a new impl.
 607         vm = (VirtualMachineImpl)aVm;
 608 
 609         this.pkt = pkt;
 610     }
 611 
 612     /**
 613      * Constructor for special events like VM disconnected
 614      */
 615     EventSetImpl(VirtualMachine aVm, byte eventCmd) {
 616         this(aVm, null);
 617         suspendPolicy = JDWP.SuspendPolicy.NONE;
 618         switch (eventCmd) {
 619             case JDWP.EventKind.VM_DISCONNECTED:
 620                 addEvent(new VMDisconnectEventImpl());
 621                 break;
 622 
 623             default:
 624                 throw new InternalException("Bad singleton event code");
 625         }
 626     }
 627 
 628     private void addEvent(EventImpl evt) {
 629         // Note that this class has a public add method that throws
 630         // an exception so that clients can't modify the EventSet
 631         super.add(evt);
 632     }
 633 
 634     /*
 635      * Complete the construction of an EventSet.  This is called from
 636      * an event handler thread.  It upacks the JDWP events inside
 637      * the packet and creates EventImpls for them.  The EventSet is already
 638      * on EventQueues when this is called, so it has to be synch.
 639      */
 640     synchronized void build() {
 641         if (pkt == null) {
 642             return;
 643         }
 644         PacketStream ps = new PacketStream(vm, pkt);
 645         JDWP.Event.Composite compEvt = new JDWP.Event.Composite(vm, ps);
 646         suspendPolicy = compEvt.suspendPolicy;
 647         if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
 648             switch(suspendPolicy) {
 649                 case JDWP.SuspendPolicy.ALL:
 650                     vm.printTrace("EventSet: SUSPEND_ALL");
 651                     break;
 652 
 653                 case JDWP.SuspendPolicy.EVENT_THREAD:
 654                     vm.printTrace("EventSet: SUSPEND_EVENT_THREAD");
 655                     break;
 656 
 657                 case JDWP.SuspendPolicy.NONE:
 658                     vm.printTrace("EventSet: SUSPEND_NONE");
 659                     break;
 660             }
 661         }
 662 
 663         ThreadReference fix6485605 = null;
 664         for (int i = 0; i < compEvt.events.length; i++) {
 665             EventImpl evt = createEvent(compEvt.events[i]);
 666             if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
 667                 try {
 668                     vm.printTrace("Event: " + evt);
 669                 } catch (VMDisconnectedException ee) {
 670                     // ignore - see bug 6502716
 671                 }
 672             }
 673 
 674             switch (evt.destination()) {
 675                 case UNKNOWN_EVENT:
 676                     // Ignore disabled, deleted, unknown events, but
 677                     // save the thread if there is one since we might
 678                     // have to resume it.  Note that events for different
 679                     // threads can't be in the same event set.
 680                     if (evt instanceof ThreadedEventImpl &&
 681                         suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
 682                         fix6485605 = ((ThreadedEventImpl)evt).thread();
 683                     }
 684                     continue;
 685                 case CLIENT_EVENT:
 686                     addEvent(evt);
 687                     break;
 688                 case INTERNAL_EVENT:
 689                     if (internalEventSet == null) {
 690                         internalEventSet = new EventSetImpl(this.vm, null);
 691                     }
 692                     internalEventSet.addEvent(evt);
 693                     break;
 694                 default:
 695                     throw new InternalException("Invalid event destination");
 696             }
 697         }
 698         pkt = null; // No longer needed - free it up
 699 
 700         // Avoid hangs described in 6296125, 6293795
 701         if (super.size() == 0) {
 702             // This set has no client events.  If we don't do
 703             // needed resumes, no one else is going to.
 704             if (suspendPolicy == JDWP.SuspendPolicy.ALL) {
 705                 vm.resume();
 706             } else if (suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
 707                 // See bug 6485605.
 708                 if (fix6485605 != null) {
 709                     fix6485605.resume();
 710                 } else {
 711                     // apparently, there is nothing to resume.
 712                 }
 713             }
 714             suspendPolicy = JDWP.SuspendPolicy.NONE;
 715 
 716         }
 717 
 718     }
 719 
 720     /**
 721      * Filter out internal events
 722      */
 723     EventSet userFilter() {
 724         return this;
 725     }
 726 
 727     /**
 728      * Filter out user events.
 729      */
 730     EventSet internalFilter() {
 731         return this.internalEventSet;
 732     }
 733 
 734     EventImpl createEvent(JDWP.Event.Composite.Events evt) {
 735         JDWP.Event.Composite.Events.EventsCommon comm = evt.aEventsCommon;
 736         switch (evt.eventKind) {
 737             case JDWP.EventKind.THREAD_START:
 738                 return new ThreadStartEventImpl(
 739                       (JDWP.Event.Composite.Events.ThreadStart)comm);
 740 
 741             case JDWP.EventKind.THREAD_END:
 742                 return new ThreadDeathEventImpl(
 743                       (JDWP.Event.Composite.Events.ThreadDeath)comm);
 744 
 745             case JDWP.EventKind.EXCEPTION:
 746                 return new ExceptionEventImpl(
 747                       (JDWP.Event.Composite.Events.Exception)comm);
 748 
 749             case JDWP.EventKind.BREAKPOINT:
 750                 return new BreakpointEventImpl(
 751                       (JDWP.Event.Composite.Events.Breakpoint)comm);
 752 
 753             case JDWP.EventKind.METHOD_ENTRY:
 754                 return new MethodEntryEventImpl(
 755                       (JDWP.Event.Composite.Events.MethodEntry)comm);
 756 
 757             case JDWP.EventKind.METHOD_EXIT:
 758                 return new MethodExitEventImpl(
 759                       (JDWP.Event.Composite.Events.MethodExit)comm);
 760 
 761             case JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
 762                 return new MethodExitEventImpl(
 763                       (JDWP.Event.Composite.Events.MethodExitWithReturnValue)comm);
 764 
 765             case JDWP.EventKind.FIELD_ACCESS:
 766                 return new AccessWatchpointEventImpl(
 767                       (JDWP.Event.Composite.Events.FieldAccess)comm);
 768 
 769             case JDWP.EventKind.FIELD_MODIFICATION:
 770                 return new ModificationWatchpointEventImpl(
 771                       (JDWP.Event.Composite.Events.FieldModification)comm);
 772 
 773             case JDWP.EventKind.SINGLE_STEP:
 774                 return new StepEventImpl(
 775                       (JDWP.Event.Composite.Events.SingleStep)comm);
 776 
 777             case JDWP.EventKind.CLASS_PREPARE:
 778                 return new ClassPrepareEventImpl(
 779                       (JDWP.Event.Composite.Events.ClassPrepare)comm);
 780 
 781             case JDWP.EventKind.CLASS_UNLOAD:
 782                 return new ClassUnloadEventImpl(
 783                       (JDWP.Event.Composite.Events.ClassUnload)comm);
 784 
 785             case JDWP.EventKind.MONITOR_CONTENDED_ENTER:
 786                 return new MonitorContendedEnterEventImpl(
 787                       (JDWP.Event.Composite.Events.MonitorContendedEnter)comm);
 788 
 789             case JDWP.EventKind.MONITOR_CONTENDED_ENTERED:
 790                 return new MonitorContendedEnteredEventImpl(
 791                       (JDWP.Event.Composite.Events.MonitorContendedEntered)comm);
 792 
 793             case JDWP.EventKind.MONITOR_WAIT:
 794                 return new MonitorWaitEventImpl(
 795                       (JDWP.Event.Composite.Events.MonitorWait)comm);
 796 
 797             case JDWP.EventKind.MONITOR_WAITED:
 798                 return new MonitorWaitedEventImpl(
 799                       (JDWP.Event.Composite.Events.MonitorWaited)comm);
 800 
 801             case JDWP.EventKind.VM_START:
 802                 return new VMStartEventImpl(
 803                       (JDWP.Event.Composite.Events.VMStart)comm);
 804 
 805             case JDWP.EventKind.VM_DEATH:
 806                 return new VMDeathEventImpl(
 807                       (JDWP.Event.Composite.Events.VMDeath)comm);
 808 
 809             default:
 810                 // Ignore unknown event types
 811                 System.err.println("Ignoring event cmd " +
 812                                    evt.eventKind + " from the VM");
 813                 return null;
 814         }
 815     }
 816 
 817     public VirtualMachine virtualMachine() {
 818         return vm;
 819     }
 820 
 821     public int suspendPolicy() {
 822         return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy);
 823     }
 824 
 825     private ThreadReference eventThread() {
 826         for (Event event : this) {
 827             if (event instanceof ThreadedEventImpl) {
 828                 return ((ThreadedEventImpl)event).thread();
 829             }
 830         }
 831         return null;
 832     }
 833 
 834     public void resume() {
 835         switch (suspendPolicy()) {
 836             case EventRequest.SUSPEND_ALL:
 837                 vm.resume();
 838                 break;
 839             case EventRequest.SUSPEND_EVENT_THREAD:
 840                 ThreadReference thread = eventThread();
 841                 if (thread == null) {
 842                     throw new InternalException("Inconsistent suspend policy");
 843                 }
 844                 thread.resume();
 845                 break;
 846             case EventRequest.SUSPEND_NONE:
 847                 // Do nothing
 848                 break;
 849             default:
 850                 throw new InternalException("Invalid suspend policy");
 851         }
 852     }
 853 
 854     public Iterator<Event> iterator() {
 855         return new Itr();
 856     }
 857 
 858     public EventIterator eventIterator() {
 859         return new Itr();
 860     }
 861 
 862     public class Itr implements EventIterator {
 863         /**
 864          * Index of element to be returned by subsequent call to next.
 865          */
 866         int cursor = 0;
 867 
 868         public boolean hasNext() {
 869             return cursor != size();
 870         }
 871 
 872         public Event next() {
 873             try {
 874                 Event nxt = get(cursor);
 875                 ++cursor;
 876                 return nxt;
 877             } catch(IndexOutOfBoundsException e) {
 878                 throw new NoSuchElementException();
 879             }
 880         }
 881 
 882         public Event nextEvent() {
 883             return next();
 884         }
 885 
 886         public void remove() {
 887             throw new UnsupportedOperationException();
 888         }
 889     }
 890 
 891     @Override
 892     public Spliterator<Event> spliterator() {
 893         return Spliterators.spliterator(this, Spliterator.DISTINCT);
 894     }
 895 
 896     /* below make this unmodifiable */
 897 
 898     public boolean add(Event o){
 899         throw new UnsupportedOperationException();
 900     }
 901     public boolean remove(Object o) {
 902         throw new UnsupportedOperationException();
 903     }
 904     public boolean addAll(Collection<? extends Event> coll) {
 905         throw new UnsupportedOperationException();
 906     }
 907     public boolean removeAll(Collection<?> coll) {
 908         throw new UnsupportedOperationException();
 909     }
 910     public boolean retainAll(Collection<?> coll) {
 911         throw new UnsupportedOperationException();
 912     }
 913     public void clear() {
 914         throw new UnsupportedOperationException();
 915     }
 916 }