Implement field getting and setting.

This lets you use "dump" and "set <object>.<field> = <value>".

Change-Id: I47aee563b26e04f4931ac1cf3de2cd2e38db35a7
diff --git a/src/debugger.cc b/src/debugger.cc
index 49a7c5e..613e27e 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -475,9 +475,9 @@
   return 0;
 }
 
-bool Dbg::IsInterface(JDWP::RefTypeId id) {
-  UNIMPLEMENTED(FATAL);
-  return false;
+bool Dbg::IsInterface(JDWP::RefTypeId classId) {
+  Class* c = gRegistry->Get<Class*>(classId);
+  return c->IsInterface();
 }
 
 void Dbg::GetClassList(uint32_t* pClassCount, JDWP::RefTypeId** pClasses) {
@@ -581,7 +581,7 @@
   return TagFromObject(o);
 }
 
-size_t Dbg::GetTagWidth(int tag) {
+size_t Dbg::GetTagWidth(JDWP::JdwpTag tag) {
   switch (tag) {
   case JDWP::JT_VOID:
     return 0;
@@ -748,6 +748,14 @@
 #endif
 }
 
+Field* FromFieldId(JDWP::FieldId fid) {
+#ifdef MOVING_GARBAGE_COLLECTOR
+  UNIMPLEMENTED(FATAL);
+#else
+  return reinterpret_cast<Field*>(static_cast<uintptr_t>(fid));
+#endif
+}
+
 Method* FromMethodId(JDWP::MethodId mid) {
 #ifdef MOVING_GARBAGE_COLLECTOR
   UNIMPLEMENTED(FATAL);
@@ -958,22 +966,55 @@
   JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
 }
 
-uint8_t Dbg::GetFieldBasicTag(JDWP::ObjectId objId, JDWP::FieldId fieldId) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+JDWP::JdwpTag Dbg::GetFieldBasicTag(JDWP::FieldId fieldId) {
+  return BasicTagFromDescriptor(FromFieldId(fieldId)->GetTypeDescriptor());
 }
 
-uint8_t Dbg::GetStaticFieldBasicTag(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+JDWP::JdwpTag Dbg::GetStaticFieldBasicTag(JDWP::FieldId fieldId) {
+  return BasicTagFromDescriptor(FromFieldId(fieldId)->GetTypeDescriptor());
 }
 
 void Dbg::GetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
-  UNIMPLEMENTED(FATAL);
+  Object* o = gRegistry->Get<Object*>(objectId);
+  Field* f = FromFieldId(fieldId);
+
+  JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor());
+
+  if (IsPrimitiveTag(tag)) {
+    expandBufAdd1(pReply, tag);
+    if (tag == JDWP::JT_BOOLEAN || tag == JDWP::JT_BYTE) {
+      expandBufAdd1(pReply, f->Get32(o));
+    } else if (tag == JDWP::JT_CHAR || tag == JDWP::JT_SHORT) {
+      expandBufAdd2BE(pReply, f->Get32(o));
+    } else if (tag == JDWP::JT_FLOAT || tag == JDWP::JT_INT) {
+      expandBufAdd4BE(pReply, f->Get32(o));
+    } else if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) {
+      expandBufAdd8BE(pReply, f->Get64(o));
+    } else {
+      LOG(FATAL) << "unknown tag: " << tag;
+    }
+  } else {
+    Object* value = f->GetObject(o);
+    expandBufAdd1(pReply, TagFromObject(value));
+    expandBufAddObjectId(pReply, gRegistry->Add(value));
+  }
 }
 
 void Dbg::SetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, uint64_t value, int width) {
-  UNIMPLEMENTED(FATAL);
+  Object* o = gRegistry->Get<Object*>(objectId);
+  Field* f = FromFieldId(fieldId);
+
+  JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor());
+
+  if (IsPrimitiveTag(tag)) {
+    if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) {
+      f->Set64(o, value);
+    } else {
+      f->Set32(o, value);
+    }
+  } else {
+    f->SetObject(o, gRegistry->Get<Object*>(value));
+  }
 }
 
 void Dbg::GetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
