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 
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 classSignature.substring(1, classSignature.length()-1)
429                 .replace('/', '.');
430         }
431 
classSignature()432         public String classSignature() {
433             return classSignature;
434         }
435 
eventName()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 
ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt)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 
exception()452         public ObjectReference exception() {
453             return exception;
454         }
455 
catchLocation()456         public Location catchLocation() {
457             return catchLocation;
458         }
459 
eventName()460         String eventName() {
461             return "ExceptionEvent";
462         }
463     }
464 
465     class ThreadDeathEventImpl extends ThreadedEventImpl
466                                         implements ThreadDeathEvent {
ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt)467         ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) {
468             super(evt, evt.requestID, evt.thread);
469         }
470 
eventName()471         String eventName() {
472             return "ThreadDeathEvent";
473         }
474     }
475 
476     class ThreadStartEventImpl extends ThreadedEventImpl
477                                         implements ThreadStartEvent {
ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt)478         ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) {
479             super(evt, evt.requestID, evt.thread);
480         }
481 
eventName()482         String eventName() {
483             return "ThreadStartEvent";
484         }
485     }
486 
487     class VMStartEventImpl extends ThreadedEventImpl
488                                         implements VMStartEvent {
VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt)489         VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) {
490             super(evt, evt.requestID, evt.thread);
491         }
492 
eventName()493         String eventName() {
494             return "VMStartEvent";
495         }
496     }
497 
498     class VMDeathEventImpl extends EventImpl implements VMDeathEvent {
499 
VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt)500         VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) {
501             super(evt, evt.requestID);
502         }
503 
eventName()504         String eventName() {
505             return "VMDeathEvent";
506         }
507     }
508 
509     class VMDisconnectEventImpl extends EventImpl
510                                          implements VMDisconnectEvent {
511 
VMDisconnectEventImpl()512         VMDisconnectEventImpl() {
513             super((byte)JDWP.EventKind.VM_DISCONNECTED);
514         }
515 
eventName()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 
WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, int requestID, ThreadReference thread, Location location, byte refTypeTag, long typeID, long fieldID, ObjectReference object)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 
field()539         public Field field() {
540             if (field == null) {
541                 field = refType.getFieldMirror(fieldID);
542             }
543             return field;
544         }
545 
object()546         public ObjectReference object() {
547             return object;
548         }
549 
valueCurrent()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 
AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt)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 
eventName()567         String eventName() {
568             return "AccessWatchpoint";
569         }
570     }
571 
572     class ModificationWatchpointEventImpl extends WatchpointEventImpl
573                            implements ModificationWatchpointEvent {
574         Value newValue;
575 
ModificationWatchpointEventImpl( JDWP.Event.Composite.Events.FieldModification evt)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 
valueToBe()583         public Value valueToBe() {
584             return newValue;
585         }
586 
eventName()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      */
EventSetImpl(VirtualMachine aVm, Packet pkt)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      */
EventSetImpl(VirtualMachine aVm, byte eventCmd)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 
addEvent(EventImpl evt)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      */
build()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      */
userFilter()723     EventSet userFilter() {
724         return this;
725     }
726 
727     /**
728      * Filter out user events.
729      */
internalFilter()730     EventSet internalFilter() {
731         return this.internalEventSet;
732     }
733 
createEvent(JDWP.Event.Composite.Events evt)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 
virtualMachine()817     public VirtualMachine virtualMachine() {
818         return vm;
819     }
820 
suspendPolicy()821     public int suspendPolicy() {
822         return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy);
823     }
824 
eventThread()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 
resume()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 
iterator()854     public Iterator<Event> iterator() {
855         return new Itr();
856     }
857 
eventIterator()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 
hasNext()868         public boolean hasNext() {
869             return cursor != size();
870         }
871 
next()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 
nextEvent()882         public Event nextEvent() {
883             return next();
884         }
885 
remove()886         public void remove() {
887             throw new UnsupportedOperationException();
888         }
889     }
890 
891     @Override
spliterator()892     public Spliterator<Event> spliterator() {
893         return Spliterators.spliterator(this, Spliterator.DISTINCT);
894     }
895 
896     /* below make this unmodifiable */
897 
add(Event o)898     public boolean add(Event o){
899         throw new UnsupportedOperationException();
900     }
remove(Object o)901     public boolean remove(Object o) {
902         throw new UnsupportedOperationException();
903     }
addAll(Collection<? extends Event> coll)904     public boolean addAll(Collection<? extends Event> coll) {
905         throw new UnsupportedOperationException();
906     }
removeAll(Collection<?> coll)907     public boolean removeAll(Collection<?> coll) {
908         throw new UnsupportedOperationException();
909     }
retainAll(Collection<?> coll)910     public boolean retainAll(Collection<?> coll) {
911         throw new UnsupportedOperationException();
912     }
clear()913     public void clear() {
914         throw new UnsupportedOperationException();
915     }
916 }
917