Implement local setting.

I've also worked out how to test CreateString and CreateObject, but
not CreateArrayObject yet.

Also stop saying "cnt".

Change-Id: I26569ff6c4fa356fb91e6c22cbf8ced95094fabd
diff --git a/src/debugger.cc b/src/debugger.cc
index a858962..98d501c 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -716,13 +716,12 @@
 }
 
 JDWP::ObjectId Dbg::CreateString(const char* str) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+  return gRegistry->Add(String::AllocFromModifiedUtf8(str));
 }
 
 JDWP::ObjectId Dbg::CreateObject(JDWP::RefTypeId classId) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+  Class* c = gRegistry->Get<Class*>(classId);
+  return gRegistry->Add(c->AllocObject());
 }
 
 JDWP::ObjectId Dbg::CreateArrayObject(JDWP::RefTypeId arrayTypeId, uint32_t length) {
@@ -1295,7 +1294,7 @@
   return false;
 }
 
-void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t expectedLen) {
+void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t width) {
   Method** sp = reinterpret_cast<Method**>(frameId);
   Frame f;
   f.SetSP(sp);
@@ -1311,7 +1310,7 @@
   switch (tag) {
   case JDWP::JT_BOOLEAN:
     {
-      CHECK_EQ(expectedLen, 1U);
+      CHECK_EQ(width, 1U);
       uint32_t intVal = f.GetVReg(m, reg);
       LOG(VERBOSE) << "get boolean local " << reg << " = " << intVal;
       JDWP::Set1(buf+1, intVal != 0);
@@ -1319,7 +1318,7 @@
     break;
   case JDWP::JT_BYTE:
     {
-      CHECK_EQ(expectedLen, 1U);
+      CHECK_EQ(width, 1U);
       uint32_t intVal = f.GetVReg(m, reg);
       LOG(VERBOSE) << "get byte local " << reg << " = " << intVal;
       JDWP::Set1(buf+1, intVal);
@@ -1328,7 +1327,7 @@
   case JDWP::JT_SHORT:
   case JDWP::JT_CHAR:
     {
-      CHECK_EQ(expectedLen, 2U);
+      CHECK_EQ(width, 2U);
       uint32_t intVal = f.GetVReg(m, reg);
       LOG(VERBOSE) << "get short/char local " << reg << " = " << intVal;
       JDWP::Set2BE(buf+1, intVal);
@@ -1337,7 +1336,7 @@
   case JDWP::JT_INT:
   case JDWP::JT_FLOAT:
     {
-      CHECK_EQ(expectedLen, 4U);
+      CHECK_EQ(width, 4U);
       uint32_t intVal = f.GetVReg(m, reg);
       LOG(VERBOSE) << "get int/float local " << reg << " = " << intVal;
       JDWP::Set4BE(buf+1, intVal);
@@ -1345,7 +1344,7 @@
     break;
   case JDWP::JT_ARRAY:
     {
-      CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
+      CHECK_EQ(width, sizeof(JDWP::ObjectId));
       Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
       LOG(VERBOSE) << "get array local " << reg << " = " << o;
       if (o != NULL && !Heap::IsHeapAddress(o)) {
@@ -1356,7 +1355,7 @@
     break;
   case JDWP::JT_OBJECT:
     {
-      CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
+      CHECK_EQ(width, sizeof(JDWP::ObjectId));
       Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
       LOG(VERBOSE) << "get object local " << reg << " = " << o;
       if (o != NULL && !Heap::IsHeapAddress(o)) {
@@ -1369,7 +1368,7 @@
   case JDWP::JT_DOUBLE:
   case JDWP::JT_LONG:
     {
-      CHECK_EQ(expectedLen, 8U);
+      CHECK_EQ(width, 8U);
       uint32_t lo = f.GetVReg(m, reg);
       uint64_t hi = f.GetVReg(m, reg + 1);
       uint64_t longVal = (hi << 32) | lo;
@@ -1387,7 +1386,53 @@
 }
 
 void Dbg::SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint64_t value, size_t width) {
-  UNIMPLEMENTED(FATAL);
+  Method** sp = reinterpret_cast<Method**>(frameId);
+  Frame f;
+  f.SetSP(sp);
+  uint16_t reg = DemangleSlot(slot, f);
+  Method* m = f.GetMethod();
+
+  const VmapTable vmap_table(m->GetVmapTableRaw());
+  uint32_t vmap_offset;
+  if (vmap_table.IsInContext(reg, vmap_offset)) {
+    UNIMPLEMENTED(FATAL) << "don't know how to pull locals from callee save frames: " << vmap_offset;
+  }
+
+  switch (tag) {
+  case JDWP::JT_BOOLEAN:
+  case JDWP::JT_BYTE:
+    CHECK_EQ(width, 1U);
+    f.SetVReg(m, reg, static_cast<uint32_t>(value));
+    break;
+  case JDWP::JT_SHORT:
+  case JDWP::JT_CHAR:
+    CHECK_EQ(width, 2U);
+    f.SetVReg(m, reg, static_cast<uint32_t>(value));
+    break;
+  case JDWP::JT_INT:
+  case JDWP::JT_FLOAT:
+    CHECK_EQ(width, 4U);
+    f.SetVReg(m, reg, static_cast<uint32_t>(value));
+    break;
+  case JDWP::JT_ARRAY:
+  case JDWP::JT_OBJECT:
+  case JDWP::JT_STRING:
+    {
+      CHECK_EQ(width, sizeof(JDWP::ObjectId));
+      Object* o = gRegistry->Get<Object*>(static_cast<JDWP::ObjectId>(value));
+      f.SetVReg(m, reg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)));
+    }
+    break;
+  case JDWP::JT_DOUBLE:
+  case JDWP::JT_LONG:
+    CHECK_EQ(width, 8U);
+    f.SetVReg(m, reg, static_cast<uint32_t>(value));
+    f.SetVReg(m, reg + 1, static_cast<uint32_t>(value >> 32));
+    break;
+  default:
+    LOG(FATAL) << "unknown tag " << tag;
+    break;
+  }
 }
 
 void Dbg::PostLocationEvent(const Method* method, int pcOffset, Object* thisPtr, int eventFlags) {
@@ -1640,11 +1685,11 @@
   DdmSendChunk(type, bytes.size(), &bytes[0]);
 }
 
-void Dbg::DdmSendChunkV(uint32_t type, const struct iovec* iov, int iovcnt) {
+void Dbg::DdmSendChunkV(uint32_t type, const struct iovec* iov, int iov_count) {
   if (gJdwpState == NULL) {
     LOG(VERBOSE) << "Debugger thread not active, ignoring DDM send: " << type;
   } else {
-    gJdwpState->DdmSendChunkV(type, iov, iovcnt);
+    gJdwpState->DdmSendChunkV(type, iov, iov_count);
   }
 }
 
diff --git a/src/debugger.h b/src/debugger.h
index 3f0f7f6..826c787 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -240,7 +240,7 @@
   static void DdmDisconnected();
   static void DdmSendChunk(uint32_t type, const std::vector<uint8_t>& bytes);
   static void DdmSendChunk(uint32_t type, size_t len, const uint8_t* buf);
-  static void DdmSendChunkV(uint32_t type, const struct iovec* iov, int iovcnt);
+  static void DdmSendChunkV(uint32_t type, const struct iovec* iov, int iov_count);
 
   /*
    * Recent allocation tracking support.
diff --git a/src/jdwp/jdwp.h b/src/jdwp/jdwp.h
index f138880..b628e6c 100644
--- a/src/jdwp/jdwp.h
+++ b/src/jdwp/jdwp.h
@@ -213,7 +213,7 @@
   /*
    * Send up a chunk of DDM data.
    */
-  void DdmSendChunkV(uint32_t type, const iovec* iov, int iovcnt);
+  void DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count);
 
   /*
    * Process a request from the debugger.
diff --git a/src/jdwp/jdwp_adb.cc b/src/jdwp/jdwp_adb.cc
index 5570b53..f6b977e 100644
--- a/src/jdwp/jdwp_adb.cc
+++ b/src/jdwp/jdwp_adb.cc
@@ -670,7 +670,7 @@
  *
  * Returns "true" if it was sent successfully.
  */
-static bool sendBufferedRequest(JdwpState* state, const iovec* iov, int iovcnt) {
+static bool sendBufferedRequest(JdwpState* state, const iovec* iov, int iov_count) {
   JdwpNetState* netState = state->netState;
 
   if (netState->clientSock < 0) {
@@ -680,12 +680,11 @@
   }
 
   size_t expected = 0;
-  int i;
-  for (i = 0; i < iovcnt; i++) {
+  for (int i = 0; i < iov_count; i++) {
     expected += iov[i].iov_len;
   }
 
-  ssize_t actual = netState->writeBufferedPacket(iov, iovcnt);
+  ssize_t actual = netState->writeBufferedPacket(iov, iov_count);
   if ((size_t)actual != expected) {
     PLOG(ERROR) << "Failed sending b-req to debugger (" << actual << " of " << expected << ")";
     return false;
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index 9440066..15e1151 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -1091,19 +1091,20 @@
  * other debugger traffic, and can't suspend the VM, so we skip all of
  * the fun event token gymnastics.
  */
-void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iovcnt) {
+void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
   uint8_t header[kJDWPHeaderLen + 8];
   size_t dataLen = 0;
 
   CHECK(iov != NULL);
-  CHECK(iovcnt > 0 && iovcnt < 10);
+  CHECK_GT(iov_count, 0);
+  CHECK_LT(iov_count, 10);
 
   /*
    * "Wrap" the contents of the iovec with a JDWP/DDMS header.  We do
    * this by creating a new copy of the vector with space for the header.
    */
-  iovec wrapiov[iovcnt+1];
-  for (int i = 0; i < iovcnt; i++) {
+  iovec wrapiov[iov_count+1];
+  for (int i = 0; i < iov_count; i++) {
     wrapiov[i+1].iov_base = iov[i].iov_base;
     wrapiov[i+1].iov_len = iov[i].iov_len;
     dataLen += iov[i].iov_len;
@@ -1125,7 +1126,7 @@
    * Make sure we're in VMWAIT in case the write blocks.
    */
   int old_state = Dbg::ThreadWaiting();
-  (*transport->sendBufferedRequest)(this, wrapiov, iovcnt + 1);
+  (*transport->sendBufferedRequest)(this, wrapiov, iov_count + 1);
   Dbg::ThreadContinuing(old_state);
 }
 
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index 28ea303..07ffc52 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -53,9 +53,9 @@
 /*
  * Write a buffered packet. Grabs a mutex to assure atomicity.
  */
-ssize_t JdwpNetStateBase::writeBufferedPacket(const iovec* iov, int iovcnt) {
+ssize_t JdwpNetStateBase::writeBufferedPacket(const iovec* iov, int iov_count) {
   MutexLock mu(socket_lock_);
-  return writev(clientSock, iov, iovcnt);
+  return writev(clientSock, iov, iov_count);
 }
 
 bool JdwpState::IsConnected() {
diff --git a/src/jdwp/jdwp_priv.h b/src/jdwp/jdwp_priv.h
index 45d70f8..d2c35dd 100644
--- a/src/jdwp/jdwp_priv.h
+++ b/src/jdwp/jdwp_priv.h
@@ -62,7 +62,7 @@
   bool (*awaitingHandshake)(JdwpState* state);
   bool (*processIncoming)(JdwpState* state);
   bool (*sendRequest)(JdwpState* state, ExpandBuf* pReq);
-  bool (*sendBufferedRequest)(JdwpState* state, const iovec* iov, int iovcnt);
+  bool (*sendBufferedRequest)(JdwpState* state, const iovec* iov, int iov_count);
 };
 
 const JdwpTransport* SocketTransport();
@@ -77,7 +77,7 @@
 
   JdwpNetStateBase();
   ssize_t writePacket(ExpandBuf* pReply);
-  ssize_t writeBufferedPacket(const iovec* iov, int iovcnt);
+  ssize_t writeBufferedPacket(const iovec* iov, int iov_count);
 
 private:
   Mutex socket_lock_;
diff --git a/src/jdwp/jdwp_socket.cc b/src/jdwp/jdwp_socket.cc
index aba893d..351e456 100644
--- a/src/jdwp/jdwp_socket.cc
+++ b/src/jdwp/jdwp_socket.cc
@@ -822,7 +822,7 @@
  *
  * Returns "true" if it was sent successfully.
  */
-static bool sendBufferedRequest(JdwpState* state, const iovec* iov, int iovcnt) {
+static bool sendBufferedRequest(JdwpState* state, const iovec* iov, int iov_count) {
   JdwpNetState* netState = state->netState;
 
   if (netState->clientSock < 0) {
@@ -832,11 +832,11 @@
   }
 
   size_t expected = 0;
-  for (int i = 0; i < iovcnt; i++) {
+  for (int i = 0; i < iov_count; i++) {
     expected += iov[i].iov_len;
   }
 
-  ssize_t actual = netState->writeBufferedPacket(iov, iovcnt);
+  ssize_t actual = netState->writeBufferedPacket(iov, iov_count);
 
   if ((size_t)actual != expected) {
     PLOG(ERROR) << "Failed sending b-req to debugger (" << actual << " of " << expected << ")";
diff --git a/src/object.cc b/src/object.cc
index 3053823..b8d82dc 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -874,13 +874,11 @@
   if (new_reference_offsets != CLASS_WALK_SUPER) {
     // Sanity check that the number of bits set in the reference offset bitmap
     // agrees with the number of references
-    Class* cur = this;
-    size_t cnt = 0;
-    while (cur) {
-      cnt += cur->NumReferenceInstanceFieldsDuringLinking();
-      cur = cur->GetSuperClass();
+    size_t count = 0;
+    for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+      count += c->NumReferenceInstanceFieldsDuringLinking();
     }
-    CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets), cnt);
+    CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets), count);
   }
   SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
              new_reference_offsets, false);
diff --git a/src/stack.cc b/src/stack.cc
index 9589b57..542ac47 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -52,6 +52,13 @@
   return *reinterpret_cast<uint32_t*>(vreg_addr);
 }
 
+void Frame::SetVReg(Method* method, int vreg, uint32_t new_value) {
+  DCHECK(method == GetMethod());
+  int offset = oatVRegOffsetFromMethod(method, vreg);
+  byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
+  *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
+}
+
 uintptr_t Frame::LoadCalleeSave(int num) const {
   // Callee saves are held at the top of the frame
   Method* method = GetMethod();
diff --git a/src/stack.h b/src/stack.h
index 680a69d..a0f13d3 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -55,6 +55,7 @@
   uintptr_t LoadCalleeSave(int num) const;
 
   uint32_t GetVReg(Method* method, int vreg) const;
+  void SetVReg(Method* method, int vreg, uint32_t new_value);
 
   Method** GetSP() const {
     return sp_;