@@ -1376,7 +1417,7 @@
   UNIMPLEMENTED(FATAL);
 }
 
-JDWP::JdwpError Dbg::InvokeMethod(JDWP::ObjectId threadId, JDWP::ObjectId objectId, JDWP::RefTypeId classId, JDWP::MethodId methodId, uint32_t numArgs, uint64_t* argArray, uint32_t options, uint8_t* pResultTag, uint64_t* pResultValue, JDWP::ObjectId* pExceptObj) {
+JDWP::JdwpError Dbg::InvokeMethod(JDWP::ObjectId threadId, JDWP::ObjectId objectId, JDWP::RefTypeId classId, JDWP::MethodId methodId, uint32_t numArgs, uint64_t* argArray, uint32_t options, JDWP::JdwpTag* pResultTag, uint64_t* pResultValue, JDWP::ObjectId* pExceptObj) {
   UNIMPLEMENTED(FATAL);
   return JDWP::ERR_NONE;
 }
diff --git a/src/debugger.h b/src/debugger.h
index ec20458..8cbfeea 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -141,7 +141,7 @@
   static bool GetSourceFile(JDWP::RefTypeId refTypeId, std::string& source_file);
   static const char* GetObjectTypeName(JDWP::ObjectId objectId);
   static uint8_t GetObjectTag(JDWP::ObjectId objectId);
-  static size_t GetTagWidth(int tag);
+  static size_t GetTagWidth(JDWP::JdwpTag tag);
 
   static int GetArrayLength(JDWP::ObjectId arrayId);
   static uint8_t GetArrayElementTag(JDWP::ObjectId arrayId);
@@ -164,8 +164,8 @@
   static void OutputLineTable(JDWP::RefTypeId refTypeId, JDWP::MethodId methodId, JDWP::ExpandBuf* pReply);
   static void OutputVariableTable(JDWP::RefTypeId refTypeId, JDWP::MethodId id, bool withGeneric, JDWP::ExpandBuf* pReply);
 
-  static uint8_t GetFieldBasicTag(JDWP::ObjectId objId, JDWP::FieldId fieldId);
-  static uint8_t GetStaticFieldBasicTag(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId);
+  static JDWP::JdwpTag GetFieldBasicTag(JDWP::FieldId fieldId);
+  static JDWP::JdwpTag GetStaticFieldBasicTag(JDWP::FieldId fieldId);
   static void GetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
   static void SetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, uint64_t value, int width);
   static void GetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
@@ -224,7 +224,7 @@
   static bool ConfigureStep(JDWP::ObjectId threadId, JDWP::JdwpStepSize size, JDWP::JdwpStepDepth depth);
   static void UnconfigureStep(JDWP::ObjectId threadId);
 
-  static JDWP::JdwpError InvokeMethod(JDWP::ObjectId threadId, JDWP::ObjectId objectId, JDWP::RefTypeId classId, JDWP::MethodId methodId, uint32_t numArgs, uint64_t* argArray, uint32_t options, uint8_t* pResultTag, uint64_t* pResultValue, JDWP::ObjectId* pExceptObj);
+  static JDWP::JdwpError InvokeMethod(JDWP::ObjectId threadId, JDWP::ObjectId objectId, JDWP::RefTypeId classId, JDWP::MethodId methodId, uint32_t numArgs, uint64_t* argArray, uint32_t options, JDWP::JdwpTag* pResultTag, uint64_t* pResultValue, JDWP::ObjectId* pExceptObj);
   static void ExecuteMethod(DebugInvokeReq* pReq);
 
   /* perform "late registration" of an object ID */
