Add implementation of JDWP ClassType.NewInstance

Add a handler for the ClassType.NewInstance request, and some bits of
plumbing to go with it.

For bug 2157236.
diff --git a/vm/Debugger.c b/vm/Debugger.c
index 3ea130d..3119350 100644
--- a/vm/Debugger.c
+++ b/vm/Debugger.c
@@ -1117,6 +1117,19 @@
 }
 
 /*
+ * Allocate a new object of the specified type.
+ *
+ * Add it to the registry to prevent it from being GCed.
+ */
+ObjectId dvmDbgCreateObject(RefTypeId classId)
+{
+    ClassObject* clazz = refTypeIdToClassObject(classId);
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DEFAULT);
+    dvmReleaseTrackedAlloc(newObj, NULL);
+    return objectToObjectId(newObj);
+}
+
+/*
  * Determine if "instClassId" is an instance of "classId".
  */
 bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId)
@@ -2796,9 +2809,11 @@
 
     /*
      * Translate the method through the vtable, unless we're calling a
-     * static method or the debugger wants to suppress it.
+     * direct method or the debugger wants to suppress it.
      */
-    if ((pReq->options & INVOKE_NONVIRTUAL) != 0 || pReq->obj == NULL) {
+    if ((pReq->options & INVOKE_NONVIRTUAL) != 0 || pReq->obj == NULL ||
+        dvmIsDirectMethod(pReq->method))
+    {
         meth = pReq->method;
     } else {
         meth = dvmGetVirtualizedMethod(pReq->clazz, pReq->method);
@@ -2809,8 +2824,8 @@
 
     IF_LOGV() {
         char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
-        LOGV("JDWP invoking method %s.%s %s\n",
-            meth->clazz->descriptor, meth->name, desc);
+        LOGV("JDWP invoking method %p/%p %s.%s:%s\n",
+            pReq->method, meth, meth->clazz->descriptor, meth->name, desc);
         free(desc);
     }
 
@@ -2819,8 +2834,10 @@
     pReq->exceptObj = objectToObjectId(dvmGetException(self));
     pReq->resultTag = resultTagFromSignature(meth);
     if (pReq->exceptObj != 0) {
-        LOGD("  JDWP invocation returning with exceptObj=%p\n",
-            dvmGetException(self));
+        Object* exc = dvmGetException(self);
+        LOGD("  JDWP invocation returning with exceptObj=%p (%s)\n",
+            exc, exc->clazz->descriptor);
+        //dvmLogExceptionStackTrace();
         dvmClearException(self);
         /*
          * Nothing should try to use this, but it looks like something is.
diff --git a/vm/Debugger.h b/vm/Debugger.h
index fcf07c7..b41318c 100644
--- a/vm/Debugger.h
+++ b/vm/Debugger.h
@@ -188,6 +188,7 @@
     const u1* buf);
 
 ObjectId dvmDbgCreateString(const char* str);
+ObjectId dvmDbgCreateObject(RefTypeId classId);
 
 bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId);
 
diff --git a/vm/jdwp/JdwpHandler.c b/vm/jdwp/JdwpHandler.c
index ff6ecf4..16d9a5d 100644
--- a/vm/jdwp/JdwpHandler.c
+++ b/vm/jdwp/JdwpHandler.c
@@ -110,10 +110,14 @@
 
 /*
  * Common code for *_InvokeMethod requests.
+ *
+ * If "isConstructor" is set, this returns "objectId" rather than the
+ * expected-to-be-void return value of the called function.
  */
 static JdwpError finishInvoke(JdwpState* state,
     const u1* buf, int dataLen, ExpandBuf* pReply,
-    ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId)
+    ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId,
+    bool isConstructor)
 {
     JdwpError err = ERR_NONE;
     u8* argArray = NULL;
@@ -121,6 +125,8 @@
     u4 options;     /* enum InvokeOptions bit flags */
     int i;
 
+    assert(!isConstructor || objectId != 0);
+
     numArgs = read4BE(&buf);
 
     LOGV("    --> threadId=%llx objectId=%llx\n", threadId, objectId);
@@ -163,11 +169,16 @@
         goto bail;
 
     if (err == ERR_NONE) {
-        int width = dvmDbgGetTagWidth(resultTag);
+        if (isConstructor) {
+            expandBufAdd1(pReply, JT_OBJECT);
+            expandBufAddObjectId(pReply, objectId);
+        } else {
+            int width = dvmDbgGetTagWidth(resultTag);
 
-        expandBufAdd1(pReply, resultTag);
-        if (width != 0)
-            jdwpWriteValue(pReply, width, resultValue);
+            expandBufAdd1(pReply, resultTag);
+            if (width != 0)
+                jdwpWriteValue(pReply, width, resultValue);
+        }
         expandBufAdd1(pReply, JT_OBJECT);
         expandBufAddObjectId(pReply, exceptObjId);
 
@@ -400,8 +411,10 @@
     LOGV("  Req to create string '%s'\n", str);
 
     stringId = dvmDbgCreateString(str);
-    expandBufAddObjectId(pReply, stringId);
+    if (stringId == 0)
+        return ERR_OUT_OF_MEMORY;
 
+    expandBufAddObjectId(pReply, stringId);
     return ERR_NONE;
 }
 
@@ -834,7 +847,36 @@
     methodId = dvmReadMethodId(&buf);
 
     return finishInvoke(state, buf, dataLen, pReply,
-            threadId, 0, classId, methodId);
+            threadId, 0, classId, methodId, false);
+}
+
+/*
+ * Create a new object of the requested type, and invoke the specified
+ * constructor.
+ *
+ * Example: in IntelliJ, create a watch on "new String(myByteArray)" to
+ * see the contents of a byte[] as a string.
+ */
+static JdwpError handleCT_NewInstance(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId;
+    ObjectId threadId;
+    MethodId methodId;
+    ObjectId objectId;
+    u4 numArgs;
+
+    classId = dvmReadRefTypeId(&buf);
+    threadId = dvmReadObjectId(&buf);
+    methodId = dvmReadMethodId(&buf);
+
+    LOGV("Creating instance of %s\n", dvmDbgGetClassDescriptor(classId));
+    objectId = dvmDbgCreateObject(classId);
+    if (objectId == 0)
+        return ERR_OUT_OF_MEMORY;
+
+    return finishInvoke(state, buf, dataLen, pReply,
+            threadId, objectId, classId, methodId, true);
 }
 
 /*
@@ -1011,7 +1053,7 @@
     methodId = dvmReadMethodId(&buf);
 
     return finishInvoke(state, buf, dataLen, pReply,
-            threadId, objectId, classId, methodId);
+            threadId, objectId, classId, methodId, false);
 }
 
 /*
@@ -1955,7 +1997,7 @@
     { 3,    1,  handleCT_Superclass,    "ClassType.Superclass" },
     { 3,    2,  handleCT_SetValues,     "ClassType.SetValues" },
     { 3,    3,  handleCT_InvokeMethod,  "ClassType.InvokeMethod" },
-    //3,    4,  NewInstance
+    { 3,    4,  handleCT_NewInstance,   "ClassType.NewInstance" },
 
     /* ArrayType command set (4) */
     //4,    1,  NewInstance