Merge "JDWP Tests: add breakpoint tests for framework code"
diff --git a/jdwp/Android.mk b/jdwp/Android.mk
index 00449da..8a5bce4 100644
--- a/jdwp/Android.mk
+++ b/jdwp/Android.mk
@@ -36,6 +36,7 @@
 LOCAL_NO_EMMA_COMPILE := true
 LOCAL_CTS_TEST_PACKAGE := android.jdwp
 LOCAL_CTS_TARGET_RUNTIME_ARGS := $(cts_jdwp_test_target_runtime_args)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 include $(BUILD_CTS_TARGET_JAVA_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -46,6 +47,7 @@
 LOCAL_NO_EMMA_INSTRUMENT := true
 LOCAL_NO_EMMA_COMPILE := true
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/jdwp
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 include $(BUILD_JAVA_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/JDWPCommands.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/JDWPCommands.java
index f2d5c25..14aa8d9 100644
--- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/JDWPCommands.java
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/jdwp/JDWPCommands.java
@@ -157,6 +157,8 @@
      */
     public class InterfaceTypeCommandSet {
         public static final byte CommandSetID = 5;
+
+        public static final byte InvokeMethodCommand = 1;
     }
 
     /**
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodDebuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodDebuggee.java
new file mode 100644
index 0000000..2e9f401
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodDebuggee.java
@@ -0,0 +1,48 @@
+/*
+ * 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.InterfaceType;
+
+import org.apache.harmony.jpda.tests.framework.LogWriter;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.JPDATestOptions;
+import org.apache.harmony.jpda.tests.share.SyncDebuggee;
+
+/**
+ * Used for InterfaceType.InvokeMethodTest.testInvokeMethodStatic
+ */
+public class InvokeMethodDebuggee extends SyncDebuggee implements InvokeMethodTestInterface {
+
+    void execMethod() {
+        logWriter.println("InvokeMethodDebuggee.execMethod()");
+    }
+
+    @Override
+    public void run() {
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+        logWriter.println("InvokeMethodDebuggee");
+        synchronizer.receiveMessageWithoutException(
+            "org.apache.harmony.jpda.tests.jdwp.InterfaceType.InvokeMethodDebuggee(#1)");
+        execMethod();
+        synchronizer.receiveMessageWithoutException(
+            "org.apache.harmony.jpda.tests.jdwp.InterfaceType.InvokeMethodDebuggee(#2)");
+    }
+    public static void main(String[] args) {
+        runDebuggee(InvokeMethodDebuggee.class);
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTest.java
new file mode 100644
index 0000000..1301748
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.InterfaceType;
+
+import org.apache.harmony.jpda.tests.framework.LogWriter;
+import org.apache.harmony.jpda.tests.framework.jdwp.*;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
+import org.apache.harmony.jpda.tests.jdwp.share.debuggee.*;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.JPDATestOptions;
+
+/**
+ * JDWP unit test to exercise InterfaceType.InvokeMethod command.
+ */
+public class InvokeMethodTest extends JDWPSyncTestCase {
+
+    @Override
+    protected String getDebuggeeClassName() {
+        return InvokeMethodDebuggee.class.getName();
+    }
+
+    /**
+     * This testcase exercises InterfaceType.InvokeMethod command.
+     * <BR>The test first starts the debuggee, request METHOD_ENTRY event so the
+     * application suspends on first invoke.
+     * <BR>Then sends InterfaceType.InvokeMethod command for method with null
+     * argument. Checks that returned value is expected int value and returned
+     * exception object is as expected.
+     * <BR>Finally resume the application.
+     */
+    private void testInvokeMethodStatic(boolean shouldThrow) {
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Get debuggee class ID.
+        String debuggeeClassSig = getDebuggeeClassSignature();
+        long debuggeeTypeID = debuggeeWrapper.vmMirror.getClassID(debuggeeClassSig);
+        assertTrue("Failed to find debuggee class", debuggeeTypeID != 0);
+
+        // Set METHOD_ENTRY event request so application is suspended.
+        CommandPacket packet = new CommandPacket(
+                JDWPCommands.EventRequestCommandSet.CommandSetID,
+                JDWPCommands.EventRequestCommandSet.SetCommand);
+        packet.setNextValueAsByte(JDWPConstants.EventKind.METHOD_ENTRY);
+        packet.setNextValueAsByte(JDWPConstants.SuspendPolicy.ALL);
+        packet.setNextValueAsInt(1);  // number of modifiers.
+        packet.setNextValueAsByte(EventMod.ModKind.ClassOnly);  // class-only modifier.
+        packet.setNextValueAsReferenceTypeID(debuggeeTypeID);
+        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "EventRequest::Set command");
+
+        int requestID = reply.getNextValueAsInt();
+        logWriter.println(" EventRequest.Set: requestID=" + requestID);
+        assertAllDataRead(reply);
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        long targetThreadID = 0;
+        // Wait for METHOD_ENTRY event and collect event thread.
+        CommandPacket event = debuggeeWrapper.vmMirror.receiveEvent();
+        byte suspendPolicy = event.getNextValueAsByte();
+        int events = event.getNextValueAsInt();
+        logWriter.println(" EVENT_THREAD event: suspendPolicy=" + suspendPolicy + " events=" + events);
+        for (int i = 0; i < events; i++) {
+            byte eventKind = event.getNextValueAsByte();
+            int newRequestID = event.getNextValueAsInt();
+            long threadID = event.getNextValueAsThreadID();
+            //Location location =
+                event.getNextValueAsLocation();
+            logWriter.println("  EVENT_THREAD event " + i + ": eventKind="
+                    + eventKind + " requestID=" + newRequestID + " threadID="
+                    + threadID);
+            if (newRequestID == requestID) {
+                targetThreadID = threadID;
+            }
+        }
+        assertAllDataRead(event);
+        assertTrue("Invalid targetThreadID, must be != 0", targetThreadID != 0);
+
+        //  Now we're suspended, clear event request.
+        debuggeeWrapper.vmMirror.clearEvent(JDWPConstants.EventKind.METHOD_ENTRY, requestID);
+
+        // Get test method ID.
+        String debuggeeInterfaceSig = getClassSignature(InvokeMethodTestInterface.class);
+        long debuggeeInterfaceTypeID =
+                debuggeeWrapper.vmMirror.getInterfaceID(debuggeeInterfaceSig);
+        assertTrue("Failed to find debuggee interface", debuggeeInterfaceTypeID != 0);
+        long targetMethodID = debuggeeWrapper.vmMirror.getMethodID(debuggeeInterfaceTypeID,
+                "testInvokeMethodStatic1");
+        assertTrue("Failed to find method", targetMethodID != 0);
+
+        Value throwValue = new Value(shouldThrow);
+        // Invoke test method with null argument.
+        packet = new CommandPacket(
+                JDWPCommands.InterfaceTypeCommandSet.CommandSetID,
+                JDWPCommands.InterfaceTypeCommandSet.InvokeMethodCommand);
+        packet.setNextValueAsInterfaceID(debuggeeInterfaceTypeID);
+        packet.setNextValueAsThreadID(targetThreadID);
+        packet.setNextValueAsMethodID(targetMethodID);
+        packet.setNextValueAsInt(1);  // number of arguments
+        packet.setNextValueAsValue(throwValue);
+        packet.setNextValueAsInt(0);  // invoke options
+        logWriter.println(" Send InterfaceType.InvokeMethod " +
+                ((shouldThrow) ? "with" : "without") + " exception.");
+        reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "InterfaceType::InvokeMethod command");
+
+        Value returnValue = reply.getNextValueAsValue();
+        assertNotNull("Returned value is null", returnValue);
+        if (shouldThrow) {
+            assertEquals("Invalid returned value,", 0, returnValue.getIntValue());
+            logWriter.println(" InterfaceType.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            // Check that some exception was thrown.
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertTrue("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID != 0);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" InterfaceType.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        } else {
+            assertEquals("Invalid returned value,",
+                InvokeMethodTestInterface.RETURN_VALUE, returnValue.getIntValue());
+            logWriter.println(" InterfaceType.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertEquals("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID, 0);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" InterfaceType.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        }
+
+        assertAllDataRead(reply);
+
+        //  Let's resume application suspended on the METHOD_ENTRY event.
+        debuggeeWrapper.vmMirror.resume();
+
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+    }
+
+    public void testInvokeMethodStaticWithoutThrowing() {
+        testInvokeMethodStatic(false);
+    }
+    public void testInvokeMethodStaticThrowing() {
+        testInvokeMethodStatic(true);
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTestInterface.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTestInterface.java
new file mode 100644
index 0000000..d36f0d9
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/InterfaceType/InvokeMethodTestInterface.java
@@ -0,0 +1,35 @@
+/*
+ * 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.InterfaceType;
+
+import org.apache.harmony.jpda.tests.framework.LogWriter;
+import org.apache.harmony.jpda.tests.share.JPDATestOptions;
+
+/**
+ * Used for InterfaceType.InvokeMethodTest
+ */
+public interface InvokeMethodTestInterface {
+    public static final int RETURN_VALUE = 567;
+    public static int testInvokeMethodStatic1(boolean needsThrow) throws Throwable {
+        if (needsThrow) {
+            throw new Throwable("test exception");
+        }
+        return InvokeMethodTestInterface.RETURN_VALUE;
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Debuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Debuggee.java
new file mode 100644
index 0000000..efb3dbc
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Debuggee.java
@@ -0,0 +1,88 @@
+/*
+ * 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.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.SyncDebuggee;
+
+public class InvokeMethodDefault002Debuggee extends SyncDebuggee {
+
+    /**
+     * Interface defining the default method to be invoked.
+     */
+    static interface TestInterface {
+        public static final int RETURN_VALUE = 123;
+        /**
+         * Method invoked for test
+         * @param shouldThrow throws if the value is true.
+         * @return the value 123
+         */
+        public default int testDefaultMethod(boolean shouldThrow) throws Throwable {
+            if (shouldThrow) {
+                throw new Throwable("testDefaultMethod");
+            }
+            return TestInterface.RETURN_VALUE;
+        }
+    }
+
+    /**
+     * The overriding class we will initialize to call the default method.
+     */
+    static class TestClass implements TestInterface {
+        public static final int RETURN_VALUE = 456;
+        @Override
+        public int testDefaultMethod(boolean shouldThrow) throws Throwable {
+            if (shouldThrow) {
+                throw new Throwable("testDefaultMethod");
+            }
+            return TestClass.RETURN_VALUE;
+        }
+    }
+
+    // The instance used to invoke "TestClass.testMethod".
+    static TestClass invokeReceiver = new TestClass();
+
+    void execMethod() {
+        logWriter.println("InvokeMethodDefault002Debuggee.execMethod()");
+    }
+
+    public void run() {
+        // Preload TestClass so it is available during the test.
+        Class c = null;
+        String packageName = "org.apache.harmony.jpda.tests.jdwp.";
+        try {
+            c = Class.forName(
+                    packageName + "ObjectReference.InvokeMethodDefault002Debuggee$TestClass");
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+        logWriter.println("InvokeMethodDefault002Debuggee");
+        synchronizer.receiveMessageWithoutException(
+                packageName + "ObjectReference.InvokeMethodDefault002Debuggee(#1)");
+        execMethod();
+        synchronizer.receiveMessageWithoutException(
+                packageName + "ObjectReference.InvokeMethodDefault002Debuggee(#2)");
+    }
+
+    public static void main(String[] args) {
+        runDebuggee(InvokeMethodDefault002Debuggee.class);
+    }
+}
+
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Test.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Test.java
new file mode 100644
index 0000000..7aaf026
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault002Test.java
@@ -0,0 +1,191 @@
+/*
+ * 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.*;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+
+
+/**
+ * JDWP unit test for ObjectReference.InvokeMethod command on an
+ * overridden default method.
+ */
+public class InvokeMethodDefault002Test extends JDWPSyncTestCase {
+    protected String getDebuggeeClassName() {
+        return InvokeMethodDefault002Debuggee.class.getName();
+    }
+
+    /**
+     * This testcase exercises ObjectReference.InvokeMethod command.
+     * <BR>The test first starts the debuggee, requests METHOD_ENTRY event so
+     * the application suspends on first invoke.
+     * <BR>Then sends ObjectReference.InvokeMethod command to invoke method
+     * InvokeMethodDefaultTest$TestInterface.testDefaultMethod on an instance
+     * of a subclass of Object overriding the method toString.
+     * <BR>Checks that returned value is expected string value and returned
+     * exception object is null.
+     * <BR>Finally resumes the application.
+     * @param shouldThrow If true test that we can make the function throw.
+     */
+    private void testInvokeMethod(boolean shouldThrow) {
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Get debuggee class ID.
+        String debuggeeClassSig = getDebuggeeClassSignature();
+        long debuggeeTypeID = debuggeeWrapper.vmMirror.getClassID(debuggeeClassSig);
+        assertTrue("Failed to find debuggee class", debuggeeTypeID != 0L);
+
+        // Set METHOD_ENTRY event request so application is suspended.
+        CommandPacket packet = new CommandPacket(
+                JDWPCommands.EventRequestCommandSet.CommandSetID,
+                JDWPCommands.EventRequestCommandSet.SetCommand);
+        packet.setNextValueAsByte(JDWPConstants.EventKind.METHOD_ENTRY);
+        packet.setNextValueAsByte(JDWPConstants.SuspendPolicy.ALL);
+        packet.setNextValueAsInt(1);  // number of modifiers
+        packet.setNextValueAsByte(EventMod.ModKind.ClassOnly);  // class-only modifier.
+        packet.setNextValueAsReferenceTypeID(debuggeeTypeID);
+        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "EventRequest::Set command");
+
+        int requestID = reply.getNextValueAsInt();
+        logWriter.println(" EventRequest.Set: requestID=" + requestID);
+        assertAllDataRead(reply);
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        long targetThreadID = 0;
+        // Wait for METHOD_ENTRY event and collect event thread.
+        CommandPacket event = debuggeeWrapper.vmMirror.receiveEvent();
+        byte suspendPolicy = event.getNextValueAsByte();
+        int events = event.getNextValueAsInt();
+        logWriter.println(
+                " EVENT_THREAD event: suspendPolicy=" + suspendPolicy + " events=" + events);
+        for (int i = 0; i < events; i++) {
+            byte eventKind = event.getNextValueAsByte();
+            int newRequestID = event.getNextValueAsInt();
+            long threadID = event.getNextValueAsThreadID();
+            event.getNextValueAsLocation();  // location
+            logWriter.println("  EVENT_THREAD event " + i + ": eventKind="
+                    + eventKind + " requestID=" + newRequestID + " threadID="
+                    + threadID);
+            if (newRequestID == requestID) {
+                targetThreadID = threadID;
+            }
+        }
+        assertAllDataRead(event);
+        assertTrue("Invalid targetThreadID, must be != 0", targetThreadID != 0L);
+
+        //  Now we're suspended, clear event request.
+        debuggeeWrapper.vmMirror.clearEvent(JDWPConstants.EventKind.METHOD_ENTRY, requestID);
+
+        // Load value of the invoke's receiver.
+        long receiverFieldID =
+                debuggeeWrapper.vmMirror.getFieldID(debuggeeTypeID, "invokeReceiver");
+        assertTrue("Failed to find receiver field", receiverFieldID != 0L);
+
+        logWriter.println(" Send ReferenceType.GetValues");
+        Value fieldValue = debuggeeWrapper.vmMirror.getReferenceTypeValue(debuggeeTypeID, receiverFieldID);
+        assertNotNull("Received null value", fieldValue);
+        assertEquals("Expected an object value", JDWPConstants.Tag.OBJECT_TAG, fieldValue.getTag());
+        long receiverObjectID = fieldValue.getLongValue();
+        assertTrue("Field is null", receiverObjectID != 0L);
+
+        // Get test class ID.
+        String testClassSig = getClassSignature(InvokeMethodDefault002Debuggee.TestClass.class);
+        long testTypeID = debuggeeWrapper.vmMirror.getClassID(testClassSig);
+        assertTrue("Failed to find test class", testTypeID != 0L);
+
+        // Get InvokeMethodDefaultDebuggee.TestInterface class ID.
+        long interfaceTypeID = debuggeeWrapper.vmMirror.getInterfaceID(
+                getClassSignature(InvokeMethodDefault002Debuggee.TestInterface.class));
+        assertTrue("Failed to find InvokeMethodDefault002Debuggee.TestInterface class",
+                interfaceTypeID != 0L);
+
+        // Get InvokeMethodDefaultDebuggee.TestInterface.testDefaultMethod method ID.
+        long targetMethodID =
+                debuggeeWrapper.vmMirror.getMethodID(interfaceTypeID, "testDefaultMethod");
+        assertTrue("Failed to find method", targetMethodID != 0L);
+        logWriter.println(" Method ID=" + targetMethodID);
+
+        // The method argument.
+        Value throwValue = new Value(shouldThrow);
+        // Invoke method.
+        packet = new CommandPacket(
+                JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
+                JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand);
+        packet.setNextValueAsObjectID(receiverObjectID);
+        packet.setNextValueAsThreadID(targetThreadID);
+        packet.setNextValueAsClassID(testTypeID);  // TestClass type ID.
+        packet.setNextValueAsMethodID(targetMethodID);  // testDefaultMethod method ID.
+        packet.setNextValueAsInt(1);  // 1 argument.
+        packet.setNextValueAsValue(throwValue);
+        packet.setNextValueAsInt(0);  // invoke options.
+        logWriter.println(" Send ObjectReference.InvokeMethod " +
+                ((shouldThrow) ? "with" : "without") + " exception");
+        reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "ObjectReference::InvokeMethod command");
+
+        Value returnValue = reply.getNextValueAsValue();
+        assertNotNull("Returned value is null", returnValue);
+        if (shouldThrow) {
+            assertEquals("Invalid returned value,", 0, returnValue.getIntValue());
+            logWriter.println(" ObjectReference.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            // Check that some exception was thrown.
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertTrue("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID != 0L);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" InterfaceType.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        } else {
+            assertEquals("Invalid returned value,",
+                InvokeMethodDefault002Debuggee.TestClass.RETURN_VALUE, returnValue.getIntValue());
+            logWriter.println(" ObjectReference.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertEquals("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID, 0);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" ObjectReference.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        }
+
+        //  Let's resume application
+        debuggeeWrapper.vmMirror.resume();
+
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+    }
+
+    public void testInvokeMethodFromInterfaceThrow() {
+        testInvokeMethod(true);
+    }
+
+    public void testInvokeMethodFromInterfaceNoThrow() {
+        testInvokeMethod(false);
+    }
+}
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultDebuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultDebuggee.java
new file mode 100644
index 0000000..b3b5e97
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultDebuggee.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.share.JPDADebuggeeSynchronizer;
+import org.apache.harmony.jpda.tests.share.SyncDebuggee;
+
+public class InvokeMethodDefaultDebuggee extends SyncDebuggee {
+
+    /**
+     * Interface defining the default method to be invoked.
+     */
+    public static interface TestInterface {
+        public static final int RETURN_VALUE = 123;
+        /**
+         * Method invoked for test
+         * @param shouldThrow throws if the value is true.
+         * @return the value 123
+         */
+        public default int testDefaultMethod(boolean shouldThrow) throws Throwable {
+            if (shouldThrow) {
+                throw new Throwable("testDefaultMethod");
+            }
+            return TestInterface.RETURN_VALUE;
+        }
+    }
+
+    /**
+     * The empty class we will initialize to call the default method.
+     */
+    public static class TestClass implements TestInterface {
+    }
+
+    // The instance used to invoke "TestClass.testMethod".
+    static TestClass invokeReceiver = new TestClass();
+
+    void execMethod() {
+        logWriter.println("InvokeMethodDefaultDebuggee.execMethod()");
+    }
+
+    public void run() {
+        // Preload TestClass so it is available during the test.
+        Class c = null;
+        String packageName = "org.apache.harmony.jpda.tests.jdwp.";
+        try {
+            c = Class.forName(
+                    packageName + "ObjectReference.InvokeMethodDefaultDebuggee$TestClass");
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+        logWriter.println("InvokeMethodDefaultDebuggee");
+        synchronizer.receiveMessageWithoutException(
+                packageName + "ObjectReference.InvokeMethodDefaultDebuggee(#1)");
+        execMethod();
+        synchronizer.receiveMessageWithoutException(
+                packageName + "ObjectReference.InvokeMethodDefaultDebuggee(#2)");
+    }
+
+    public static void main(String[] args) {
+        runDebuggee(InvokeMethodDefaultDebuggee.class);
+    }
+}
+
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultTest.java
new file mode 100644
index 0000000..0f2a386
--- /dev/null
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefaultTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.*;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
+import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
+
+
+/**
+ * JDWP unit test for ObjectReference.InvokeMethod command.
+ */
+public class InvokeMethodDefaultTest extends JDWPSyncTestCase {
+    protected String getDebuggeeClassName() {
+        return InvokeMethodDefaultDebuggee.class.getName();
+    }
+
+    /**
+     * This testcase exercises ObjectReference.InvokeMethod command.
+     * <BR>The test first starts the debuggee, requests METHOD_ENTRY event so
+     * the application suspends on first invoke.
+     * <BR>Then sends ObjectReference.InvokeMethod command to invoke method
+     * InvokeMethodDefaultTest$TestInterface.testDefaultMethod on an instance
+     * of a subclass of Object overriding the method toString.
+     * <BR>Checks that returned value is expected string value and returned
+     * exception object is null.
+     * <BR>Finally resumes the application.
+     * @param shouldThrow If true test that we can make the function throw.
+     */
+    private void testInvokeMethod(boolean shouldThrow) {
+        synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+        // Get debuggee class ID.
+        String debuggeeClassSig = getDebuggeeClassSignature();
+        long debuggeeTypeID = debuggeeWrapper.vmMirror.getClassID(debuggeeClassSig);
+        assertTrue("Failed to find debuggee class", debuggeeTypeID  != 0L);
+
+        // Set METHOD_ENTRY event request so application is suspended.
+        CommandPacket packet = new CommandPacket(
+                JDWPCommands.EventRequestCommandSet.CommandSetID,
+                JDWPCommands.EventRequestCommandSet.SetCommand);
+        packet.setNextValueAsByte(JDWPConstants.EventKind.METHOD_ENTRY);
+        packet.setNextValueAsByte(JDWPConstants.SuspendPolicy.ALL);
+        packet.setNextValueAsInt(1);
+        packet.setNextValueAsByte(EventMod.ModKind.ClassOnly);  // class-only modifier.
+        packet.setNextValueAsReferenceTypeID(debuggeeTypeID);
+        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "EventRequest::Set command");
+
+        int requestID = reply.getNextValueAsInt();
+        logWriter.println(" EventRequest.Set: requestID=" + requestID);
+        assertAllDataRead(reply);
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+
+        long targetThreadID = 0;
+        // Wait for METHOD_ENTRY event and collect event thread.
+        CommandPacket event = debuggeeWrapper.vmMirror.receiveEvent();
+        byte suspendPolicy = event.getNextValueAsByte();
+        int events = event.getNextValueAsInt();
+        logWriter.println(" EVENT_THREAD event: suspendPolicy=" + suspendPolicy +
+                " events=" + events);
+        for (int i = 0; i < events; i++) {
+            byte eventKind = event.getNextValueAsByte();
+            int newRequestID = event.getNextValueAsInt();
+            long threadID = event.getNextValueAsThreadID();
+            //Location location =
+            event.getNextValueAsLocation();
+            logWriter.println("  EVENT_THREAD event " + i + ": eventKind="
+                    + eventKind + " requestID=" + newRequestID + " threadID="
+                    + threadID);
+            if (newRequestID == requestID) {
+                targetThreadID = threadID;
+            }
+        }
+        assertAllDataRead(event);
+        assertTrue("Invalid targetThreadID, must be != 0", targetThreadID  != 0L);
+
+        //  Now we're suspended, clear event request.
+        debuggeeWrapper.vmMirror.clearEvent(JDWPConstants.EventKind.METHOD_ENTRY, requestID);
+
+        // Load value of the invoke's receiver.
+        long receiverFieldID =
+                debuggeeWrapper.vmMirror.getFieldID(debuggeeTypeID, "invokeReceiver");
+        assertTrue("Failed to find receiver field", receiverFieldID  != 0L);
+
+        logWriter.println(" Send ReferenceType.GetValues");
+        Value fieldValue = debuggeeWrapper.vmMirror.getReferenceTypeValue(debuggeeTypeID, receiverFieldID);
+        assertNotNull("Received null value", fieldValue);
+        assertEquals("Expected an object value", JDWPConstants.Tag.OBJECT_TAG, fieldValue.getTag());
+        long receiverObjectID = fieldValue.getLongValue();
+        assertTrue("Field is null", receiverObjectID  != 0L);
+
+        // Get test class ID.
+        String testClassSig = getClassSignature(InvokeMethodDefaultDebuggee.TestClass.class);
+        long testTypeID = debuggeeWrapper.vmMirror.getClassID(testClassSig);
+        assertTrue("Failed to find test class", testTypeID  != 0L);
+
+        // Get InvokeMethodDefualtDebuggee.TestInterface class ID.
+        long interfaceTypeID = debuggeeWrapper.vmMirror.getInterfaceID(
+                getClassSignature(InvokeMethodDefaultDebuggee.TestInterface.class));
+        assertTrue("Failed to find InvokeMethodDefaultDebuggee.TestInterface class",
+                interfaceTypeID != 0L);
+
+        // Get InvokeMethodDefualtDebuggee.TestInterface.testDefaultMethod method ID.
+        long targetMethodID =
+                debuggeeWrapper.vmMirror.getMethodID(interfaceTypeID, "testDefaultMethod");
+        assertTrue("Failed to find method", targetMethodID  != 0L);
+        logWriter.println(" Method ID=" + targetMethodID);
+
+        // The method argument.
+        Value throwValue = new Value(shouldThrow);
+        // Invoke method.
+        packet = new CommandPacket(
+                JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
+                JDWPCommands.ObjectReferenceCommandSet.InvokeMethodCommand);
+        packet.setNextValueAsObjectID(receiverObjectID);
+        packet.setNextValueAsThreadID(targetThreadID);
+        packet.setNextValueAsClassID(testTypeID);  // TestClass type ID.
+        packet.setNextValueAsMethodID(targetMethodID);  // testDefaultMethod method ID.
+        packet.setNextValueAsInt(1);  // 1 argument.
+        packet.setNextValueAsValue(throwValue);
+        packet.setNextValueAsInt(0);  // invoke options.
+        logWriter.println(" Send ObjectReference.InvokeMethod " +
+                ((shouldThrow) ? "with" : "without") + " exception");
+        reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        checkReplyPacket(reply, "ObjectReference::InvokeMethod command");
+
+        Value returnValue = reply.getNextValueAsValue();
+        assertNotNull("Returned value is null", returnValue);
+        if (shouldThrow) {
+            assertEquals("Invalid returned value,", 0, returnValue.getIntValue());
+            logWriter.println(" ObjectReference.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            // Check that some exception was thrown.
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertTrue("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID != 0L);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" InterfaceType.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        } else {
+            assertEquals("Invalid returned value,",
+                InvokeMethodDefaultDebuggee.TestInterface.RETURN_VALUE, returnValue.getIntValue());
+            logWriter.println(" ObjectReference.InvokeMethod: returnValue.getIntValue()="
+                    + returnValue.getIntValue());
+
+            TaggedObject exception = reply.getNextValueAsTaggedObject();
+            assertNotNull("Returned exception is null", exception);
+            assertEquals("Invalid exception object ID:<" + exception.objectID + ">",
+                    exception.objectID, 0);
+            assertEquals("Invalid exception tag,", JDWPConstants.Tag.OBJECT_TAG, exception.tag
+                    , JDWPConstants.Tag.getName(JDWPConstants.Tag.OBJECT_TAG)
+                    , JDWPConstants.Tag.getName(exception.tag));
+            logWriter.println(" ObjectReference.InvokeMethod: exception.tag="
+                    + exception.tag + " exception.objectID=" + exception.objectID);
+        }
+
+        //  Let's resume application
+        debuggeeWrapper.vmMirror.resume();
+
+        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+    }
+
+    public void testInvokeMethodFromInterfaceThrow() {
+        testInvokeMethod(true);
+    }
+
+    public void testInvokeMethodFromInterfaceNoThrow() {
+        testInvokeMethod(false);
+    }
+}
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 412a87b..5618247 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
@@ -114,6 +114,7 @@
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.ThreadStartTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.VMDeathTest.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.InterfaceType.InvokeMethodTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Method.BytecodesTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Method.IsObsoleteTest.class);
     suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Method.LineTableTest.class);
@@ -142,6 +143,8 @@
     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.InvokeMethodAfterMultipleThreadSuspensionTest.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethodDefault002Test.class);
+    suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ObjectReference.InvokeMethodDefaultTest.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);