diff --git a/src/jdwp/jdwp.h b/src/jdwp/jdwp.h
index 1b766bd..f138880 100644
--- a/src/jdwp/jdwp.h
+++ b/src/jdwp/jdwp.h
@@ -55,6 +55,7 @@
 static inline ObjectId ReadObjectId(const uint8_t** pBuf) { return Read8BE(pBuf); }
 static inline RefTypeId ReadRefTypeId(const uint8_t** pBuf) { return Read8BE(pBuf); }
 static inline FrameId ReadFrameId(const uint8_t** pBuf) { return Read8BE(pBuf); }
+static inline JdwpTag ReadTag(const uint8_t** pBuf) { return static_cast<JdwpTag>(Read1(pBuf)); }
 static inline void SetFieldId(uint8_t* buf, FieldId val) { return Set4BE(buf, val); }
 static inline void SetMethodId(uint8_t* buf, MethodId val) { return Set4BE(buf, val); }
 static inline void SetObjectId(uint8_t* buf, ObjectId val) { return Set8BE(buf, val); }
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index c0a44e0..65b645d 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -118,7 +118,7 @@
   }
 
   for (uint32_t i = 0; i < numArgs; i++) {
-    uint8_t typeTag = Read1(&buf);
+    JDWP::JdwpTag typeTag = ReadTag(&buf);
     size_t width = Dbg::GetTagWidth(typeTag);
     uint64_t value = jdwpReadValue(&buf, width);
 
@@ -129,7 +129,7 @@
   uint32_t options = Read4BE(&buf);  /* enum InvokeOptions bit flags */
   LOG(VERBOSE) << StringPrintf("        options=0x%04x%s%s", options, (options & INVOKE_SINGLE_THREADED) ? " (SINGLE_THREADED)" : "", (options & INVOKE_NONVIRTUAL) ? " (NONVIRTUAL)" : "");
 
-  uint8_t resultTag;
+  JDWP::JdwpTag resultTag;
   uint64_t resultValue;
   ObjectId exceptObjId;
   JdwpError err = Dbg::InvokeMethod(threadId, objectId, classId, methodId, numArgs, argArray, options, &resultTag, &resultValue, &exceptObjId);
@@ -657,7 +657,7 @@
 
   for (uint32_t i = 0; i < values; i++) {
     FieldId fieldId = ReadFieldId(&buf);
-    uint8_t fieldTag = Dbg::GetStaticFieldBasicTag(classId, fieldId);
+    JDWP::JdwpTag fieldTag = Dbg::GetStaticFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
     uint64_t value = jdwpReadValue(&buf, width);
 
@@ -805,7 +805,7 @@
   for (uint32_t i = 0; i < numFields; i++) {
     FieldId fieldId = ReadFieldId(&buf);
 
-    uint8_t fieldTag = Dbg::GetFieldBasicTag(objectId, fieldId);
+    JDWP::JdwpTag fieldTag = Dbg::GetFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
     uint64_t value = jdwpReadValue(&buf, width);
 
@@ -1443,7 +1443,7 @@
   expandBufAdd4BE(pReply, slots);     /* "int values" */
   for (uint32_t i = 0; i < slots; i++) {
     uint32_t slot = Read4BE(&buf);
-    JDWP::JdwpTag reqSigByte = static_cast<JDWP::JdwpTag>(Read1(&buf));
+    JDWP::JdwpTag reqSigByte = ReadTag(&buf);
 
     LOG(VERBOSE) << StringPrintf("    --> slot %d '%c'", slot, reqSigByte);
 
@@ -1467,7 +1467,7 @@
 
   for (uint32_t i = 0; i < slots; i++) {
     uint32_t slot = Read4BE(&buf);
-    JDWP::JdwpTag sigByte = static_cast<JDWP::JdwpTag>(Read1(&buf));
+    JDWP::JdwpTag sigByte = ReadTag(&buf);
     size_t width = Dbg::GetTagWidth(sigByte);
     uint64_t value = jdwpReadValue(&buf, width);