Implement getting of 64-bit locals (double, long).

Also implement the JDWP "GetClassLoader" request, used by jswat's "classes"
command.

Also implement the JDWP "exit" request, tested with jswat's "shutdown".

Change-Id: Ic8424a332151242211d8a772721deb3199b24682
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
index d87bc2b..682aed9 100644
--- a/src/dalvik_system_VMStack.cc
+++ b/src/dalvik_system_VMStack.cc
@@ -59,7 +59,7 @@
   // TODO: need SmartFrame (Thread::WalkStack-like iterator).
   for (Frame frame = self->GetTopOfStack(); frame.HasNext(); frame.Next()) {
     Class* c = frame.GetMethod()->GetDeclaringClass();
-    Object* cl = const_cast<ClassLoader*>(c->GetClassLoader());
+    Object* cl = c->GetClassLoader();
     if (cl != bootstrap && cl != system) {
       return AddLocalReference<jobject>(env, cl);
     }
diff --git a/src/debugger.cc b/src/debugger.cc
index c95d64a..f4969dc 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -21,6 +21,7 @@
 #include <set>
 
 #include "class_linker.h"
+#include "class_loader.h"
 #include "context.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
@@ -440,7 +441,7 @@
 }
 
 void Dbg::Exit(int status) {
-  UNIMPLEMENTED(FATAL);
+  exit(status); // This is all dalvik did.
 }
 
 void Dbg::VisitRoots(Heap::RootVisitor* visitor, void* arg) {
@@ -465,8 +466,8 @@
 }
 
 JDWP::ObjectId Dbg::GetClassLoader(JDWP::RefTypeId id) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+  Object* o = gRegistry->Get<Object*>(id);
+  return gRegistry->Add(o->GetClass()->GetClassLoader());
 }
 
 uint32_t Dbg::GetAccessFlags(JDWP::RefTypeId id) {
@@ -1208,16 +1209,16 @@
   case JDWP::JT_BOOLEAN:
     {
       CHECK_EQ(expectedLen, 1U);
-      uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get boolean local " << reg << " = " << intVal;
+      uint32_t intVal = f.GetVReg(m, reg);
+      LOG(VERBOSE) << "get boolean local " << reg << " = " << intVal;
       JDWP::Set1(buf+1, intVal != 0);
     }
     break;
   case JDWP::JT_BYTE:
     {
       CHECK_EQ(expectedLen, 1U);
-      uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get byte local " << reg << " = " << intVal;
+      uint32_t intVal = f.GetVReg(m, reg);
+      LOG(VERBOSE) << "get byte local " << reg << " = " << intVal;
       JDWP::Set1(buf+1, intVal);
     }
     break;
@@ -1225,8 +1226,8 @@
   case JDWP::JT_CHAR:
     {
       CHECK_EQ(expectedLen, 2U);
-      uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get short/char local " << reg << " = " << intVal;
+      uint32_t intVal = f.GetVReg(m, reg);
+      LOG(VERBOSE) << "get short/char local " << reg << " = " << intVal;
       JDWP::Set2BE(buf+1, intVal);
     }
     break;
@@ -1234,8 +1235,8 @@
   case JDWP::JT_FLOAT:
     {
       CHECK_EQ(expectedLen, 4U);
-      uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get int/float local " << reg << " = " << intVal;
+      uint32_t intVal = f.GetVReg(m, reg);
+      LOG(VERBOSE) << "get int/float local " << reg << " = " << intVal;
       JDWP::Set4BE(buf+1, intVal);
     }
     break;
@@ -1243,7 +1244,7 @@
     {
       CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
       Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get array local " << reg << " = " << o;
+      LOG(VERBOSE) << "get array local " << reg << " = " << o;
       if (o != NULL && !Heap::IsHeapAddress(o)) {
         LOG(FATAL) << "reg " << reg << " expected to hold array: " << o;
       }
@@ -1254,7 +1255,7 @@
     {
       CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
       Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
-      LOG(WARNING) << "get object local " << reg << " = " << o;
+      LOG(VERBOSE) << "get object local " << reg << " = " << o;
       if (o != NULL && !Heap::IsHeapAddress(o)) {
         LOG(FATAL) << "reg " << reg << " expected to hold object: " << o;
       }
@@ -1265,9 +1266,11 @@
   case JDWP::JT_DOUBLE:
   case JDWP::JT_LONG:
     {
-      UNIMPLEMENTED(WARNING) << "get 64-bit local " << reg;
       CHECK_EQ(expectedLen, 8U);
-      uint64_t longVal = 0; // memcpy(&longVal, &framePtr[reg], 8);
+      uint32_t lo = f.GetVReg(m, reg);
+      uint64_t hi = f.GetVReg(m, reg + 1);
+      uint64_t longVal = (hi << 32) | lo;
+      LOG(VERBOSE) << "get double/long local " << hi << ":" << lo << " = " << longVal;
       JDWP::Set8BE(buf+1, longVal);
     }
     break;
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index cba037a..b85969e 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -195,7 +195,7 @@
 
 jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
   Class* c = Decode<Class*>(env, javaClass);
-  Object* result = reinterpret_cast<Object*>(const_cast<ClassLoader*>(c->GetClassLoader()));
+  Object* result = c->GetClassLoader();
   return AddLocalReference<jobject>(env, result);
 }
 
diff --git a/src/object.cc b/src/object.cc
index abf8310..3053823 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1024,8 +1024,8 @@
   return this == GetDescriptor()->GetClass();
 }
 
-const ClassLoader* Class::GetClassLoader() const {
-  return GetFieldObject<const ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
+ClassLoader* Class::GetClassLoader() const {
+  return GetFieldObject<ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
 }
 
 void Class::SetClassLoader(const ClassLoader* new_cl) {
diff --git a/src/object.h b/src/object.h
index 85542d2..82cd0a3 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1583,7 +1583,7 @@
     SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_), new_super_class_idx, false);
   }
 
-  const ClassLoader* GetClassLoader() const;
+  ClassLoader* GetClassLoader() const;
 
   void SetClassLoader(const ClassLoader* new_cl);
 
@@ -1949,7 +1949,7 @@
   String* name_;  // TODO initialize
 
   // defining class loader, or NULL for the "bootstrap" system loader
-  const ClassLoader* class_loader_;
+  ClassLoader* class_loader_;
 
   // For array classes, the component class object for instanceof/checkcast
   // (for String[][][], this will be String[][]). NULL for non-array classes.
diff --git a/src/stack.cc b/src/stack.cc
index 1e1f932..9589b57 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -45,11 +45,11 @@
   return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
-uintptr_t Frame::GetVReg(Method* method, int vreg) const {
+uint32_t Frame::GetVReg(Method* method, int vreg) const {
   DCHECK(method == GetMethod());
   int offset = oatVRegOffsetFromMethod(method, vreg);
   byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
-  return *reinterpret_cast<uintptr_t*>(vreg_addr);
+  return *reinterpret_cast<uint32_t*>(vreg_addr);
 }
 
 uintptr_t Frame::LoadCalleeSave(int num) const {
diff --git a/src/stack.h b/src/stack.h
index f1fb08f..680a69d 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -54,7 +54,7 @@
 
   uintptr_t LoadCalleeSave(int num) const;
 
-  uintptr_t GetVReg(Method* method, int vreg) const;
+  uint32_t GetVReg(Method* method, int vreg) const;
 
   Method** GetSP() const {
     return sp_;