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