1 /*
  2  * Copyright (c) 1998, 2021, 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.Collections;
 30 import java.util.HashMap;
 31 import java.util.List;
 32 import java.util.Map;
 33 
 34 import com.sun.jdi.Field;
 35 import com.sun.jdi.Location;
 36 import com.sun.jdi.NativeMethodException;
 37 import com.sun.jdi.ObjectReference;
 38 import com.sun.jdi.ReferenceType;
 39 import com.sun.jdi.ThreadReference;
 40 import com.sun.jdi.VirtualMachine;
 41 import com.sun.jdi.request.AccessWatchpointRequest;
 42 import com.sun.jdi.request.BreakpointRequest;
 43 import com.sun.jdi.request.ClassPrepareRequest;
 44 import com.sun.jdi.request.ClassUnloadRequest;
 45 import com.sun.jdi.request.DuplicateRequestException;
 46 import com.sun.jdi.request.EventRequest;
 47 import com.sun.jdi.request.EventRequestManager;
 48 import com.sun.jdi.request.ExceptionRequest;
 49 import com.sun.jdi.request.InvalidRequestStateException;
 50 import com.sun.jdi.request.MethodEntryRequest;
 51 import com.sun.jdi.request.MethodExitRequest;
 52 import com.sun.jdi.request.ModificationWatchpointRequest;
 53 import com.sun.jdi.request.MonitorContendedEnterRequest;
 54 import com.sun.jdi.request.MonitorContendedEnteredRequest;
 55 import com.sun.jdi.request.MonitorWaitRequest;
 56 import com.sun.jdi.request.MonitorWaitedRequest;
 57 import com.sun.jdi.request.StepRequest;
 58 import com.sun.jdi.request.ThreadDeathRequest;
 59 import com.sun.jdi.request.ThreadStartRequest;
 60 import com.sun.jdi.request.VMDeathRequest;
 61 import com.sun.jdi.request.WatchpointRequest;
 62 
 63 /**
 64  * This interface is used to create and remove Breakpoints, Watchpoints,
 65  * etc.
 66  * It include implementations of all the request interfaces..
 67  */
 68 // Warnings from List filters and List[] requestLists is  hard to fix.
 69 // Remove SuppressWarning when we fix the warnings from List filters
 70 // and List[] requestLists. The generic array is not supported.
 71 @SuppressWarnings({"unchecked", "rawtypes"})
 72 class EventRequestManagerImpl extends MirrorImpl
 73                               implements EventRequestManager
 74 {
 75     private final List<? extends EventRequest>[] requestLists;
 76     private static int methodExitEventCmd = 0;
 77 
 78     static int JDWPtoJDISuspendPolicy(byte jdwpPolicy) {
 79         switch(jdwpPolicy) {
 80             case JDWP.SuspendPolicy.ALL:
 81                 return EventRequest.SUSPEND_ALL;
 82             case JDWP.SuspendPolicy.EVENT_THREAD:
 83                 return EventRequest.SUSPEND_EVENT_THREAD;
 84         case JDWP.SuspendPolicy.NONE:
 85                 return EventRequest.SUSPEND_NONE;
 86             default:
 87                 throw new IllegalArgumentException("Illegal policy constant: " + jdwpPolicy);
 88         }
 89     }
 90 
 91     static byte JDItoJDWPSuspendPolicy(int jdiPolicy) {
 92         switch(jdiPolicy) {
 93             case EventRequest.SUSPEND_ALL:
 94                 return JDWP.SuspendPolicy.ALL;
 95             case EventRequest.SUSPEND_EVENT_THREAD:
 96                 return JDWP.SuspendPolicy.EVENT_THREAD;
 97             case EventRequest.SUSPEND_NONE:
 98                 return JDWP.SuspendPolicy.NONE;
 99             default:
100                 throw new IllegalArgumentException("Illegal policy constant: " + jdiPolicy);
101         }
102     }
103 
104     /*
105      * Override superclass back to default equality
106      */
107     public boolean equals(Object obj) {
108         return this == obj;
109     }
110 
111     public int hashCode() {
112         return System.identityHashCode(this);
113     }
114 
115     private abstract class EventRequestImpl extends MirrorImpl implements EventRequest {
116         int id;
117 
118         /*
119          * This list is not protected by a synchronized wrapper. All
120          * access/modification should be protected by synchronizing on
121          * the enclosing instance of EventRequestImpl.
122          */
123         List<Object> filters = new ArrayList<>();
124 
125         boolean isEnabled = false;
126         boolean deleted = false;
127         byte suspendPolicy = JDWP.SuspendPolicy.ALL;
128         private Map<Object, Object> clientProperties = null;
129 
130         EventRequestImpl() {
131             super(EventRequestManagerImpl.this.vm);
132         }
133 
134         /*
135          * Override superclass back to default equality
136          */
137         public boolean equals(Object obj) {
138             return this == obj;
139         }
140 
141         public int hashCode() {
142             return System.identityHashCode(this);
143         }
144 
145         abstract int eventCmd();
146 
147         InvalidRequestStateException invalidState() {
148             return new InvalidRequestStateException(toString());
149         }
150 
151         String state() {
152             return deleted? " (deleted)" :
153                 (isEnabled()? " (enabled)" : " (disabled)");
154         }
155 
156         /**
157          * @return all the event request of this kind
158          */
159         List requestList() {
160             return EventRequestManagerImpl.this.requestList(eventCmd());
161         }
162 
163         /**
164          * delete the event request
165          */
166         void delete() {
167             if (!deleted) {
168                 requestList().remove(this);
169                 disable(); /* must do BEFORE delete */
170                 deleted = true;
171             }
172         }
173 
174         public boolean isEnabled() {
175             return isEnabled;
176         }
177 
178         public void enable() {
179             setEnabled(true);
180         }
181 
182         public void disable() {
183             setEnabled(false);
184         }
185 
186         public synchronized void setEnabled(boolean val) {
187             if (deleted) {
188                 throw invalidState();
189             } else {
190                 if (val != isEnabled) {
191                     if (isEnabled) {
192                         clear();
193                     } else {
194                         set();
195                     }
196                 }
197             }
198         }
199 
200         public synchronized void addCountFilter(int count) {
201             if (isEnabled() || deleted) {
202                 throw invalidState();
203             }
204             if (count < 1) {
205                 throw new IllegalArgumentException("count is less than one");
206             }
207             filters.add(JDWP.EventRequest.Set.Modifier.Count.create(count));
208         }
209 
210         public void setSuspendPolicy(int policy) {
211             if (isEnabled() || deleted) {
212                 throw invalidState();
213             }
214             suspendPolicy = JDItoJDWPSuspendPolicy(policy);
215         }
216 
217         public int suspendPolicy() {
218             return JDWPtoJDISuspendPolicy(suspendPolicy);
219         }
220 
221         /**
222          * set (enable) the event request
223          */
224         synchronized void set() {
225             JDWP.EventRequest.Set.Modifier[] mods =
226                 filters.toArray(
227                     new JDWP.EventRequest.Set.Modifier[filters.size()]);
228             try {
229                 id = JDWP.EventRequest.Set.process(vm, (byte)eventCmd(),
230                                                    suspendPolicy, mods).requestID;
231             } catch (JDWPException exc) {
232                 throw exc.toJDIException();
233             }
234             isEnabled = true;
235         }
236 
237         synchronized void clear() {
238             try {
239                 JDWP.EventRequest.Clear.process(vm, (byte)eventCmd(), id);
240             } catch (JDWPException exc) {
241                 throw exc.toJDIException();
242             }
243             isEnabled = false;
244         }
245 
246         /**
247          * @return a small Map
248          * @see #putProperty
249          * @see #getProperty
250          */
251         private Map<Object, Object> getProperties() {
252             if (clientProperties == null) {
253                 clientProperties = new HashMap<>(2);
254             }
255             return clientProperties;
256         }
257 
258         /**
259          * Returns the value of the property with the specified key.  Only
260          * properties added with <code>putProperty</code> will return
261          * a non-null value.
262          *
263          * @return the value of this property or null
264          * @see #putProperty
265          */
266         public final Object getProperty(Object key) {
267             if (clientProperties == null) {
268                 return null;
269             } else {
270                 return getProperties().get(key);
271             }
272         }
273 
274         /**
275          * Add an arbitrary key/value "property" to this component.
276          *
277          * @see #getProperty
278          */
279         public final void putProperty(Object key, Object value) {
280             if (value != null) {
281                 getProperties().put(key, value);
282             } else {
283                 getProperties().remove(key);
284             }
285         }
286     }
287 
288     abstract class ThreadVisibleEventRequestImpl extends EventRequestImpl {
289         public synchronized void addThreadFilter(ThreadReference thread) {
290             validateMirror(thread);
291             if (isEnabled() || deleted) {
292                 throw invalidState();
293             }
294             filters.add(JDWP.EventRequest.Set.Modifier.ThreadOnly
295                                       .create((ThreadReferenceImpl)thread));
296         }
297     }
298 
299     abstract class ClassVisibleEventRequestImpl
300                                   extends ThreadVisibleEventRequestImpl {
301         public synchronized void addClassFilter(ReferenceType clazz) {
302             validateMirror(clazz);
303             if (isEnabled() || deleted) {
304                 throw invalidState();
305             }
306             filters.add(JDWP.EventRequest.Set.Modifier.ClassOnly
307                                       .create((ReferenceTypeImpl)clazz));
308         }
309 
310         public synchronized void addClassFilter(String classPattern) {
311             if (isEnabled() || deleted) {
312                 throw invalidState();
313             }
314             if (classPattern == null) {
315                 throw new NullPointerException();
316             }
317             filters.add(JDWP.EventRequest.Set.Modifier.ClassMatch
318                                       .create(classPattern));
319         }
320 
321         public synchronized void addClassExclusionFilter(String classPattern) {
322             if (isEnabled() || deleted) {
323                 throw invalidState();
324             }
325             if (classPattern == null) {
326                 throw new NullPointerException();
327             }
328             filters.add(JDWP.EventRequest.Set.Modifier.ClassExclude
329                                       .create(classPattern));
330         }
331 
332         public synchronized void addInstanceFilter(ObjectReference instance) {
333             validateMirror(instance);
334             if (isEnabled() || deleted) {
335                 throw invalidState();
336             }
337             if (!vm.canUseInstanceFilters()) {
338                 throw new UnsupportedOperationException(
339                      "target does not support instance filters");
340             }
341             filters.add(JDWP.EventRequest.Set.Modifier.InstanceOnly
342                                       .create((ObjectReferenceImpl)instance));
343         }
344     }
345 
346     class BreakpointRequestImpl extends ClassVisibleEventRequestImpl
347                                      implements BreakpointRequest {
348         private final Location location;
349 
350         BreakpointRequestImpl(Location location) {
351             this.location = location;
352             filters.add(0,JDWP.EventRequest.Set.Modifier.LocationOnly
353                                                  .create(location));
354             requestList().add(this);
355         }
356 
357         public Location location() {
358             return location;
359         }
360 
361         int eventCmd() {
362             return JDWP.EventKind.BREAKPOINT;
363         }
364 
365         public String toString() {
366             return "breakpoint request " + location() + state();
367         }
368     }
369 
370     class ClassPrepareRequestImpl extends ClassVisibleEventRequestImpl
371                                   implements ClassPrepareRequest {
372         ClassPrepareRequestImpl() {
373             requestList().add(this);
374         }
375 
376         int eventCmd() {
377             return JDWP.EventKind.CLASS_PREPARE;
378         }
379 
380         public synchronized void addSourceNameFilter(String sourceNamePattern) {
381             if (isEnabled() || deleted) {
382                 throw invalidState();
383             }
384             if (!vm.canUseSourceNameFilters()) {
385                 throw new UnsupportedOperationException(
386                      "target does not support source name filters");
387             }
388             if (sourceNamePattern == null) {
389                 throw new NullPointerException();
390             }
391 
392             filters.add(JDWP.EventRequest.Set.Modifier.SourceNameMatch
393                                       .create(sourceNamePattern));
394         }
395 
396         public String toString() {
397             return "class prepare request " + state();
398         }
399     }
400 
401     class ClassUnloadRequestImpl extends ClassVisibleEventRequestImpl
402                                  implements ClassUnloadRequest {
403         ClassUnloadRequestImpl() {
404             requestList().add(this);
405         }
406 
407         int eventCmd() {
408             return JDWP.EventKind.CLASS_UNLOAD;
409         }
410 
411         public String toString() {
412             return "class unload request " + state();
413         }
414     }
415 
416     class ExceptionRequestImpl extends ClassVisibleEventRequestImpl
417                                implements ExceptionRequest {
418         ReferenceType exception = null;
419         boolean caught = true;
420         boolean uncaught = true;
421 
422         ExceptionRequestImpl(ReferenceType refType,
423                           boolean notifyCaught, boolean notifyUncaught) {
424             exception = refType;
425             caught = notifyCaught;
426             uncaught = notifyUncaught;
427             {
428                 ReferenceTypeImpl exc;
429                 if (exception == null) {
430                     exc = new ClassTypeImpl(vm, 0);
431                 } else {
432                     exc = (ReferenceTypeImpl)exception;
433                 }
434                 filters.add(JDWP.EventRequest.Set.Modifier.ExceptionOnly.
435                             create(exc, caught, uncaught));
436             }
437             requestList().add(this);
438         }
439 
440         public ReferenceType exception() {
441             return exception;
442         }
443 
444         public boolean notifyCaught() {
445             return caught;
446         }
447 
448         public boolean notifyUncaught() {
449             return uncaught;
450         }
451 
452         int eventCmd() {
453             return JDWP.EventKind.EXCEPTION;
454         }
455 
456         public String toString() {
457             return "exception request " + exception() + state();
458         }
459     }
460 
461     class MethodEntryRequestImpl extends ClassVisibleEventRequestImpl
462                                  implements MethodEntryRequest {
463         MethodEntryRequestImpl() {
464             requestList().add(this);
465         }
466 
467         int eventCmd() {
468             return JDWP.EventKind.METHOD_ENTRY;
469         }
470 
471         public String toString() {
472             return "method entry request " + state();
473         }
474     }
475 
476     class MethodExitRequestImpl extends ClassVisibleEventRequestImpl
477                                 implements MethodExitRequest {
478         MethodExitRequestImpl() {
479             if (methodExitEventCmd == 0) {
480                 /*
481                  * If we can get return values, then we always get them.
482                  * Thus, for JDI MethodExitRequests, we always use the
483                  * same JDWP EventKind.  Here we decide which to use and
484                  * save it so that it will be used for all future
485                  * MethodExitRequests.
486                  *
487                  * This call to canGetMethodReturnValues can't
488                  * be done in the EventRequestManager ctor because that is too early.
489                  */
490                 if (vm.canGetMethodReturnValues()) {
491                     methodExitEventCmd = JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE;
492                 } else {
493                     methodExitEventCmd = JDWP.EventKind.METHOD_EXIT;
494                 }
495             }
496             requestList().add(this);
497         }
498 
499         int eventCmd() {
500             return EventRequestManagerImpl.methodExitEventCmd;
501         }
502 
503         public String toString() {
504             return "method exit request " + state();
505         }
506     }
507 
508     class MonitorContendedEnterRequestImpl extends ClassVisibleEventRequestImpl
509                                            implements MonitorContendedEnterRequest {
510         MonitorContendedEnterRequestImpl() {
511             requestList().add(this);
512         }
513 
514         int eventCmd() {
515             return JDWP.EventKind.MONITOR_CONTENDED_ENTER;
516         }
517 
518         public String toString() {
519             return "monitor contended enter request " + state();
520         }
521     }
522 
523     class MonitorContendedEnteredRequestImpl extends ClassVisibleEventRequestImpl
524                                              implements MonitorContendedEnteredRequest {
525         MonitorContendedEnteredRequestImpl() {
526             requestList().add(this);
527         }
528 
529         int eventCmd() {
530             return JDWP.EventKind.MONITOR_CONTENDED_ENTERED;
531         }
532 
533         public String toString() {
534             return "monitor contended entered request " + state();
535         }
536     }
537 
538     class MonitorWaitRequestImpl extends ClassVisibleEventRequestImpl
539                                  implements MonitorWaitRequest {
540         MonitorWaitRequestImpl() {
541             requestList().add(this);
542         }
543 
544         int eventCmd() {
545             return JDWP.EventKind.MONITOR_WAIT;
546         }
547 
548         public String toString() {
549             return "monitor wait request " + state();
550         }
551     }
552 
553     class MonitorWaitedRequestImpl extends ClassVisibleEventRequestImpl
554                                    implements MonitorWaitedRequest {
555         MonitorWaitedRequestImpl() {
556             requestList().add(this);
557         }
558 
559         int eventCmd() {
560             return JDWP.EventKind.MONITOR_WAITED;
561         }
562 
563         public String toString() {
564             return "monitor waited request " + state();
565         }
566     }
567 
568     class StepRequestImpl extends ClassVisibleEventRequestImpl
569                           implements StepRequest {
570         ThreadReferenceImpl thread;
571         int size;
572         int depth;
573 
574         StepRequestImpl(ThreadReference thread, int size, int depth) {
575             this.thread = (ThreadReferenceImpl)thread;
576             this.size = size;
577             this.depth = depth;
578 
579             /*
580              * Translate size and depth to corresponding JDWP values.
581              */
582             int jdwpSize;
583             switch (size) {
584                 case STEP_MIN:
585                     jdwpSize = JDWP.StepSize.MIN;
586                     break;
587                 case STEP_LINE:
588                     jdwpSize = JDWP.StepSize.LINE;
589                     break;
590                 default:
591                     throw new IllegalArgumentException("Invalid step size");
592             }
593 
594             int jdwpDepth;
595             switch (depth) {
596                 case STEP_INTO:
597                     jdwpDepth = JDWP.StepDepth.INTO;
598                     break;
599                 case STEP_OVER:
600                     jdwpDepth = JDWP.StepDepth.OVER;
601                     break;
602                 case STEP_OUT:
603                     jdwpDepth = JDWP.StepDepth.OUT;
604                     break;
605                 default:
606                     throw new IllegalArgumentException("Invalid step depth");
607             }
608 
609             /*
610              * Make sure this isn't a duplicate
611              */
612             List<StepRequest> requests = stepRequests();
613             for (StepRequest request : requests) {
614                 if ((request != this) &&
615                         request.isEnabled() &&
616                         request.thread().equals(thread)) {
617                     throw new DuplicateRequestException(
618                         "Only one step request allowed per thread");
619                 }
620             }
621 
622             filters.add(JDWP.EventRequest.Set.Modifier.Step.
623                         create(this.thread, jdwpSize, jdwpDepth));
624             requestList().add(this);
625 
626         }
627         public int depth() {
628             return depth;
629         }
630 
631         public int size() {
632             return size;
633         }
634 
635         public ThreadReference thread() {
636             return thread;
637         }
638 
639         int eventCmd() {
640             return JDWP.EventKind.SINGLE_STEP;
641         }
642 
643         public String toString() {
644             return "step request " + thread() + state();
645         }
646     }
647 
648     class ThreadDeathRequestImpl extends ThreadVisibleEventRequestImpl
649                                  implements ThreadDeathRequest {
650         ThreadDeathRequestImpl() {
651             requestList().add(this);
652         }
653 
654         int eventCmd() {
655             return JDWP.EventKind.THREAD_DEATH;
656         }
657 
658         public String toString() {
659             return "thread death request " + state();
660         }
661     }
662 
663     class ThreadStartRequestImpl extends ThreadVisibleEventRequestImpl
664                                  implements ThreadStartRequest {
665         ThreadStartRequestImpl() {
666             requestList().add(this);
667         }
668 
669         int eventCmd() {
670             return JDWP.EventKind.THREAD_START;
671         }
672 
673         public String toString() {
674             return "thread start request " + state();
675         }
676     }
677 
678     abstract class WatchpointRequestImpl extends ClassVisibleEventRequestImpl
679                                          implements WatchpointRequest {
680         final Field field;
681 
682         WatchpointRequestImpl(Field field) {
683             this.field = field;
684             filters.add(0,
685                    JDWP.EventRequest.Set.Modifier.FieldOnly.create(
686                     (ReferenceTypeImpl)field.declaringType(),
687                     ((FieldImpl)field).ref()));
688         }
689 
690         public Field field() {
691             return field;
692         }
693     }
694 
695     class AccessWatchpointRequestImpl extends WatchpointRequestImpl
696                                       implements AccessWatchpointRequest {
697         AccessWatchpointRequestImpl(Field field) {
698             super(field);
699             requestList().add(this);
700         }
701 
702         int eventCmd() {
703             return JDWP.EventKind.FIELD_ACCESS;
704         }
705 
706         public String toString() {
707             return "access watchpoint request " + field + state();
708         }
709     }
710 
711     class ModificationWatchpointRequestImpl extends WatchpointRequestImpl
712                                             implements ModificationWatchpointRequest {
713         ModificationWatchpointRequestImpl(Field field) {
714             super(field);
715             requestList().add(this);
716         }
717 
718         int eventCmd() {
719             return JDWP.EventKind.FIELD_MODIFICATION;
720         }
721 
722         public String toString() {
723             return "modification watchpoint request " + field + state();
724         }
725     }
726 
727     class VMDeathRequestImpl extends EventRequestImpl
728                              implements VMDeathRequest {
729         VMDeathRequestImpl() {
730             requestList().add(this);
731         }
732 
733         int eventCmd() {
734             return JDWP.EventKind.VM_DEATH;
735         }
736 
737         public String toString() {
738             return "VM death request " + state();
739         }
740     }
741 
742     /**
743      * Constructor.
744      */
745     EventRequestManagerImpl(VirtualMachine vm) {
746         super(vm);
747         java.lang.reflect.Field[] ekinds =
748             JDWP.EventKind.class.getDeclaredFields();
749         int highest = 0;
750         for (int i = 0; i < ekinds.length; ++i) {
751             int val;
752             try {
753                 val = ekinds[i].getInt(null);
754             } catch (IllegalAccessException exc) {
755                 throw new RuntimeException("Got: " + exc);
756             }
757             if (val > highest) {
758                 highest = val;
759             }
760         }
761         requestLists = new List[highest+1];
762         for (int i=0; i <= highest; i++) {
763             requestLists[i] = Collections.synchronizedList(new ArrayList<>());
764         }
765     }
766 
767     public ClassPrepareRequest createClassPrepareRequest() {
768         return new ClassPrepareRequestImpl();
769     }
770 
771     public ClassUnloadRequest createClassUnloadRequest() {
772         return new ClassUnloadRequestImpl();
773     }
774 
775     public ExceptionRequest createExceptionRequest(ReferenceType refType,
776                                                    boolean notifyCaught,
777                                                    boolean notifyUncaught) {
778         validateMirrorOrNull(refType);
779         return new ExceptionRequestImpl(refType, notifyCaught, notifyUncaught);
780     }
781 
782     public StepRequest createStepRequest(ThreadReference thread,
783                                          int size, int depth) {
784         validateMirror(thread);
785         return new StepRequestImpl(thread, size, depth);
786     }
787 
788     public ThreadDeathRequest createThreadDeathRequest() {
789         return new ThreadDeathRequestImpl();
790     }
791 
792     public ThreadStartRequest createThreadStartRequest() {
793         return new ThreadStartRequestImpl();
794     }
795 
796     public MethodEntryRequest createMethodEntryRequest() {
797         return new MethodEntryRequestImpl();
798     }
799 
800     public MethodExitRequest createMethodExitRequest() {
801         return new MethodExitRequestImpl();
802     }
803 
804     public MonitorContendedEnterRequest createMonitorContendedEnterRequest() {
805         if (!vm.canRequestMonitorEvents()) {
806             throw new UnsupportedOperationException(
807           "target VM does not support requesting Monitor events");
808         }
809         return new MonitorContendedEnterRequestImpl();
810     }
811 
812     public MonitorContendedEnteredRequest createMonitorContendedEnteredRequest() {
813         if (!vm.canRequestMonitorEvents()) {
814             throw new UnsupportedOperationException(
815           "target VM does not support requesting Monitor events");
816         }
817         return new MonitorContendedEnteredRequestImpl();
818     }
819 
820     public MonitorWaitRequest createMonitorWaitRequest() {
821         if (!vm.canRequestMonitorEvents()) {
822             throw new UnsupportedOperationException(
823           "target VM does not support requesting Monitor events");
824         }
825         return new MonitorWaitRequestImpl();
826     }
827 
828     public MonitorWaitedRequest createMonitorWaitedRequest() {
829         if (!vm.canRequestMonitorEvents()) {
830             throw new UnsupportedOperationException(
831           "target VM does not support requesting Monitor events");
832         }
833         return new MonitorWaitedRequestImpl();
834     }
835 
836     public BreakpointRequest createBreakpointRequest(Location location) {
837         validateMirror(location);
838         if (location.codeIndex() == -1) {
839             throw new NativeMethodException("Cannot set breakpoints on native methods");
840         }
841         return new BreakpointRequestImpl(location);
842     }
843 
844     public AccessWatchpointRequest
845                               createAccessWatchpointRequest(Field field) {
846         validateMirror(field);
847         if (!vm.canWatchFieldAccess()) {
848             throw new UnsupportedOperationException(
849           "target VM does not support access watchpoints");
850         }
851         return new AccessWatchpointRequestImpl(field);
852     }
853 
854     public ModificationWatchpointRequest
855                         createModificationWatchpointRequest(Field field) {
856         validateMirror(field);
857         if (!vm.canWatchFieldModification()) {
858             throw new UnsupportedOperationException(
859           "target VM does not support modification watchpoints");
860         }
861         return new ModificationWatchpointRequestImpl(field);
862     }
863 
864     public VMDeathRequest createVMDeathRequest() {
865         if (!vm.canRequestVMDeathEvent()) {
866             throw new UnsupportedOperationException(
867           "target VM does not support requesting VM death events");
868         }
869         return new VMDeathRequestImpl();
870     }
871 
872     public void deleteEventRequest(EventRequest eventRequest) {
873         validateMirror(eventRequest);
874         ((EventRequestImpl)eventRequest).delete();
875     }
876 
877     public void deleteEventRequests(List<? extends EventRequest> eventRequests) {
878         validateMirrors(eventRequests);
879         // copy the eventRequests to avoid ConcurrentModificationException
880         for (EventRequest eventRequest : new ArrayList<>(eventRequests)) {
881             ((EventRequestImpl)eventRequest).delete();
882         }
883     }
884 
885     public void deleteAllBreakpoints() {
886         requestList(JDWP.EventKind.BREAKPOINT).clear();
887 
888         try {
889             JDWP.EventRequest.ClearAllBreakpoints.process(vm);
890         } catch (JDWPException exc) {
891             throw exc.toJDIException();
892         }
893     }
894 
895     public List<StepRequest> stepRequests() {
896         return (List<StepRequest>)unmodifiableRequestList(JDWP.EventKind.SINGLE_STEP);
897     }
898 
899     public List<ClassPrepareRequest> classPrepareRequests() {
900         return (List<ClassPrepareRequest>)unmodifiableRequestList(JDWP.EventKind.CLASS_PREPARE);
901     }
902 
903     public List<ClassUnloadRequest> classUnloadRequests() {
904         return (List<ClassUnloadRequest>)unmodifiableRequestList(JDWP.EventKind.CLASS_UNLOAD);
905     }
906 
907     public List<ThreadStartRequest> threadStartRequests() {
908         return (List<ThreadStartRequest>)unmodifiableRequestList(JDWP.EventKind.THREAD_START);
909     }
910 
911     public List<ThreadDeathRequest> threadDeathRequests() {
912         return (List<ThreadDeathRequest>)unmodifiableRequestList(JDWP.EventKind.THREAD_DEATH);
913     }
914 
915     public List<ExceptionRequest> exceptionRequests() {
916         return (List<ExceptionRequest>)unmodifiableRequestList(JDWP.EventKind.EXCEPTION);
917     }
918 
919     public List<BreakpointRequest> breakpointRequests() {
920         return (List<BreakpointRequest>)unmodifiableRequestList(JDWP.EventKind.BREAKPOINT);
921     }
922 
923     public List<AccessWatchpointRequest> accessWatchpointRequests() {
924         return (List<AccessWatchpointRequest>)unmodifiableRequestList(JDWP.EventKind.FIELD_ACCESS);
925     }
926 
927     public List<ModificationWatchpointRequest> modificationWatchpointRequests() {
928         return (List<ModificationWatchpointRequest>)unmodifiableRequestList(JDWP.EventKind.FIELD_MODIFICATION);
929     }
930 
931     public List<MethodEntryRequest> methodEntryRequests() {
932         return (List<MethodEntryRequest>)unmodifiableRequestList(JDWP.EventKind.METHOD_ENTRY);
933     }
934 
935     public List<MethodExitRequest> methodExitRequests() {
936         return (List<MethodExitRequest>)unmodifiableRequestList(EventRequestManagerImpl.methodExitEventCmd);
937     }
938 
939     public List<MonitorContendedEnterRequest> monitorContendedEnterRequests() {
940         return (List<MonitorContendedEnterRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTER);
941     }
942 
943     public List<MonitorContendedEnteredRequest> monitorContendedEnteredRequests() {
944         return (List<MonitorContendedEnteredRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTERED);
945     }
946 
947     public List<MonitorWaitRequest> monitorWaitRequests() {
948         return (List<MonitorWaitRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_WAIT);
949     }
950 
951     public List<MonitorWaitedRequest> monitorWaitedRequests() {
952         return (List<MonitorWaitedRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_WAITED);
953     }
954 
955     public List<VMDeathRequest> vmDeathRequests() {
956         return (List<VMDeathRequest>)unmodifiableRequestList(JDWP.EventKind.VM_DEATH);
957     }
958 
959     List<? extends EventRequest> unmodifiableRequestList(int eventCmd) {
960         // No need of explicit synchronization for requestList here.
961         // It is taken care internally by SynchronizedList class.
962         return Collections.unmodifiableList(new ArrayList<>(requestList(eventCmd)));
963     }
964 
965     EventRequest request(int eventCmd, int requestId) {
966         List<? extends EventRequest> rl = requestList(eventCmd);
967         synchronized(rl) {   // Refer Collections.synchronizedList javadoc.
968             for (EventRequest eventRequest : rl) {
969                 EventRequestImpl er = (EventRequestImpl)eventRequest;
970                 if (er.id == requestId)
971                     return er;
972             }
973         }
974         return null;
975     }
976 
977     private List<? extends EventRequest> requestList(int eventCmd) {
978         return requestLists[eventCmd];
979     }
980 }