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