Support for stack scanning of roots.

Change-Id: Icbb02959725735faaa230e0fd00e8039b2f9c1b2
diff --git a/src/compiler.h b/src/compiler.h
index 50447db..563bbde 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -8,6 +8,8 @@
 #include "jni_compiler.h"
 #include "object.h"
 
+int oatVRegOffsetFromMethod(art::Method* method, int reg);
+
 namespace art {
 
 class Compiler {
@@ -45,7 +47,6 @@
   void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
   void CompileClass(Class* klass);
   void CompileMethod(Method* klass);
-  int oatVRegOffsetFromMethod(Method* method, int reg);
 
   // After compiling, walk all the DexCaches and set the code and
   // method pointers of CodeAndDirectMethods entries in the DexCaches.
diff --git a/src/context.h b/src/context.h
index 05cd43b..b4a8b65 100644
--- a/src/context.h
+++ b/src/context.h
@@ -27,6 +27,9 @@
   // Set the program counter value
   virtual void SetPC(uintptr_t new_pc) = 0;
 
+  // Read the given GPR
+  virtual uintptr_t GetGPR(uint32_t reg) = 0;
+
   // Switch execution of the executing context to this context
   virtual void DoLongJump() = 0;
 };
diff --git a/src/context_arm.h b/src/context_arm.h
index 31a1a2a..07a4c0b 100644
--- a/src/context_arm.h
+++ b/src/context_arm.h
@@ -24,6 +24,12 @@
     gprs_[PC] = new_pc;
   }
 
+  virtual uintptr_t GetGPR(uint32_t reg) {
+    CHECK_GE(reg, 0u);
+    CHECK_LT(reg, 16u);
+    return gprs_[reg];
+  }
+
   virtual void DoLongJump();
 
  private:
diff --git a/src/context_x86.h b/src/context_x86.h
index 10dcbb4..aca994b 100644
--- a/src/context_x86.h
+++ b/src/context_x86.h
@@ -26,6 +26,12 @@
     eip_ = new_pc;
   }
 
+  virtual uintptr_t GetGPR(uint32_t reg) {
+    CHECK_GE(reg, 0u);
+    CHECK_LT(reg, 8u);
+    return gprs_[reg];
+  }
+
   virtual void DoLongJump();
 
  private:
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 2268772..8577dcc 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -5305,14 +5305,14 @@
   }
 
   /* Update method, and free compressed map if it was sitting on the heap. */
-  ByteArray* header = ByteArray::Alloc(sizeof(RegisterMapHeader));
-  ByteArray* data = ByteArray::Alloc(ComputeRegisterMapSize(map));
+  //ByteArray* header = ByteArray::Alloc(sizeof(RegisterMapHeader));
+  //ByteArray* data = ByteArray::Alloc(ComputeRegisterMapSize(map));
 
-  memcpy(header->GetData(), map->header_, sizeof(RegisterMapHeader));
-  memcpy(data->GetData(), map->data_, ComputeRegisterMapSize(map));
+  //memcpy(header->GetData(), map->header_, sizeof(RegisterMapHeader));
+  //memcpy(data->GetData(), map->data_, ComputeRegisterMapSize(map));
 
-  method->SetRegisterMapHeader(header);
-  method->SetRegisterMapData(data);
+  //method->SetRegisterMapHeader(header);
+  //method->SetRegisterMapData(data);
 
   delete map;
   return new_map;
diff --git a/src/heap.cc b/src/heap.cc
index 1b3daad..015f638 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -348,12 +348,13 @@
     ++Runtime::Current()->GetStats()->gc_for_alloc_count;
     ++Thread::Current()->GetStats()->gc_for_alloc_count;
   }
-  UNIMPLEMENTED(FATAL) << "No implicit GC, use larger -Xms -Xmx";
+  LOG(INFO) << "GC_FOR_ALLOC: TODO: test";
   CollectGarbageInternal();
   ptr = space->AllocWithoutGrowth(size);
   if (ptr != NULL) {
     return ptr;
   }
+  UNIMPLEMENTED(FATAL) << "No AllocWithGrowth, use larger -Xms -Xmx";
 
   // Even that didn't work;  this is an exceptional state.
   // Try harder, growing the heap if necessary.
