jdk/src/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,955 @@
+/*
+ * Copyright 1998-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.request.*;
+import com.sun.tools.jdi.JDWP;
+
+import java.util.*;
+
+/**
+ * This interface is used to create and remove Breakpoints, Watchpoints,
+ * etc.
+ * It include implementations of all the request interfaces..
+ */
+// Warnings from List filters and List[] requestLists is  hard to fix.
+// Remove SuppressWarning when we fix the warnings from List filters
+// and List[] requestLists. The generic array is not supported.
+@SuppressWarnings("unchecked")
+class EventRequestManagerImpl extends MirrorImpl
+                                       implements EventRequestManager
+{
+    List[] requestLists;
+    private static int methodExitEventCmd = 0;
+
+    static int JDWPtoJDISuspendPolicy(byte jdwpPolicy) {
+        switch(jdwpPolicy) {
+            case JDWP.SuspendPolicy.ALL:
+                return EventRequest.SUSPEND_ALL;
+            case JDWP.SuspendPolicy.EVENT_THREAD:
+                return EventRequest.SUSPEND_EVENT_THREAD;
+        case JDWP.SuspendPolicy.NONE:
+                return EventRequest.SUSPEND_NONE;
+            default:
+                throw new IllegalArgumentException("Illegal policy constant: " + jdwpPolicy);
+        }
+    }
+
+    static byte JDItoJDWPSuspendPolicy(int jdiPolicy) {
+        switch(jdiPolicy) {
+            case EventRequest.SUSPEND_ALL:
+                return JDWP.SuspendPolicy.ALL;
+            case EventRequest.SUSPEND_EVENT_THREAD:
+                return JDWP.SuspendPolicy.EVENT_THREAD;
+            case EventRequest.SUSPEND_NONE:
+                return JDWP.SuspendPolicy.NONE;
+            default:
+                throw new IllegalArgumentException("Illegal policy constant: " + jdiPolicy);
+        }
+    }
+
+    /*
+     * Override superclass back to default equality
+     */
+    public boolean equals(Object obj) {
+        return this == obj;
+    }
+
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    abstract class EventRequestImpl extends MirrorImpl implements EventRequest {
+        int id;
+
+        /*
+         * This list is not protected by a synchronized wrapper. All
+         * access/modification should be protected by synchronizing on
+         * the enclosing instance of EventRequestImpl.
+         */
+        List filters = new ArrayList();
+
+        boolean isEnabled = false;
+        boolean deleted = false;
+        byte suspendPolicy = JDWP.SuspendPolicy.ALL;
+        private Map<Object, Object> clientProperties = null;
+
+        EventRequestImpl() {
+            super(EventRequestManagerImpl.this.vm);
+        }
+
+
+        /*
+         * Override superclass back to default equality
+         */
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+
+        public int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        abstract int eventCmd();
+
+        InvalidRequestStateException invalidState() {
+            return new InvalidRequestStateException(toString());
+        }
+
+        String state() {
+            return deleted? " (deleted)" :
+                (isEnabled()? " (enabled)" : " (disabled)");
+        }
+
+        /**
+         * @return all the event request of this kind
+         */
+        List requestList() {
+            return EventRequestManagerImpl.this.requestList(eventCmd());
+        }
+
+        /**
+         * delete the event request
+         */
+        void delete() {
+            if (!deleted) {
+                requestList().remove(this);
+                disable(); /* must do BEFORE delete */
+                deleted = true;
+            }
+        }
+
+        public boolean isEnabled() {
+            return isEnabled;
+        }
+
+        public void enable() {
+            setEnabled(true);
+        }
+
+        public void disable() {
+            setEnabled(false);
+        }
+
+        public synchronized void setEnabled(boolean val) {
+            if (deleted) {
+                throw invalidState();
+            } else {
+                if (val != isEnabled) {
+                    if (isEnabled) {
+                        clear();
+                    } else {
+                        set();
+                    }
+                }
+            }
+        }
+
+        public synchronized void addCountFilter(int count) {
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            if (count < 1) {
+                throw new IllegalArgumentException("count is less than one");
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.Count.create(count));
+        }
+
+        public void setSuspendPolicy(int policy) {
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            suspendPolicy = JDItoJDWPSuspendPolicy(policy);
+        }
+
+        public int suspendPolicy() {
+            return JDWPtoJDISuspendPolicy(suspendPolicy);
+        }
+
+        /**
+         * set (enable) the event request
+         */
+        synchronized void set() {
+            JDWP.EventRequest.Set.Modifier[] mods =
+                (JDWP.EventRequest.Set.Modifier[])
+                filters.toArray(
+                    new JDWP.EventRequest.Set.Modifier[filters.size()]);
+            try {
+                id = JDWP.EventRequest.Set.process(vm, (byte)eventCmd(),
+                                                   suspendPolicy, mods).requestID;
+            } catch (JDWPException exc) {
+                throw exc.toJDIException();
+            }
+            isEnabled = true;
+        }
+
+        synchronized void clear() {
+            try {
+                JDWP.EventRequest.Clear.process(vm, (byte)eventCmd(), id);
+            } catch (JDWPException exc) {
+                throw exc.toJDIException();
+            }
+            isEnabled = false;
+        }
+
+        /**
+         * @return a small Map
+         * @see #putProperty
+         * @see #getProperty
+         */
+        private Map<Object, Object> getProperties() {
+            if (clientProperties == null) {
+                clientProperties = new HashMap<Object, Object>(2);
+            }
+            return clientProperties;
+        }
+
+        /**
+         * Returns the value of the property with the specified key.  Only
+         * properties added with <code>putProperty</code> will return
+         * a non-null value.
+         *
+         * @return the value of this property or null
+         * @see #putProperty
+         */
+        public final Object getProperty(Object key) {
+            if (clientProperties == null) {
+                return null;
+            } else {
+                return getProperties().get(key);
+            }
+        }
+
+        /**
+         * Add an arbitrary key/value "property" to this component.
+         *
+         * @see #getProperty
+         */
+        public final void putProperty(Object key, Object value) {
+            if (value != null) {
+                getProperties().put(key, value);
+            } else {
+                getProperties().remove(key);
+            }
+        }
+    }
+
+    abstract class ThreadVisibleEventRequestImpl extends EventRequestImpl {
+        public synchronized void addThreadFilter(ThreadReference thread) {
+            validateMirror(thread);
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.ThreadOnly
+                                      .create((ThreadReferenceImpl)thread));
+        }
+    }
+
+    abstract class ClassVisibleEventRequestImpl
+                                  extends ThreadVisibleEventRequestImpl {
+        public synchronized void addClassFilter(ReferenceType clazz) {
+            validateMirror(clazz);
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.ClassOnly
+                                      .create((ReferenceTypeImpl)clazz));
+        }
+
+        public synchronized void addClassFilter(String classPattern) {
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            if (classPattern == null) {
+                throw new NullPointerException();
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.ClassMatch
+                                      .create(classPattern));
+        }
+
+        public synchronized void addClassExclusionFilter(String classPattern) {
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            if (classPattern == null) {
+                throw new NullPointerException();
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.ClassExclude
+                                      .create(classPattern));
+        }
+
+        public synchronized void addInstanceFilter(ObjectReference instance) {
+            validateMirror(instance);
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            if (!vm.canUseInstanceFilters()) {
+                throw new UnsupportedOperationException(
+                     "target does not support instance filters");
+            }
+            filters.add(JDWP.EventRequest.Set.Modifier.InstanceOnly
+                                      .create((ObjectReferenceImpl)instance));
+        }
+    }
+
+    class BreakpointRequestImpl extends ClassVisibleEventRequestImpl
+                                     implements BreakpointRequest {
+        private final Location location;
+
+        BreakpointRequestImpl(Location location) {
+            this.location = location;
+            filters.add(0,JDWP.EventRequest.Set.Modifier.LocationOnly
+                                                 .create(location));
+            requestList().add(this);
+        }
+
+        public Location location() {
+            return location;
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.BREAKPOINT;
+        }
+
+        public String toString() {
+            return "breakpoint request " + location() + state();
+        }
+    }
+
+    class ClassPrepareRequestImpl extends ClassVisibleEventRequestImpl
+                                     implements ClassPrepareRequest {
+        ClassPrepareRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.CLASS_PREPARE;
+        }
+
+        public synchronized void addSourceNameFilter(String sourceNamePattern) {
+            if (isEnabled() || deleted) {
+                throw invalidState();
+            }
+            if (!vm.canUseSourceNameFilters()) {
+                throw new UnsupportedOperationException(
+                     "target does not support source name filters");
+            }
+            if (sourceNamePattern == null) {
+                throw new NullPointerException();
+            }
+
+            filters.add(JDWP.EventRequest.Set.Modifier.SourceNameMatch
+                                      .create(sourceNamePattern));
+        }
+
+        public String toString() {
+            return "class prepare request " + state();
+        }
+    }
+
+    class ClassUnloadRequestImpl extends ClassVisibleEventRequestImpl
+                                     implements ClassUnloadRequest {
+        ClassUnloadRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.CLASS_UNLOAD;
+        }
+
+        public String toString() {
+            return "class unload request " + state();
+        }
+    }
+
+    class ExceptionRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements ExceptionRequest {
+        ReferenceType exception = null;
+        boolean caught = true;
+        boolean uncaught = true;
+
+        ExceptionRequestImpl(ReferenceType refType,
+                          boolean notifyCaught, boolean notifyUncaught) {
+            exception = refType;
+            caught = notifyCaught;
+            uncaught = notifyUncaught;
+            {
+                ReferenceTypeImpl exc;
+                if (exception == null) {
+                    exc = new ClassTypeImpl(vm, 0);
+                } else {
+                    exc = (ReferenceTypeImpl)exception;
+                }
+                filters.add(JDWP.EventRequest.Set.Modifier.ExceptionOnly.
+                            create(exc, caught, uncaught));
+            }
+            requestList().add(this);
+        }
+
+        public ReferenceType exception() {
+            return exception;
+        }
+
+        public boolean notifyCaught() {
+            return caught;
+        }
+
+        public boolean notifyUncaught() {
+            return uncaught;
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.EXCEPTION;
+        }
+
+        public String toString() {
+            return "exception request " + exception() + state();
+        }
+    }
+
+    class MethodEntryRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements MethodEntryRequest {
+        MethodEntryRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.METHOD_ENTRY;
+        }
+
+        public String toString() {
+            return "method entry request " + state();
+        }
+    }
+
+    class MethodExitRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements MethodExitRequest {
+        MethodExitRequestImpl() {
+            if (methodExitEventCmd == 0) {
+                /*
+                 * If we can get return values, then we always get them.
+                 * Thus, for JDI MethodExitRequests, we always use the
+                 * same JDWP EventKind.  Here we decide which to use and
+                 * save it so that it will be used for all future
+                 * MethodExitRequests.
+                 *
+                 * This call to canGetMethodReturnValues can't
+                 * be done in the EventRequestManager ctor because that is too early.
+                 */
+                if (vm.canGetMethodReturnValues()) {
+                    methodExitEventCmd = JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE;
+                } else {
+                    methodExitEventCmd = JDWP.EventKind.METHOD_EXIT;
+                }
+            }
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return EventRequestManagerImpl.methodExitEventCmd;
+        }
+
+        public String toString() {
+            return "method exit request " + state();
+        }
+    }
+
+    class MonitorContendedEnterRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements MonitorContendedEnterRequest {
+        MonitorContendedEnterRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.MONITOR_CONTENDED_ENTER;
+        }
+
+        public String toString() {
+            return "monitor contended enter request " + state();
+        }
+    }
+
+    class MonitorContendedEnteredRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements MonitorContendedEnteredRequest {
+        MonitorContendedEnteredRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.MONITOR_CONTENDED_ENTERED;
+        }
+
+        public String toString() {
+            return "monitor contended entered request " + state();
+        }
+    }
+
+    class MonitorWaitRequestImpl extends ClassVisibleEventRequestImpl
+                                 implements MonitorWaitRequest {
+        MonitorWaitRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.MONITOR_WAIT;
+        }
+
+        public String toString() {
+            return "monitor wait request " + state();
+        }
+    }
+
+    class MonitorWaitedRequestImpl extends ClassVisibleEventRequestImpl
+                                 implements MonitorWaitedRequest {
+        MonitorWaitedRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.MONITOR_WAITED;
+        }
+
+        public String toString() {
+            return "monitor waited request " + state();
+        }
+    }
+
+    class StepRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements StepRequest {
+        ThreadReferenceImpl thread;
+        int size;
+        int depth;
+
+        StepRequestImpl(ThreadReference thread, int size, int depth) {
+            this.thread = (ThreadReferenceImpl)thread;
+            this.size = size;
+            this.depth = depth;
+
+            /*
+             * Translate size and depth to corresponding JDWP values.
+             */
+            int jdwpSize;
+            switch (size) {
+                case STEP_MIN:
+                    jdwpSize = JDWP.StepSize.MIN;
+                    break;
+                case STEP_LINE:
+                    jdwpSize = JDWP.StepSize.LINE;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid step size");
+            }
+
+            int jdwpDepth;
+            switch (depth) {
+                case STEP_INTO:
+                    jdwpDepth = JDWP.StepDepth.INTO;
+                    break;
+                case STEP_OVER:
+                    jdwpDepth = JDWP.StepDepth.OVER;
+                    break;
+                case STEP_OUT:
+                    jdwpDepth = JDWP.StepDepth.OUT;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid step depth");
+            }
+
+            /*
+             * Make sure this isn't a duplicate
+             */
+            List requests = stepRequests();
+            Iterator iter = requests.iterator();
+            while (iter.hasNext()) {
+                StepRequest request = (StepRequest)iter.next();
+                if ((request != this) &&
+                        request.isEnabled() &&
+                        request.thread().equals(thread)) {
+                    throw new DuplicateRequestException(
+                        "Only one step request allowed per thread");
+                }
+            }
+
+            filters.add(JDWP.EventRequest.Set.Modifier.Step.
+                        create(this.thread, jdwpSize, jdwpDepth));
+            requestList().add(this);
+
+        }
+        public int depth() {
+            return depth;
+        }
+
+        public int size() {
+            return size;
+        }
+
+        public ThreadReference thread() {
+            return thread;
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.SINGLE_STEP;
+        }
+
+        public String toString() {
+            return "step request " + thread() + state();
+        }
+    }
+
+    class ThreadDeathRequestImpl extends ThreadVisibleEventRequestImpl
+                                      implements ThreadDeathRequest {
+        ThreadDeathRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.THREAD_DEATH;
+        }
+
+        public String toString() {
+            return "thread death request " + state();
+        }
+    }
+
+    class ThreadStartRequestImpl extends ThreadVisibleEventRequestImpl
+                                      implements ThreadStartRequest {
+        ThreadStartRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.THREAD_START;
+        }
+
+        public String toString() {
+            return "thread start request " + state();
+        }
+    }
+
+    abstract class WatchpointRequestImpl extends ClassVisibleEventRequestImpl
+                                      implements WatchpointRequest {
+        final Field field;
+
+        WatchpointRequestImpl(Field field) {
+            this.field = field;
+            filters.add(0,
+                   JDWP.EventRequest.Set.Modifier.FieldOnly.create(
+                    (ReferenceTypeImpl)field.declaringType(),
+                    ((FieldImpl)field).ref()));
+        }
+
+        public Field field() {
+            return field;
+        }
+    }
+
+    class AccessWatchpointRequestImpl extends WatchpointRequestImpl
+                                  implements AccessWatchpointRequest {
+        AccessWatchpointRequestImpl(Field field) {
+            super(field);
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.FIELD_ACCESS;
+        }
+
+        public String toString() {
+            return "access watchpoint request " + field + state();
+        }
+    }
+
+    class ModificationWatchpointRequestImpl extends WatchpointRequestImpl
+                                  implements ModificationWatchpointRequest {
+        ModificationWatchpointRequestImpl(Field field) {
+            super(field);
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.FIELD_MODIFICATION;
+        }
+
+        public String toString() {
+            return "modification watchpoint request " + field + state();
+        }
+    }
+
+    class VMDeathRequestImpl extends EventRequestImpl
+                                        implements VMDeathRequest {
+        VMDeathRequestImpl() {
+            requestList().add(this);
+        }
+
+        int eventCmd() {
+            return JDWP.EventKind.VM_DEATH;
+        }
+
+        public String toString() {
+            return "VM death request " + state();
+        }
+    }
+
+    /**
+     * Constructor.
+     */
+    EventRequestManagerImpl(VirtualMachine vm) {
+        super(vm);
+        java.lang.reflect.Field[] ekinds =
+            JDWP.EventKind.class.getDeclaredFields();
+        int highest = 0;
+        for (int i = 0; i < ekinds.length; ++i) {
+            int val;
+            try {
+                val = ekinds[i].getInt(null);
+            } catch (IllegalAccessException exc) {
+                throw new RuntimeException("Got: " + exc);
+            }
+            if (val > highest) {
+                highest = val;
+            }
+        }
+        requestLists = new List[highest+1];
+        for (int i=0; i <= highest; i++) {
+            requestLists[i] = new ArrayList();
+        }
+    }
+
+    public ClassPrepareRequest createClassPrepareRequest() {
+        return new ClassPrepareRequestImpl();
+    }
+
+    public ClassUnloadRequest createClassUnloadRequest() {
+        return new ClassUnloadRequestImpl();
+    }
+
+    public ExceptionRequest createExceptionRequest(ReferenceType refType,
+                                                   boolean notifyCaught,
+                                                   boolean notifyUncaught) {
+        validateMirrorOrNull(refType);
+        return new ExceptionRequestImpl(refType, notifyCaught, notifyUncaught);
+    }
+
+    public StepRequest createStepRequest(ThreadReference thread,
+                                         int size, int depth) {
+        validateMirror(thread);
+        return new StepRequestImpl(thread, size, depth);
+    }
+
+    public ThreadDeathRequest createThreadDeathRequest() {
+        return new ThreadDeathRequestImpl();
+    }
+
+    public ThreadStartRequest createThreadStartRequest() {
+        return new ThreadStartRequestImpl();
+    }
+
+    public MethodEntryRequest createMethodEntryRequest() {
+        return new MethodEntryRequestImpl();
+    }
+
+    public MethodExitRequest createMethodExitRequest() {
+        return new MethodExitRequestImpl();
+    }
+
+    public MonitorContendedEnterRequest createMonitorContendedEnterRequest() {
+        if (!vm.canRequestMonitorEvents()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support requesting Monitor events");
+        }
+        return new MonitorContendedEnterRequestImpl();
+    }
+
+    public MonitorContendedEnteredRequest createMonitorContendedEnteredRequest() {
+        if (!vm.canRequestMonitorEvents()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support requesting Monitor events");
+        }
+        return new MonitorContendedEnteredRequestImpl();
+    }
+
+    public MonitorWaitRequest createMonitorWaitRequest() {
+        if (!vm.canRequestMonitorEvents()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support requesting Monitor events");
+        }
+        return new MonitorWaitRequestImpl();
+    }
+
+    public MonitorWaitedRequest createMonitorWaitedRequest() {
+        if (!vm.canRequestMonitorEvents()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support requesting Monitor events");
+        }
+        return new MonitorWaitedRequestImpl();
+    }
+
+    public BreakpointRequest createBreakpointRequest(Location location) {
+        validateMirror(location);
+        if (location.codeIndex() == -1) {
+            throw new NativeMethodException("Cannot set breakpoints on native methods");
+        }
+        return new BreakpointRequestImpl(location);
+    }
+
+    public AccessWatchpointRequest
+                              createAccessWatchpointRequest(Field field) {
+        validateMirror(field);
+        if (!vm.canWatchFieldAccess()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support access watchpoints");
+        }
+        return new AccessWatchpointRequestImpl(field);
+    }
+
+    public ModificationWatchpointRequest
+                        createModificationWatchpointRequest(Field field) {
+        validateMirror(field);
+        if (!vm.canWatchFieldModification()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support modification watchpoints");
+        }
+        return new ModificationWatchpointRequestImpl(field);
+    }
+
+    public VMDeathRequest createVMDeathRequest() {
+        if (!vm.canRequestVMDeathEvent()) {
+            throw new UnsupportedOperationException(
+          "target VM does not support requesting VM death events");
+        }
+        return new VMDeathRequestImpl();
+    }
+
+    public void deleteEventRequest(EventRequest eventRequest) {
+        validateMirror(eventRequest);
+        ((EventRequestImpl)eventRequest).delete();
+    }
+
+    public void deleteEventRequests(List<? extends EventRequest> eventRequests) {
+        validateMirrors(eventRequests);
+        // copy the eventRequests to avoid ConcurrentModificationException
+        Iterator iter = (new ArrayList(eventRequests)).iterator();
+        while (iter.hasNext()) {
+            ((EventRequestImpl)iter.next()).delete();
+        }
+    }
+
+    public void deleteAllBreakpoints() {
+        requestList(JDWP.EventKind.BREAKPOINT).clear();
+
+        try {
+            JDWP.EventRequest.ClearAllBreakpoints.process(vm);
+        } catch (JDWPException exc) {
+            throw exc.toJDIException();
+        }
+    }
+
+    public List<StepRequest> stepRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.SINGLE_STEP);
+    }
+
+    public List<ClassPrepareRequest> classPrepareRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.CLASS_PREPARE);
+    }
+
+    public List<ClassUnloadRequest> classUnloadRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.CLASS_UNLOAD);
+    }
+
+    public List<ThreadStartRequest> threadStartRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.THREAD_START);
+    }
+
+    public List<ThreadDeathRequest> threadDeathRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.THREAD_DEATH);
+    }
+
+    public List<ExceptionRequest> exceptionRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.EXCEPTION);
+    }
+
+    public List<BreakpointRequest> breakpointRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.BREAKPOINT);
+    }
+
+    public List<AccessWatchpointRequest> accessWatchpointRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.FIELD_ACCESS);
+    }
+
+    public List<ModificationWatchpointRequest> modificationWatchpointRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.FIELD_MODIFICATION);
+    }
+
+    public List<MethodEntryRequest> methodEntryRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.METHOD_ENTRY);
+    }
+
+    public List<MethodExitRequest> methodExitRequests() {
+        return unmodifiableRequestList(
+                               EventRequestManagerImpl.methodExitEventCmd);
+    }
+
+    public List<MonitorContendedEnterRequest> monitorContendedEnterRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTER);
+    }
+
+    public List<MonitorContendedEnteredRequest> monitorContendedEnteredRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.MONITOR_CONTENDED_ENTERED);
+    }
+
+    public List<MonitorWaitRequest> monitorWaitRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.MONITOR_WAIT);
+    }
+
+    public List<MonitorWaitedRequest> monitorWaitedRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.MONITOR_WAITED);
+    }
+
+    public List<VMDeathRequest> vmDeathRequests() {
+        return unmodifiableRequestList(JDWP.EventKind.VM_DEATH);
+    }
+
+    List unmodifiableRequestList(int eventCmd) {
+        return Collections.unmodifiableList(requestList(eventCmd));
+    }
+
+    EventRequest request(int eventCmd, int requestId) {
+        List rl = requestList(eventCmd);
+        for (int i = rl.size() - 1; i >= 0; i--) {
+            EventRequestImpl er = (EventRequestImpl)rl.get(i);
+            if (er.id == requestId) {
+                return er;
+            }
+        }
+        return null;
+    }
+
+    List<? extends EventRequest>  requestList(int eventCmd) {
+        return requestLists[eventCmd];
+    }
+
+}