merge in mnc-release history after reset to mnc-dev
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/VmMirror.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/VmMirror.java
index 3ffa6df..67c0aa0 100644
--- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/VmMirror.java
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/VmMirror.java
@@ -218,6 +218,19 @@
      * @return requestID id of request
      */
     public int setBreakpointAtMethodBegin(long classID, String methodName) {
+        return setBreakpointAtMethodBegin(classID, methodName, JDWPConstants.SuspendPolicy.ALL);
+    }
+
+    /**
+     * Sets breakpoint at the beginning of method with name <i>methodName</i>.
+     *
+     * @param classID
+     *            id of class with required method
+     * @param methodName
+     *            name of required method
+     * @return requestID id of request
+     */
+    public int setBreakpointAtMethodBegin(long classID, String methodName, byte suspendPolicy) {
         long methodID = getMethodID(classID, methodName);
 
         ReplyPacket lineTableReply = getLineTable(classID, methodID);
@@ -245,7 +258,7 @@
         Location breakpointLocation = new Location(JDWPConstants.TypeTag.CLASS,
                 classID, methodID, lineCodeIndex);
 
-        ReplyPacket reply = setBreakpoint(breakpointLocation);
+        ReplyPacket reply = setBreakpoint(breakpointLocation, suspendPolicy);
         checkReply(reply);
 
         return reply.getNextValueAsInt();
@@ -733,6 +746,22 @@
     }
 
     /**
+     * Returns suspend count for specified <code>threadID</code>.
+     *
+     * @param threadID
+     *            thread ID
+     * @return thread's suspend count
+     */
+    public int getThreadSuspendCount(long threadID) {
+        CommandPacket commandPacket = new CommandPacket(
+                JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
+                JDWPCommands.ThreadReferenceCommandSet.SuspendCountCommand);
+        commandPacket.setNextValueAsThreadID(threadID);
+        ReplyPacket replyPacket = checkReply(performCommand(commandPacket));
+        return replyPacket.getNextValueAsInt();
+    }
+
+    /**
      * Returns name of thread group for specified <code>groupID</code>
      * 
      * @param groupID
@@ -2349,6 +2378,20 @@
     }
 
     /**
+     * Returns the value of one static field of the reference type
+     *
+     * @param refTypeID
+     *            The reference type ID.
+     * @param fieldID
+     *            ID of field to get
+     * @return A Value object representing the field's value
+     */
+    public final Value getReferenceTypeValue(long refTypeID, long fieldID) {
+        Value[] values = getReferenceTypeValues(refTypeID, new long[]{fieldID});
+        return values[0];
+    }
+
+    /**
      * Returns the value of the 'this' reference for this frame
      * 
      * @param threadID
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/InvokeMethodWithSuspensionTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/InvokeMethodWithSuspensionTest.java
new file mode 100644
index 0000000..d1d7efe
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/InvokeMethodWithSuspensionTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.ClassType;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject;
+import org.apache.harmony.jpda.tests.framework.jdwp.Value;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPInvokeMethodWithSuspensionTestCase;
+import org.apache.harmony.jpda.tests.jdwp.share.debuggee.InvokeMethodWithSuspensionDebuggee;
+
+/**
+ * JDWP unit test for ClassType.InvokeCommand command with a thread suspension.
+ */
+public class InvokeMethodWithSuspensionTest extends JDWPInvokeMethodWithSuspensionTestCase {
+    public void testInvokeWithMultipleEvents001() {
+        runInvokeMethodTest(InvokeMethodWithSuspensionDebuggee.STATIC_METHOD_NAME);
+    }
+
+    @Override
+    protected CommandPacket buildInvokeCommand(long threadId, long classID,
+            long methodId, int invoke_options) {
+        CommandPacket command = new CommandPacket(
+                JDWPCommands.ClassTypeCommandSet.CommandSetID,
+                JDWPCommands.ClassTypeCommandSet.InvokeMethodCommand);
+        command.setNextValueAsClassID(classID);
+        command.setNextValueAsThreadID(threadId);
+        command.setNextValueAsMethodID(methodId);
+        command.setNextValueAsInt(0);
+        command.setNextValueAsInt(invoke_options);
+        return command;
+    }
+
+    @Override
+    protected String getInvokeCommandName() {
+        return "ClassType.InvokeCommand";
+    }
+
+    @Override
+    protected void checkInvokeReply(ReplyPacket reply) {
+        // Check result is 'void'
+        Value invokeResult = reply.getNextValueAsValue();
+        assertNull("Expect null result value for 'void'", invokeResult);
+
+        // Check exception is null.
+        TaggedObject invokeException = reply.getNextValueAsTaggedObject();
+        assertEquals("Invalid exception object id", 0, invokeException.objectID);
+        assertAllDataRead(reply);
+
+    }
+
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceWithSuspensionTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceWithSuspensionTest.java
new file mode 100644
index 0000000..26509d3
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceWithSuspensionTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.ClassType;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPInvokeMethodWithSuspensionTestCase;
+
+/**
+ * JDWP unit test for ClassType.NewInstance command with a thread suspension.
+ */
+public class NewInstanceWithSuspensionTest extends JDWPInvokeMethodWithSuspensionTestCase {
+    public void testInvokeWithMultipleEvents001() {
+        runInvokeMethodTest("<init>");
+    }
+
+    @Override
+    protected CommandPacket buildInvokeCommand(long threadId, long classID,
+            long methodId, int invoke_options) {
+        CommandPacket command = new CommandPacket(
+                JDWPCommands.ClassTypeCommandSet.CommandSetID,
+                JDWPCommands.ClassTypeCommandSet.NewInstanceCommand);
+        command.setNextValueAsClassID(classID);
+        command.setNextValueAsThreadID(threadId);
+        command.setNextValueAsMethodID(methodId);
+        command.setNextValueAsInt(0);
+        command.setNextValueAsInt(invoke_options);
+        return command;
+    }
+
+    @Override
+    protected String getInvokeCommandName() {
+        return "ClassType.NewInstance";
+    }
+
+    @Override
+    protected void checkInvokeReply(ReplyPacket reply) {
+        // Check result is 'void'
+        TaggedObject invokeNewObject = reply.getNextValueAsTaggedObject();
+        assertEquals(JDWPConstants.Tag.OBJECT_TAG, invokeNewObject.tag);
+        assertFalse("Invalid exception object id", invokeNewObject.objectID == 0);
+
+        // Check exception is null.
+        TaggedObject invokeException = reply.getNextValueAsTaggedObject();
+        assertEquals(JDWPConstants.Tag.OBJECT_TAG, invokeException.tag);
+        assertEquals("Invalid exception object id", 0, invokeException.objectID);
+
+        assertAllDataRead(reply);
+
+    }
+
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodWithSuspensionTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodWithSuspensionTest.java
new file mode 100644
index 0000000..578d446
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodWithSuspensionTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.ObjectReference;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject;
+import org.apache.harmony.jpda.tests.framework.jdwp.Value;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPInvokeMethodWithSuspensionTestCase;
+import org.apache.harmony.jpda.tests.jdwp.share.debuggee.InvokeMethodWithSuspensionDebuggee;
+
+/**
+ * JDWP unit test for ObjectReference.InvokeCommand command with a thread suspension.
+ */
+public class InvokeMethodWithSuspensionTest extends JDWPInvokeMethodWithSuspensionTestCase {
+    public void testInvokeWithMultipleEvents001() {
+        runInvokeMethodTest(InvokeMethodWithSuspensionDebuggee.INSTANCE_METHOD_NAME);
+    }
+
+    @Override
+    protected CommandPacket buildInvokeCommand(long threadId, long classID,
+            long methodId, int invoke_options) {
+        // We must first find the 'this' object of the top frame.
+        ReplyPacket replyPacket = debuggeeWrapper.vmMirror.getThreadFrames(threadId, 0, 1);
+        int framesCount = replyPacket.getNextValueAsInt();
+        assertEquals("Invalid frame count:", 1, framesCount);
+        long topFrameId = replyPacket.getNextValueAsFrameID();
+        replyPacket.getNextValueAsLocation();  // consume 'location'
+        assertAllDataRead(replyPacket);
+
+        long receiverId = debuggeeWrapper.vmMirror.getThisObject(threadId, topFrameId);
+
+        CommandPacket command = new CommandPacket(
+                JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
+                JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand);
+        command.setNextValueAsThreadID(receiverId);
+        command.setNextValueAsThreadID(threadId);
+        command.setNextValueAsClassID(classID);
+        command.setNextValueAsMethodID(methodId);
+        command.setNextValueAsInt(0);
+        command.setNextValueAsInt(invoke_options);
+        return command;
+    }
+
+    @Override
+    protected String getInvokeCommandName() {
+        return "ObjectReference.InvokeCommand";
+    }
+
+    @Override
+    protected void checkInvokeReply(ReplyPacket reply) {
+        // Check result is 'void'
+        Value invokeResult = reply.getNextValueAsValue();
+        assertNull("Expect null result value for 'void'", invokeResult);
+
+        // Check exception is null.
+        TaggedObject invokeException = reply.getNextValueAsTaggedObject();
+        assertEquals("Invalid exception object id", 0, invokeException.objectID);
+        assertAllDataRead(reply);
+
+    }
+
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeDebuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeDebuggee.java
new file mode 100644
index 0000000..7acc3a5
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeDebuggee.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;
+
+import org.apache.harmony.jpda.tests.framework.TestErrorException;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.SyncDebuggee;
+
+/**
+ * Debuggee for {@link DisposeDuringInvokeTest}.
+ */
+public class DisposeDuringInvokeDebuggee extends SyncDebuggee {
+    public static final String INVOKED_METHOD_NAME = "invokeMethodWithSynchronization";
+    public static final String BREAKPOINT_METHOD_NAME = "breakpointMethod";
+    public static final String THIS_FIELD_NAME = "thisObject";
+
+    // This field holds the receiver to invoke the invokeMethodWithSynchronization method.
+    public static DisposeDuringInvokeDebuggee thisObject;
+
+    private class DebuggeeThread extends Thread {
+        public DebuggeeThread() {
+            super("DebuggeeThread");
+        }
+
+        public void run() {
+            breakpointMethod();
+        }
+    }
+
+    /**
+     * The method used to suspend the DebuggeeThread on a breakpoint.
+     */
+    private void breakpointMethod() {
+    }
+
+    /**
+     * The method called by the DebuggeeThread through JDWP.
+     */
+    private void invokeMethodWithSynchronization() {
+        logWriter.println("#START invokeMethodWithSynchronization");
+
+        // Tell the test we are invoking the requested method.
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Wait for the test to send a VirtualMachine.Dispose command and resume us.
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        logWriter.println("#END invokeMethodWithSynchronization");
+    }
+
+    @Override
+    public void run() {
+        thisObject = this;
+
+        DebuggeeThread thrd = new DebuggeeThread();
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        logWriter.println("Start DebuggeeThread");
+        thrd.start();
+
+        logWriter.println("Main thread waits for DebuggeeThread ...");
+        try {
+            thrd.join();
+        } catch (InterruptedException e) {
+           throw new TestErrorException(e);
+        }
+        logWriter.println("DebuggeeThread is finished");
+
+        // Tell the test we successfully waited for the end of DebuggeeThread.
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Wait for the test to resume us.
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+    }
+
+    public static void main(String [] args) {
+        runDebuggee(DisposeDuringInvokeDebuggee.class);
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeTest.java
new file mode 100644
index 0000000..7046d4e
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/VirtualMachine/DisposeDuringInvokeTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;
+
+import org.apache.harmony.jpda.tests.framework.TestErrorException;
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.Value;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+
+import java.io.IOException;
+
+/**
+ * JDWP Unit test for VirtualMachine.Dispose command while a thread is invoking a method.
+ */
+public class DisposeDuringInvokeTest extends JDWPSyncTestCase {
+
+    @Override
+    protected String getDebuggeeClassName() {
+        return DisposeDuringInvokeDebuggee.class.getName();
+    }
+
+    /**
+     * This testcase exercises VirtualMachine.Dispose command when a thread, suspended by an
+     * event, is still invoking a method.
+     * <BR>At first the test starts DisposeDuringInvokeDebuggee debuggee.
+     * <BR>Then the test sets a breakpoint so that the tested thread (DebuggeeThread) gets suspended
+     * by an event. Once this thread is suspended, we send it an ObjectReference.InvokeMethod
+     * command to initiate a method invocation executing in that thread. The method will synchronize
+     * with the test, waiting for a signal to continue its execution.
+     * <BR>While the tested thread waits for the signal, we send a VirtualMachine.Dispose command to
+     * the debuggee and sends the expected signal so the tested thread completes the method
+     * invocation.
+     * <BR>Finally, we wait for the debuggee's main thread to signal us when the tested thread has
+     * normally terminated after we dispose the JDWP connection.
+     */
+    public void testDisposeDuringInvoke() {
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Set breakpoint so the DebuggeeThread suspends itself only.
+        long classID = getClassIDBySignature(getDebuggeeClassSignature());
+        long invokedMethodId = getMethodID(classID,
+                DisposeDuringInvokeDebuggee.INVOKED_METHOD_NAME);
+        int breakpointID = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
+                DisposeDuringInvokeDebuggee.BREAKPOINT_METHOD_NAME,
+                JDWPConstants.SuspendPolicy.EVENT_THREAD);
+        long thisObjectId = getReceiverObjectId(classID);
+
+        // Continue debuggee.
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        // Wait for the DebuggeeThread to suspend on the breakpoint.
+        long threadID = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointID);
+
+        // Send ObjectReference.InvokeMethod command.
+        CommandPacket command = new CommandPacket(
+                JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
+                JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand);
+        command.setNextValueAsThreadID(thisObjectId);
+        command.setNextValueAsThreadID(threadID);
+        command.setNextValueAsClassID(classID);
+        command.setNextValueAsMethodID(invokedMethodId);
+        command.setNextValueAsInt(0);
+        command.setNextValueAsInt(0);
+        try {
+            debuggeeWrapper.vmMirror.sendCommand(command);
+        } catch (IOException e) {
+            throw new TestErrorException("Failed to send ObjectReference.InvokeMethod command", e);
+        }
+
+        // Wait for the DebuggeeThread to start method invocation.
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Detach from debuggee with a VirtualMachine.Dispose command.
+        debuggeeWrapper.vmMirror.dispose();
+
+        // Signal DebuggeeThread to continue so it completes method invocation.
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        // Wait for the DebuggeeThread to terminate. The debuggee's main thread waits for it
+        // (using Thread.join) before signaling us.
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // The test is a success: resume the debuggee to finish
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+    }
+
+    /**
+     * Returns the object ID of the debuggee object to issue the ObjectReference.InvokeMethod
+     * command.
+     *
+     * @param classID
+     *          the debuggee class ID.
+     * @return the object ID of the debuggee
+     */
+    private long getReceiverObjectId(long classID) {
+        long thisObjectFieldID = checkField(classID, DisposeDuringInvokeDebuggee.THIS_FIELD_NAME);
+        Value thisObjectValue =
+                debuggeeWrapper.vmMirror.getReferenceTypeValue(classID, thisObjectFieldID);
+        assertEquals("Invalid value tag:", JDWPConstants.Tag.OBJECT_TAG, thisObjectValue.getTag());
+        return thisObjectValue.getLongValue();
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPInvokeMethodWithSuspensionTestCase.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPInvokeMethodWithSuspensionTestCase.java
new file mode 100644
index 0000000..cbb0107
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPInvokeMethodWithSuspensionTestCase.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.share;
+
+import org.apache.harmony.jpda.tests.framework.TestErrorException;
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.jdwp.share.debuggee.InvokeMethodWithSuspensionDebuggee;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+
+import java.io.IOException;
+
+/**
+ * Base class for tests checking invoke command with thread suspension.
+ */
+public abstract class JDWPInvokeMethodWithSuspensionTestCase extends JDWPSyncTestCase {
+
+    @Override
+    protected final String getDebuggeeClassName() {
+        return InvokeMethodWithSuspensionDebuggee.class.getName();
+    }
+
+    /**
+     * This methods runs the {@link InvokeMethodWithSuspensionDebuggee} then sets up the
+     * following breakpoints:
+     * - breakpoint #1 to suspend the current thread only when the debuggee starts
+     * - breakpoint #2 to suspend all threads from a new thread started by a method called through
+     * JDWP.
+     * When we receive the event for breakpoint #1, we issue a request to invoke a method (or a
+     * constructor) in the event thread (suspended on the breakpoint). The event thread starts
+     * another child thread and loops as long as the child is running. However, we do not read the
+     * reply of the invoke yet.
+     * Next, we wait for the new thread to hit breakpoint #2. We resume all threads in the debuggee
+     * and read the reply of the invoke.
+     * Finally, we resume the thread that completed the invoke.
+     *
+     * @param invokedMethodName
+     *          the name of the method to invoke
+     */
+    protected void runInvokeMethodTest(String invokedMethodName) {
+        // Wait for debuggee to start.
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        long classID = getClassIDBySignature(getDebuggeeClassSignature());
+        long invokeMethodID = getMethodID(classID, invokedMethodName);
+
+        // Set breakpoint with EVENT_THREAD suspend policy so only the event thread is suspended.
+        // We will invoke the method in this thread.
+        int breakpointEventThread = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
+                InvokeMethodWithSuspensionDebuggee.BREAKPOINT_EVENT_THREAD_METHOD_NAME,
+                JDWPConstants.SuspendPolicy.EVENT_THREAD);
+
+        // Set breakpoint with ALL suspend policy to suspend all threads. The thread started
+        // during the invoke will suspend all threads, including the thread executing the invoke.
+        int breakpointAllThreads = debuggeeWrapper.vmMirror.setBreakpointAtMethodBegin(classID,
+                InvokeMethodWithSuspensionDebuggee.BREAKPOINT_ALL_THREADS_METHOD_NAME,
+                JDWPConstants.SuspendPolicy.ALL);
+
+        // Tell the debuggee to continue.
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        // Wait for breakpoint and get id of suspended thread.
+        long eventThreadOne = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointEventThread);
+        int suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
+        assertEquals("Invalid suspend count:", 1, suspendCount);
+
+        // Send command but does not read reply now. That invoked method starts another thread
+        // that is going to hit a breakpoint and suspend all threads, including the thread invoking
+        // the method. The invoke can only complete when that new thread terminates, which requires
+        // we send a VirtualMachine.Resume command.
+        final int invoke_options = 0;  // resume/suspend all threads before/after the invoke.
+        CommandPacket invokeMethodCommand = buildInvokeCommand(eventThreadOne, classID,
+                invokeMethodID, invoke_options);
+
+        String commandName = getInvokeCommandName();
+        logWriter.println("Send " + commandName);
+        int invokeMethodCommandID = -1;
+        try {
+            invokeMethodCommandID = debuggeeWrapper.vmMirror.sendCommand(invokeMethodCommand);
+        } catch (IOException e) {
+            logWriter.printError("Failed to send " + commandName, e);
+            fail();
+        }
+
+        // Wait for 2nd breakpoint to hit.
+        long eventThreadTwo = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointAllThreads);
+        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadTwo);
+        assertEquals("Invalid suspend count:", 1, suspendCount);
+
+        // At this point, the event thread #1 must have been suspended by event thread #2. Since
+        // the invoke has resumed it too, its suspend count must remain 1.
+        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
+        assertEquals("Invalid suspend count:", 1, suspendCount);
+
+        // Test that sending another invoke command in the same thread returns an error.
+        CommandPacket anotherInvokeMethodCommand = buildInvokeCommand(eventThreadOne, classID,
+                invokeMethodID, invoke_options);
+        ReplyPacket anotherInvokeMethodReply =
+                debuggeeWrapper.vmMirror.performCommand(anotherInvokeMethodCommand);
+        // The RI returns INVALID_THREAD error while ART returns ALREADY_INVOKING error which is
+        // more accurate. We only test we get an error so we can run the test with both runtimes.
+        assertTrue("Expected an error",
+                anotherInvokeMethodReply.getErrorCode() != JDWPConstants.Error.NONE);
+
+        // Send a VirtualMachine.Resume to resume all threads. This will unblock the event thread
+        // with the invoke in-progress.
+        logWriter.println("Resume all threads");
+        resumeDebuggee();
+
+        // Now we can read the invoke reply.
+        ReplyPacket invokeMethodReply = null;
+        try {
+            logWriter.println("Receiving reply for command " + invokeMethodCommandID + " ...");
+            invokeMethodReply = debuggeeWrapper.vmMirror.receiveReply(invokeMethodCommandID);
+        } catch (Exception e) {
+            throw new TestErrorException("Did not receive invoke reply", e);
+        }
+        checkReplyPacket(invokeMethodReply, commandName + " command");
+        logWriter.println("Received reply for command " + invokeMethodCommandID + " OK");
+
+        checkInvokeReply(invokeMethodReply);
+
+        // The invoke is complete but the thread is still suspended: let's resume it now.
+        suspendCount = debuggeeWrapper.vmMirror.getThreadSuspendCount(eventThreadOne);
+        assertEquals("Invalid suspend count:", 1, suspendCount);
+
+        logWriter.println("Resume event thread #1");
+        debuggeeWrapper.vmMirror.resumeThread(eventThreadOne);
+    }
+
+    /**
+     * Builds the packed for the tested JDWP command.
+     *
+     * @param threadId
+     *          the id of the thread that will invoke the method
+     * @param classID
+     *          the class ID of the invoked method
+     * @param methodId
+     *          the ID of the invoke method
+     * @param invokeOptions
+     *          options for the invoke
+     * @return a command
+     */
+    protected abstract CommandPacket buildInvokeCommand(long threadId, long classID,
+                                                        long methodId, int invokeOptions);
+
+    /**
+     * Returns the name of the command returned by {@link #buildInvokeCommand} for printing.
+     *
+     * @return the name of the invoke command sent to the debuggee
+     */
+    protected abstract String getInvokeCommandName();
+
+    /**
+     * Checks the reply for the tested JDWP command.
+     *
+     * @param reply the reply of the invoke
+     */
+    protected abstract void checkInvokeReply(ReplyPacket reply);
+
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/debuggee/InvokeMethodWithSuspensionDebuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/debuggee/InvokeMethodWithSuspensionDebuggee.java
new file mode 100644
index 0000000..ce7327c
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/debuggee/InvokeMethodWithSuspensionDebuggee.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.jpda.tests.jdwp.share.debuggee;
+
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPInvokeMethodWithSuspensionTestCase;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.SyncDebuggee;
+
+/**
+ * Debuggee for subclasses of {@link JDWPInvokeMethodWithSuspensionTestCase}.
+ */
+public class InvokeMethodWithSuspensionDebuggee extends SyncDebuggee {
+    // Information for the test.
+    public static final String STATIC_METHOD_NAME = "invokedStaticMethod";
+    public static final String INSTANCE_METHOD_NAME = "invokedInstanceMethod";
+    public static final String BREAKPOINT_EVENT_THREAD_METHOD_NAME = "breakpointEventThread";
+    public static final String BREAKPOINT_ALL_THREADS_METHOD_NAME = "breakpointAllThreads";
+
+    private static volatile boolean testThreadFinished = false;
+    private static Thread testThread = null;
+    private static boolean enableThreadSuspensionForTesting = false;
+
+    private class TestThread extends Thread {
+        public TestThread() {
+            super("TestThread");
+        }
+
+        @Override
+        public void run() {
+            logWriter.println("TestThread starts");
+
+            // We're going to suspend all threads in the method below.
+            logWriter.println("Breakpoint for event thread #2");
+            breakpointAllThreads();
+
+            // The test needs to resume us so the invoke in progress in event thread #1 can
+            // complete.
+            testThreadFinished = true;
+
+            logWriter.println("TestThread ends");
+        }
+    }
+
+    // Invoked to suspend main thread (event thread #1) on a breakpoint.
+    public void breakpointEventThread() {
+    }
+
+    // Invoked to suspend test thread (event thread #2) and all others threads on a breakpoint.
+    public void breakpointAllThreads() {
+    }
+
+    // Invoked in event thread #1. This will unblock event thread #2 that will suspend all threads
+    // including event thread #1. This helps us check that the debugger is not blocked waiting for
+    // this invoke.
+    private static void causeEventThreadSuspension() {
+        if (enableThreadSuspensionForTesting) {
+            // Start event thread #2. It's going to hit a breakpoint and suspend us.
+            testThread.start();
+
+            // We don't use wait/notify pattern to be sure our loop is active.
+            while (!testThreadFinished) {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    // Static method to test ClassType.InvokeMethod.
+    public static void invokedStaticMethod() {
+        causeEventThreadSuspension();
+    }
+
+    // Constructor to test ClassType.NewInstance.
+    public InvokeMethodWithSuspensionDebuggee() {
+        causeEventThreadSuspension();
+    }
+
+    // Instance method to test ObjectReference.InvokeMethod.
+    public void invokedInstanceMethod() {
+        causeEventThreadSuspension();
+    }
+
+    @Override
+    public void run() {
+        logWriter.println("InvokeMethodWithThreadSuspensionDebuggee starts");
+
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Create test thread but do not start it now. It will be started by the invoke from
+        // the test through JDWP.
+        testThread = new TestThread();
+
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        enableThreadSuspensionForTesting = true;
+
+        // We want to suspend the main thread on a breakpoint.
+        logWriter.println("Breakpoint for event thread #1");
+        breakpointEventThread();
+
+        // Ensure tested thread is finished.
+        try {
+            testThread.join();
+        } catch (InterruptedException e) {
+            logWriter.printError("Failed to join tested thread", e);
+        }
+        testThread = null;
+
+        logWriter.println("InvokeMethodWithThreadSuspensionDebuggee ends");
+    }
+
+    public static void main(String[] args) {
+        runDebuggee(InvokeMethodWithSuspensionDebuggee.class);
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java
index 3936605..e38b3d0 100644
--- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java
@@ -62,9 +62,11 @@
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassObjectReference.ReflectedTypeTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethod002Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethod003Test.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodWithSuspensionTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstance002Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceTest.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceWithSuspensionTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.SetValues002Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.SetValuesTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.SuperClassTest.class);
@@ -125,6 +127,7 @@
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethod002Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethod003Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethodTest.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethodWithSuspensionTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.MonitorInfoTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.ReferenceTypeTest.class);
@@ -198,6 +201,7 @@
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ClassesBySignatureTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ClassPathsTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CreateStringTest.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.DisposeDuringInvokeTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.DisposeTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.DisposeObjectsTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ExitTest.class);