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 ThreadLifecycleEventRequestImpl extends ThreadVisibleEventRequestImpl {
300         public synchronized void addPlatformThreadsOnlyFilter() {
301             if (isEnabled() || deleted) {
302                 throw invalidState();
303             }
304             filters.add(JDWP.EventRequest.Set.Modifier.PlatformThreadsOnly.create());
305         }
306     }
307 
308     abstract class ClassVisibleEventRequestImpl
309                                   extends ThreadVisibleEventRequestImpl {
310         public synchronized void addClassFilter(ReferenceType clazz) {
311             validateMirror(clazz);
312             if (isEnabled() || deleted) {
313                 throw invalidState();
314             }
315             filters.add(JDWP.EventRequest.Set.Modifier.ClassOnly
316                                       .create((ReferenceTypeImpl)clazz));
317         }
318 
319         public synchronized void addClassFilter(String classPattern) {
320             if (isEnabled() || deleted) {
321                 throw invalidState();
322             }
323             if (classPattern == null) {
324                 throw new NullPointerException();
325             }
326             filters.add(JDWP.EventRequest.Set.Modifier.ClassMatch
327                                       .create(classPattern));
328         }
329 
330         public synchronized void addClassExclusionFilter(String classPattern) {
331             if (isEnabled() || deleted) {
332                 throw invalidState();
333             }
334             if (classPattern == null) {
335                 throw new NullPointerException();
336             }
337             filters.add(JDWP.EventRequest.Set.Modifier.ClassExclude
338                                       .create(classPattern));
339         }
340 
341         public synchronized void addInstanceFilter(ObjectReference instance) {
342             validateMirror(instance);
343             if (isEnabled() || deleted) {
344                 throw invalidState();
345             }
346             if (!vm.canUseInstanceFilters()) {
347                 throw new UnsupportedOperationException(
348                      "target does not support instance filters");
349             }
350             filters.add(JDWP.EventRequest.Set.Modifier.InstanceOnly
351                                       .create((ObjectReferenceImpl)instance));
352         }
353     }
354 
355     class BreakpointRequestImpl extends ClassVisibleEventRequestImpl
356                                      implements BreakpointRequest {
357         private final Location location;
358 
359         BreakpointRequestImpl(Location location) {
360             this.location = location;
361             filters.add(0,JDWP.EventRequest.Set.Modifier.LocationOnly
362                                                  .create(location));
363             requestList().add(this);
364         }
365 
366         public Location location() {
367             return location;
368         }
369 
370         int eventCmd() {
371             return JDWP.EventKind.BREAKPOINT;
372         }
373 
374         public String toString() {
375             return "breakpoint request " + location() + state();
376         }
377     }
378 
379     class ClassPrepareRequestImpl extends ClassVisibleEventRequestImpl
380                                   implements ClassPrepareRequest {
381         ClassPrepareRequestImpl() {
382             requestList().add(this);
383         }
384 
385         int eventCmd() {
386             return JDWP.EventKind.CLASS_PREPARE;
387         }
388 
389         public synchronized void addSourceNameFilter(String sourceNamePattern) {
390             if (isEnabled() || deleted) {
391                 throw invalidState();
392             }
393             if (!vm.canUseSourceNameFilters()) {
394                 throw new UnsupportedOperationException(
395                      "target does not support source name filters");
396             }
397             if (sourceNamePattern == null) {
398                 throw new NullPointerException();
399             }
400 
401             filters.add(JDWP.EventRequest.Set.Modifier.SourceNameMatch
402                                       .create(sourceNamePattern));
403         }
404 
405         public String toString() {
406             return "class prepare request " + state();
407         }
408     }
409 
410     class ClassUnloadRequestImpl extends ClassVisibleEventRequestImpl
411                                  implements ClassUnloadRequest {
412         ClassUnloadRequestImpl() {
413             requestList().add(this);
414         }
415 
416         int eventCmd() {
417             return JDWP.EventKind.CLASS_UNLOAD;
418         }
419 
420         public String toString() {
421             return "class unload request " + state();
422         }
423     }
424 
425     class ExceptionRequestImpl extends ClassVisibleEventRequestImpl
426                                implements ExceptionRequest {
427         ReferenceType exception = null;
428         boolean caught = true;
429         boolean uncaught = true;
430 
431         ExceptionRequestImpl(ReferenceType refType,
432                           boolean notifyCaught, boolean notifyUncaught) {
433             exception = refType;
434             caught = notifyCaught;
435             uncaught = notifyUncaught;
436             {
437                 ReferenceTypeImpl exc;
438                 if (exception == null) {
439                     exc = new ClassTypeImpl(vm, 0);
440                 } else {
441                     exc = (ReferenceTypeImpl)exception;
442                 }
443                 filters.add(JDWP.EventRequest.Set.Modifier.ExceptionOnly.
444                             create(exc, caught, uncaught));
445             }
446             requestList().add(this);
447         }
448 
449         public ReferenceType exception() {
450             return exception;
451         }
452 
453         public boolean notifyCaught() {
454             return caught;
455         }
456 
457         public boolean notifyUncaught() {
458             return uncaught;
459         }
460 
461         int eventCmd() {
462             return JDWP.EventKind.EXCEPTION;
463         }
464 
465         public String toString() {
466             return "exception request " + exception() + state();
467         }
468     }
469 
470     class MethodEntryRequestImpl extends ClassVisibleEventRequestImpl
471                                  implements MethodEntryRequest {
472         MethodEntryRequestImpl() {
473             requestList().add(this);
474         }
475 
476         int eventCmd() {
477             return JDWP.EventKind.METHOD_ENTRY;
478         }
479 
480         public String toString() {
481             return "method entry request " + state();
482         }
483     }
484 
485     class MethodExitRequestImpl extends ClassVisibleEventRequestImpl
486                                 implements MethodExitRequest {
487         MethodExitRequestImpl() {
488             if (methodExitEventCmd == 0) {
489                 /*
490                  * If we can get return values, then we always get them.
491                  * Thus, for JDI MethodExitRequests, we always use the
492                  * same JDWP EventKind.  Here we decide which to use and
493                  * save it so that it will be used for all future
494                  * MethodExitRequests.
495                  *
496                  * This call to canGetMethodReturnValues can't
497                  * be done in the EventRequestManager ctor because that is too early.
498                  */
499                 if (vm.canGetMethodReturnValues()) {
500                     methodExitEventCmd = JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE;
501                 } else {
502                     methodExitEventCmd = JDWP.EventKind.METHOD_EXIT;
503                 }
504             }
505             requestList().add(this);
506         }
507 
508         int eventCmd() {
509             return EventRequestManagerImpl.methodExitEventCmd;
510         }
511 
512         public String toString() {
513             return "method exit request " + state();
514         }
515     }
516 
517     class MonitorContendedEnterRequestImpl extends ClassVisibleEventRequestImpl
518                                            implements MonitorContendedEnterRequest {
519         MonitorContendedEnterRequestImpl() {
520             requestList().add(this);
521         }
522 
523         int eventCmd() {
524             return JDWP.EventKind.MONITOR_CONTENDED_ENTER;
525         }
526 
527         public String toString() {
528             return "monitor contended enter request " + state();
529         }
530     }
531 
532     class MonitorContendedEnteredRequestImpl extends ClassVisibleEventRequestImpl
533                                              implements MonitorContendedEnteredRequest {
534         MonitorContendedEnteredRequestImpl() {
535             requestList().add(this);
536         }
537 
538         int eventCmd() {
539             return JDWP.EventKind.MONITOR_CONTENDED_ENTERED;
540         }
541 
542         public String toString() {
543             return "monitor contended entered request " + state();
544         }
545     }
546 
547     class MonitorWaitRequestImpl extends ClassVisibleEventRequestImpl
548                                  implements MonitorWaitRequest {
549         MonitorWaitRequestImpl() {
550             requestList().add(this);
551         }
552 
553         int eventCmd() {
554             return JDWP.EventKind.MONITOR_WAIT;
555         }
556 
557         public String toString() {
558             return "monitor wait request " + state();
559         }
560     }
561 
562     class MonitorWaitedRequestImpl extends ClassVisibleEventRequestImpl
563                                    implements MonitorWaitedRequest {
564         MonitorWaitedRequestImpl() {
565             requestList().add(this);
566         }
567 
568         int eventCmd() {
569             return JDWP.EventKind.MONITOR_WAITED;
570         }
571 
572         public String toString() {
573             return "monitor waited request " + state();
574         }
575     }
576 
577     class StepRequestImpl extends ClassVisibleEventRequestImpl
578                           implements StepRequest {
579         ThreadReferenceImpl thread;
580         int size;
581         int depth;
582 
583         StepRequestImpl(ThreadReference thread, int size, int depth) {
584             this.thread = (ThreadReferenceImpl)thread;
585             this.size = size;
586             this.depth = depth;
587 
588             /*
589              * Translate size and depth to corresponding JDWP values.
590              */
591             int jdwpSize;
592             switch (size) {
593                 case STEP_MIN:
594                     jdwpSize = JDWP.StepSize.MIN;
595                     break;
596                 case STEP_LINE:
597                     jdwpSize = JDWP.StepSize.LINE;
598                     break;
599                 default:
600                     throw new IllegalArgumentException("Invalid step size");
601             }
602 
603             int jdwpDepth;
604             switch (depth) {
605                 case STEP_INTO:
606                     jdwpDepth = JDWP.StepDepth.INTO;
607                     break;
608                 case STEP_OVER:
609                     jdwpDepth = JDWP.StepDepth.OVER;
610                     break;
611                 case STEP_OUT:
612                     jdwpDepth = JDWP.StepDepth.OUT;
613                     break;
614                 default:
615                     throw new IllegalArgumentException("Invalid step depth");
616             }
617 
618             /*
619              * Make sure this isn't a duplicate
620              */
621             List<StepRequest> requests = stepRequests();
622             for (StepRequest request : requests) {
623                 if ((request != this) &&
624                         request.isEnabled() &&
625                         request.thread().equals(thread)) {
626                     throw new DuplicateRequestException(
627                         "Only one step request allowed per thread");
628                 }
629             }
630 
631             filters.add(JDWP.EventRequest.Set.Modifier.Step.
632                         create(this.thread, jdwpSize, jdwpDepth));
633             requestList().add(this);
634 
635         }
636         public int depth() {
637             return depth;
638         }
639 
640         public int size() {
641             return size;
642         }
643 
644         public ThreadReference thread() {
645             return thread;
646         }
647 
648         int eventCmd() {
649             return JDWP.EventKind.SINGLE_STEP;
650         }
651 
652         public String toString() {
653             return "step request " + thread() + state();
654         }
655     }
656 
657     class ThreadDeathRequestImpl extends ThreadLifecycleEventRequestImpl
658                                  implements ThreadDeathRequest {
659         ThreadDeathRequestImpl() {
660             requestList().add(this);
661         }
662 
663         int eventCmd() {
664             return JDWP.EventKind.THREAD_DEATH;
665         }
666 
667         public String toString() {
668             return "thread death request " + state();
669         }
670     }
671 
672     class ThreadStartRequestImpl extends ThreadLifecycleEventRequestImpl
673                                  implements ThreadStartRequest {
674         ThreadStartRequestImpl() {
675             requestList().add(this);
676         }
677 
678         int eventCmd() {
679             return JDWP.EventKind.THREAD_START;
680         }
681 
682         public String toString() {
683             return "thread start request " + state();
684         }
685     }
686 
687     abstract class WatchpointRequestImpl extends ClassVisibleEventRequestImpl
688                                          implements WatchpointRequest {
689         final Field field;
690 
691         WatchpointRequestImpl(Field field) {
692             this.field = field;
693             filters.add(0,
694                    JDWP.EventRequest.Set.Modifier.FieldOnly.create(
695                     (ReferenceTypeImpl)field.declaringType(),
696                     ((FieldImpl)field).ref()));
697         }
698 
699         public Field field() {
700             return field;
701         }
702     }
703 
704     class AccessWatchpointRequestImpl extends WatchpointRequestImpl
705                                       implements AccessWatchpointRequest {
706         AccessWatchpointRequestImpl(Field field) {
707             super(field);
708             requestList().add(this);
709         }
710 
711         int eventCmd() {
712             return JDWP.EventKind.FIELD_ACCESS;
713         }
714 
715         public String toString() {
716             return "access watchpoint request " + field + state();
717         }
718     }
719 
720     class ModificationWatchpointRequestImpl extends WatchpointRequestImpl
721                                             implements ModificationWatchpointRequest {
722         ModificationWatchpointRequestImpl(Field field) {
723             super(field);
724             requestList().add(this);
725         }
726 
727         int eventCmd() {
728             return JDWP.EventKind.FIELD_MODIFICATION;
729         }
730 
731         public String toString() {
732             return "modification watchpoint request " + field + state();
733         }
734     }
735 
736     class VMDeathRequestImpl extends EventRequestImpl
737                              implements VMDeathRequest {
738         VMDeathRequestImpl() {
739             requestList().add(this);
740         }
741 
742         int eventCmd() {
743             return JDWP.EventKind.VM_DEATH;
744         }
745 
746         public String toString() {
747             return "VM death request " + state();
748         }
749     }
750 
751     /**
752      * Constructor.
753      */
754     EventRequestManagerImpl(VirtualMachine vm) {
755         super(vm);
756         java.lang.reflect.Field[] ekinds =
757             JDWP.EventKind.class.getDeclaredFields();
758         int highest = 0;
759         for (int i = 0; i < ekinds.length; ++i) {
760             int val;
761             try {
762                 val = ekinds[i].getInt(null);
763             } catch (IllegalAccessException exc) {
764                 throw new RuntimeException("Got: " + exc);
765             }
766             if (val > highest) {
767                 highest = val;
768             }
769         }
770         requestLists = new List[highest+1];
771         for (int i=0; i <= highest; i++) {
772             requestLists[i] = Collections.synchronizedList(new ArrayList<>());
773         }
774     }
775 
776     public ClassPrepareRequest createClassPrepareRequest() {
777         return new ClassPrepareRequestImpl();
778     }
779 
780     public ClassUnloadRequest createClassUnloadRequest() {
781         return new ClassUnloadRequestImpl();
782     }
783 
784     public ExceptionRequest createExceptionRequest(ReferenceType refType,
785                                                    boolean notifyCaught,
786                                                    boolean notifyUncaught) {
787         validateMirrorOrNull(refType);
788         return new ExceptionRequestImpl(refType, notifyCaught, notifyUncaught);
789     }
790 
791     public StepRequest createStepRequest(ThreadReference thread,
792                                          int size, int depth) {
793         validateMirror(thread);
794         return new StepRequestImpl(thread, size, depth);
795     }
796 
797     public ThreadDeathRequest createThreadDeathRequest() {
798         return new ThreadDeathRequestImpl();
799     }
800 
801     public ThreadStartRequest createThreadStartRequest() {
802         return new ThreadStartRequestImpl();
803     }
804 
805     public MethodEntryRequest createMethodEntryRequest() {
806         return new MethodEntryRequestImpl();
807     }
808 
809     public MethodExitRequest createMethodExitRequest() {
810         return new MethodExitRequestImpl();
811     }
812 
813     public MonitorContendedEnterRequest createMonitorContendedEnterRequest() {
814         if (!vm.canRequestMonitorEvents()) {
815             throw new UnsupportedOperationException(
816           "target VM does not support requesting Monitor events");
817         }
818         return new MonitorContendedEnterRequestImpl();
819     }
820 
821     public MonitorContendedEnteredRequest createMonitorContendedEnteredRequest() {
822         if (!vm.canRequestMonitorEvents()) {
823             throw new UnsupportedOperationException(
824           "target VM does not support requesting Monitor events");
825         }
826         return new MonitorContendedEnteredRequestImpl();
827     }
828 
829     public MonitorWaitRequest createMonitorWaitRequest() {
830         if (!vm.canRequestMonitorEvents()) {
831             throw new UnsupportedOperationException(
832           "target VM does not support requesting Monitor events");
833         }
834         return new MonitorWaitRequestImpl();
835     }
836 
837     public MonitorWaitedRequest createMonitorWaitedRequest() {
838         if (!vm.canRequestMonitorEvents()) {
839             throw new UnsupportedOperationException(
840           "target VM does not support requesting Monitor events");
841         }
842         return new MonitorWaitedRequestImpl();
843     }
844 
845     public BreakpointRequest createBreakpointRequest(Location location) {
846         validateMirror(location);
847         if (location.codeIndex() == -1) {
848             throw new NativeMethodException("Cannot set breakpoints on native methods");
849         }
850         return new BreakpointRequestImpl(location);
851     }
852 
853     public AccessWatchpointRequest
854                               createAccessWatchpointRequest(Field field) {
855         validateMirror(field);
856         if (!vm.canWatchFieldAccess()) {
857             throw new UnsupportedOperationException(
858           "target VM does not support access watchpoints");
859         }
860         return new AccessWatchpointRequestImpl(field);
861     }
862 
863     public ModificationWatchpointRequest
864                         createModificationWatchpointRequest(Field field) {
865         validateMirror(field);
866         if (!vm.canWatchFieldModification()) {
867             throw new UnsupportedOperationException(
868           "target VM does not support modification watchpoints");
869         }
870         return new ModificationWatchpointRequestImpl(field);
871     }
872 
873     public VMDeathRequest createVMDeathRequest() {
874         if (!vm.canRequestVMDeathEvent()) {
875             throw new UnsupportedOperationException(
876           "target VM does not support requesting VM death events");
877         }
878         return new VMDeathRequestImpl();
879     }
880 
881     public void deleteEventRequest(EventRequest eventRequest) {
882         validateMirror(eventRequest);
883         ((EventRequestImpl)eventRequest).delete();
884     }
885 
886     public void deleteEventRequests(List<? extends EventRequest> eventRequests) {
887         validateMirrors(eventRequests);
888         // copy the eventRequests to avoid ConcurrentModificationException
889         for (EventRequest eventRequest : new ArrayList<>(eventRequests)) {
890             ((EventRequestImpl)eventRequest).delete();
891         }
892     }
893 
894     public void deleteAllBreakpoints() {
895         requestList(JDWP.EventKind.BREAKPOINT).clear();
896 
897         try {
898             JDWP.EventRequest.ClearAllBreakpoints.process(vm);
899         } catch (JDWPException exc) {
900             throw exc.toJDIException();
901         }
902     }
903 
904     public List<StepRequest> stepRequests() {
905         return (List<StepRequest>)unmodifiableRequestList(JDWP.EventKind.SINGLE_STEP);
906     }
907 
908     public List<ClassPrepareRequest> classPrepareRequests() {
909         return (List<ClassPrepareRequest>)unmodifiableRequestList(JDWP.EventKind.CLASS_PREPARE);
910     }
911 
912     public List<ClassUnloadRequest> classUnloadRequests() {
913         return (List<ClassUnloadRequest>)unmodifiableRequestList(JDWP.EventKind.CLASS_UNLOAD);
914     }
915 
916     public List<ThreadStartRequest> threadStartRequests() {
917         return (List<ThreadStartRequest>)unmodifiableRequestList(JDWP.EventKind.THREAD_START);
918     }
919 
920     public List<ThreadDeathRequest> threadDeathRequests() {
921         return (List<ThreadDeathRequest>)unmodifiableRequestList(JDWP.EventKind.THREAD_DEATH);
922     }
923 
924     public List<ExceptionRequest> exceptionRequests() {
925         return (List<ExceptionRequest>)unmodifiableRequestList(JDWP.EventKind.EXCEPTION);
926     }
927 
928     public List<BreakpointRequest> breakpointRequests() {
929         return (List<BreakpointRequest>)unmodifiableRequestList(JDWP.EventKind.BREAKPOINT);
930     }
931 
932     public List<AccessWatchpointRequest> accessWatchpointRequests() {
933         return (List<AccessWatchpointRequest>)unmodifiableRequestList(JDWP.EventKind.FIELD_ACCESS);
934     }
935 
936     public List<ModificationWatchpointRequest> modificationWatchpointRequests() {
937         return (List<ModificationWatchpointRequest>)unmodifiableRequestList(JDWP.EventKind.FIELD_MODIFICATION);
938     }
939 
940     public List<MethodEntryRequest> methodEntryRequests() {
941         return (List<MethodEntryRequest>)unmodifiableRequestList(JDWP.EventKind.METHOD_ENTRY);
942     }
943 
944     public List<MethodExitRequest> methodExitRequests() {
945         return (List<MethodExitRequest>)unmodifiableRequestList(EventRequestManagerImpl.methodExitEventCmd);
946     }
947 
948     public List<MonitorContendedEnterRequest> monitorContendedEnterRequests() {
949         return (List<MonitorContendedEnterRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTER);
950     }
951 
952     public List<MonitorContendedEnteredRequest> monitorContendedEnteredRequests() {
953         return (List<MonitorContendedEnteredRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTERED);
954     }
955 
956     public List<MonitorWaitRequest> monitorWaitRequests() {
957         return (List<MonitorWaitRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_WAIT);
958     }
959 
960     public List<MonitorWaitedRequest> monitorWaitedRequests() {
961         return (List<MonitorWaitedRequest>)unmodifiableRequestList(JDWP.EventKind.MONITOR_WAITED);
962     }
963 
964     public List<VMDeathRequest> vmDeathRequests() {
965         return (List<VMDeathRequest>)unmodifiableRequestList(JDWP.EventKind.VM_DEATH);
966     }
967 
968     List<? extends EventRequest> unmodifiableRequestList(int eventCmd) {
969         // No need of explicit synchronization for requestList here.
970         // It is taken care internally by SynchronizedList class.
971         return Collections.unmodifiableList(new ArrayList<>(requestList(eventCmd)));
972     }
973 
974     EventRequest request(int eventCmd, int requestId) {
975         List<? extends EventRequest> rl = requestList(eventCmd);
976         synchronized(rl) {   // Refer Collections.synchronizedList javadoc.
977             for (EventRequest eventRequest : rl) {
978                 EventRequestImpl er = (EventRequestImpl)eventRequest;
979                 if (er.id == requestId)
980                     return er;
981             }
982         }
983         return null;
984     }
985 
986     private List<? extends EventRequest> requestList(int eventCmd) {
987         return requestLists[eventCmd];
988     }
989 }