Support for SetVReg and add SetGPR.

These changes are useful for debugging and are required for being able
to change all GC roots.

MIPS is untested.

Change-Id: I2ba055de64264098bffe869a4fb192d0975f1c8f
diff --git a/src/oat/runtime/x86/context_x86.cc b/src/oat/runtime/x86/context_x86.cc
index 4ff2283..4efdf81 100644
--- a/src/oat/runtime/x86/context_x86.cc
+++ b/src/oat/runtime/x86/context_x86.cc
@@ -21,14 +21,16 @@
 namespace art {
 namespace x86 {
 
-X86Context::X86Context() {
-#ifndef NDEBUG
-  // Initialize registers with easy to spot debug values.
-  for (int i = 0; i < 8; i++) {
-    gprs_[i] = kBadGprBase + i;
+static const uint32_t gZero = 0;
+
+void X86Context::Reset() {
+  for (int i = 0; i < kNumberOfCpuRegisters; i++) {
+    gprs_[i] = NULL;
   }
-  eip_ = 0xEBAD601F;
-#endif
+  gprs_[ESP] = &esp_;
+  // Initialize registers with easy to spot debug values.
+  esp_ = X86Context::kBadGprBase + ESP;
+  eip_ = X86Context::kBadGprBase + kNumberOfCpuRegisters;
 }
 
 void X86Context::FillCalleeSaves(const StackVisitor& fr) {
@@ -38,11 +40,11 @@
   DCHECK_EQ(method->GetFpSpillMask(), 0u);
   size_t frame_size = method->GetFrameSizeInBytes();
   if (spill_count > 0) {
-    // Lowest number spill is furthest away, walk registers and fill into context.
+    // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 2;  // Offset j to skip return address spill.
-    for (int i = 0; i < 8; i++) {
+    for (int i = 0; i < kNumberOfCpuRegisters; i++) {
       if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.LoadCalleeSave(spill_count - j, frame_size);
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size);
         j++;
       }
     }
@@ -50,37 +52,40 @@
 }
 
 void X86Context::SmashCallerSaves() {
-  gprs_[EAX] = 0; // This needs to be 0 because we want a null/zero return value.
-  gprs_[ECX] = kBadGprBase + ECX;
-  gprs_[EDX] = kBadGprBase + EDX;
-  gprs_[EBX] = kBadGprBase + EBX;
+  // This needs to be 0 because we want a null/zero return value.
+  gprs_[EAX] = const_cast<uint32_t*>(&gZero);
+  gprs_[EDX] = const_cast<uint32_t*>(&gZero);
+  gprs_[ECX] = NULL;
+  gprs_[EBX] = NULL;
+}
+
+void X86Context::SetGPR(uint32_t reg, uintptr_t value){
+  CHECK_LT(reg, kNumberOfCpuRegisters);
+  CHECK_NE(gprs_[reg], &gZero);
+  CHECK(gprs_[reg] != NULL);
+  *gprs_[reg] = value;
 }
 
 void X86Context::DoLongJump() {
 #if defined(__i386__)
-  // We push all the registers using memory-memory pushes, we then pop-all to get the registers
-  // set up, we then pop esp which will move us down the stack to the delivery address. At the frame
-  // where the exception will be delivered, we push EIP so that the return will take us to the
-  // correct delivery instruction.
-  gprs_[ESP] -= 4;
-  *(reinterpret_cast<uintptr_t*>(gprs_[ESP])) = eip_;
+  // Array of GPR values, filled from the context backward for the long jump pop. We add a slot at
+  // the top for the stack pointer that doesn't get popped in a pop-all.
+  volatile uintptr_t gprs[kNumberOfCpuRegisters + 1];
+  for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+    gprs[kNumberOfCpuRegisters - i - 1] = gprs_[i] != NULL ? *gprs_[i] : X86Context::kBadGprBase + i;
+  }
+  // We want to load the stack pointer one slot below so that the ret will pop eip.
+  uintptr_t esp = gprs[kNumberOfCpuRegisters - ESP - 1] - kWordSize;
+  gprs[kNumberOfCpuRegisters] = esp;
+  *(reinterpret_cast<uintptr_t*>(esp)) = eip_;
   __asm__ __volatile__(
-      "pushl %4\n\t"
-      "pushl %0\n\t"
-      "pushl %1\n\t"
-      "pushl %2\n\t"
-      "pushl %3\n\t"
-      "pushl %4\n\t"
-      "pushl %5\n\t"
-      "pushl %6\n\t"
-      "pushl %7\n\t"
-      "popal\n\t"
-      "popl %%esp\n\t"
-      "ret\n\t"
-      :  //output
-      : "g"(gprs_[EAX]), "g"(gprs_[ECX]), "g"(gprs_[EDX]), "g"(gprs_[EBX]),
-        "g"(gprs_[ESP]), "g"(gprs_[EBP]), "g"(gprs_[ESI]), "g"(gprs_[EDI])
-      :);  // clobber
+      "movl %0, %%esp\n\t"  // ESP points to gprs.
+      "popal\n\t"           // Load all registers except ESP and EIP with values in gprs.
+      "popl %%esp\n\t"      // Load stack pointer.
+      "ret\n\t"             // From higher in the stack pop eip.
+      :  // output.
+      : "g"(&gprs[0])  // input.
+      :);  // clobber.
 #else
     UNIMPLEMENTED(FATAL);
 #endif