diff --git a/src/object.h b/src/object.h
index 47aa98d..9b1d3c7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -838,8 +838,7 @@
   }
 
   ShortArray* GetVMapTable() const {
-    return GetFieldObject<ShortArray*>(
-        OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
+    return GetFieldObject<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
   }
 
   size_t GetFrameSizeInBytes() const {
diff --git a/src/thread.cc b/src/thread.cc
index d79e1c5..7adddfa 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -27,7 +27,9 @@
 #include <list>
 
 #include "class_linker.h"
+#include "compiler.h"
 #include "context.h"
+#include "dex_verifier.h"
 #include "heap.h"
 #include "jni_internal.h"
 #include "monitor.h"
@@ -532,6 +534,13 @@
   return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
+uintptr_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);
+}
+
 uintptr_t Frame::LoadCalleeSave(int num) const {
   // Callee saves are held at the top of the frame
   Method* method = GetMethod();
@@ -1576,7 +1585,75 @@
   return gThread_daemon->GetBoolean(peer_);
 }
 
-void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
+class ReferenceMapVisitor : public Thread::StackVisitor {
+ public:
+  ReferenceMapVisitor(Context* context, Heap::RootVisitor* root_visitor, void* arg) :
+    context_(context), root_visitor_(root_visitor), arg_(arg) {
+  }
+
+  void VisitFrame(const Frame& frame, uintptr_t pc) {
+    Method* m = frame.GetMethod();
+    LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false);
+
+    // Process register map (which native and callee save methods don't have)
+    if (!m->IsNative() && !m->IsPhony()) {
+      UniquePtr<art::DexVerifier::RegisterMap> map(art::DexVerifier::GetExpandedRegisterMap(m));
+
+      const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(map.get(), m->ToDexPC(pc));
+      CHECK(reg_bitmap != NULL);
+      ShortArray* vmap = m->GetVMapTable();
+      // For all dex registers
+      for (int reg = 0; reg < m->NumRegisters(); ++reg) {
+        // Does this register hold a reference?
+        if (TestBitmap(reg, reg_bitmap)) {
+          // Is the reference in the context or on the stack?
+          bool in_context = false;
+          int vmap_offset = -1;
+          // TODO: take advantage of the registers being ordered
+          for (int i = 0; i < vmap->GetLength(); i++) {
+            if (vmap->Get(i) == reg) {
+              in_context = true;
+              vmap_offset = i;
+              break;
+            }
+          }
+          Object* ref;
+          if (in_context) {
+            // Compute the register we need to load from the context
+            uint32_t spill_mask = m->GetCoreSpillMask();
+            uint32_t reg = 0;
+            for (int i = 0; i < vmap_offset; i++) {
+              while ((spill_mask & 1) == 0) {
+                CHECK_NE(spill_mask, 0u);
+                spill_mask >>= 1;
+                reg++;
+              }
+            }
+            ref = reinterpret_cast<Object*>(context_->GetGPR(reg));
+          } else {
+            ref = reinterpret_cast<Object*>(frame.GetVReg(m ,reg));
+          }
+          root_visitor_(ref, arg_);
+        }
+      }
+    }
+    context_->FillCalleeSaves(frame);
+  }
+
+ private:
+  bool TestBitmap(int reg, const uint8_t* reg_vector) {
+    return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
+  }
+
+  // Context used to build up picture of callee saves
+  Context* context_;
+  // Call-back when we visit a root
+  Heap::RootVisitor* root_visitor_;
+  // Argument to call-back
+  void* arg_;
+};
+
+void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) {
   if (exception_ != NULL) {
     visitor(exception_, arg);
   }
@@ -1585,8 +1662,12 @@
   }
   jni_env_->locals.VisitRoots(visitor, arg);
   jni_env_->monitors.VisitRoots(visitor, arg);
-  // visitThreadStack(visitor, thread, arg);
-  UNIMPLEMENTED(WARNING) << "some per-Thread roots not visited";
+  // Cheat and steal the long jump context. Assume that we are not doing a GC during exception
+  // delivery.
+  Context* context = GetLongJumpContext();
+  // Visit roots on this thread's stack
+  ReferenceMapVisitor mapper(context, visitor, arg);
+  WalkStack(&mapper);
 }
 
 static const char* kStateNames[] = {
diff --git a/src/thread.h b/src/thread.h
index ebab184..db5bbe8 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -121,6 +121,8 @@
 
   uintptr_t LoadCalleeSave(int num) const;
 
+  uintptr_t GetVReg(Method* method, int vreg) const;
+
   Method** GetSP() const {
     return sp_;
   }
@@ -460,7 +462,7 @@
   static jobjectArray InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
       jobjectArray output_array = NULL, int* stack_depth = NULL);
 
-  void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
+  void VisitRoots(Heap::RootVisitor* visitor, void* arg);
 
   //
   // Offsets of various members of native Thread class, used by compiled code.