Merge "ART: Refactor callbacks_ in common_runtime_test"
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 5ce73ba..b2f9c65 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -583,8 +583,13 @@
   if (method != nullptr) {
     return method;
   }
-  return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx,
-                            class_loader, dex_file);
+  method = delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx,
+                              class_loader, dex_file);
+
+  if (method != nullptr) {
+    compilation_stats_.RecordStat(MethodCompilationStat::kCompiledQuick);
+  }
+  return method;
 }
 
 Compiler* CreateOptimizingCompiler(CompilerDriver* driver) {
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 22ec2a5..b97a667 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -28,6 +28,7 @@
   kAttemptCompilation = 0,
   kCompiledBaseline,
   kCompiledOptimized,
+  kCompiledQuick,
   kInlinedInvoke,
   kNotCompiledUnsupportedIsa,
   kNotCompiledPathological,
@@ -65,16 +66,22 @@
           compile_stats_[kCompiledBaseline] * 100 / compile_stats_[kAttemptCompilation];
       size_t optimized_percent =
           compile_stats_[kCompiledOptimized] * 100 / compile_stats_[kAttemptCompilation];
+      size_t quick_percent =
+          compile_stats_[kCompiledQuick] * 100 / compile_stats_[kAttemptCompilation];
       std::ostringstream oss;
-      oss << "Attempted compilation of " << compile_stats_[kAttemptCompilation] << " methods: "
-          << unoptimized_percent << "% (" << compile_stats_[kCompiledBaseline] << ") unoptimized, "
-          << optimized_percent << "% (" << compile_stats_[kCompiledOptimized] << ") optimized.";
+      oss << "Attempted compilation of " << compile_stats_[kAttemptCompilation] << " methods: ";
+
+      oss << unoptimized_percent << "% (" << compile_stats_[kCompiledBaseline] << ") unoptimized, ";
+      oss << optimized_percent << "% (" << compile_stats_[kCompiledOptimized] << ") optimized, ";
+      oss << quick_percent << "% (" << compile_stats_[kCompiledQuick] << ") quick.";
+
+      LOG(INFO) << oss.str();
+
       for (int i = 0; i < kLastStat; i++) {
         if (compile_stats_[i] != 0) {
-          oss << "\n" << PrintMethodCompilationStat(i) << ": " << compile_stats_[i];
+          VLOG(compiler) << PrintMethodCompilationStat(i) << ": " << compile_stats_[i];
         }
       }
-      LOG(INFO) << oss.str();
     }
   }
 
@@ -84,6 +91,7 @@
       case kAttemptCompilation : return "kAttemptCompilation";
       case kCompiledBaseline : return "kCompiledBaseline";
       case kCompiledOptimized : return "kCompiledOptimized";
+      case kCompiledQuick : return "kCompiledQuick";
       case kInlinedInvoke : return "kInlinedInvoke";
       case kNotCompiledUnsupportedIsa : return "kNotCompiledUnsupportedIsa";
       case kNotCompiledPathological : return "kNotCompiledPathological";
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index cecc210..efb98f0 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -851,6 +851,23 @@
   return false;
 }
 
+bool RegisterAllocator::PotentiallyRemoveOtherHalf(LiveInterval* interval,
+                                                   GrowableArray<LiveInterval*>* intervals,
+                                                   size_t index) {
+  if (interval->IsLowInterval()) {
+    DCHECK_EQ(intervals->Get(index), interval->GetHighInterval());
+    intervals->DeleteAt(index);
+    return true;
+  } else if (interval->IsHighInterval()) {
+    DCHECK_GT(index, 0u);
+    DCHECK_EQ(intervals->Get(index - 1), interval->GetLowInterval());
+    intervals->DeleteAt(index - 1);
+    return true;
+  } else {
+    return false;
+  }
+}
+
 // Find the register that is used the last, and spill the interval
 // that holds it. If the first use of `current` is after that register
 // we spill `current` instead.
@@ -974,33 +991,17 @@
       if (active->GetRegister() == reg) {
         DCHECK(!active->IsFixed());
         LiveInterval* split = Split(active, current->GetStart());
-        active_.DeleteAt(i);
         if (split != active) {
           handled_.Add(active);
         }
+        active_.DeleteAt(i);
+        PotentiallyRemoveOtherHalf(active, &active_, i);
         AddSorted(unhandled_, split);
-
-        if (active->IsLowInterval() || active->IsHighInterval()) {
-          LiveInterval* other_half = active->IsLowInterval()
-              ? active->GetHighInterval()
-              : active->GetLowInterval();
-          // We also need to remove the other half from the list of actives.
-          bool found = false;
-          for (size_t j = 0; j < active_.Size(); ++j) {
-            if (active_.Get(j) == other_half) {
-              found = true;
-              active_.DeleteAt(j);
-              handled_.Add(other_half);
-              break;
-            }
-          }
-          DCHECK(found);
-        }
         break;
       }
     }
 
-    for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
+    for (size_t i = 0; i < inactive_.Size(); ++i) {
       LiveInterval* inactive = inactive_.Get(i);
       if (inactive->GetRegister() == reg) {
         if (!current->IsSplit() && !inactive->IsFixed()) {
@@ -1024,29 +1025,14 @@
             // If it's inactive, it must start before the current interval.
             DCHECK_NE(split, inactive);
             inactive_.DeleteAt(i);
+            if (PotentiallyRemoveOtherHalf(inactive, &inactive_, i) && inactive->IsHighInterval()) {
+              // We have removed an entry prior to `inactive`. So we need to decrement.
+              --i;
+            }
+            // Decrement because we have removed `inactive` from the list.
             --i;
-            --e;
             handled_.Add(inactive);
             AddSorted(unhandled_, split);
-
-            if (inactive->IsLowInterval() || inactive->IsHighInterval()) {
-              LiveInterval* other_half = inactive->IsLowInterval()
-                  ? inactive->GetHighInterval()
-                  : inactive->GetLowInterval();
-
-              // We also need to remove the other half from the list of inactives.
-              bool found = false;
-              for (size_t j = 0; j < inactive_.Size(); ++j) {
-                if (inactive_.Get(j) == other_half) {
-                  found = true;
-                  inactive_.DeleteAt(j);
-                  --e;
-                  handled_.Add(other_half);
-                  break;
-                }
-              }
-              DCHECK(found);
-            }
           }
         }
       }
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index fcc6112..717be75 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -144,6 +144,13 @@
                                                 size_t first_register_use,
                                                 size_t* next_use);
 
+  // If `interval` has another half, remove it from the list of `intervals`.
+  // `index` holds the index at which `interval` is in `intervals`.
+  // Returns whether there is another half.
+  bool PotentiallyRemoveOtherHalf(LiveInterval* interval,
+                                  GrowableArray<LiveInterval*>* intervals,
+                                  size_t index);
+
   ArenaAllocator* const allocator_;
   CodeGenerator* const codegen_;
   const SsaLivenessAnalysis& liveness_;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 5ea0187..a767cf0 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1451,22 +1451,31 @@
  * Circularly shifts registers so that arguments come last. Reverts
  * slots to dex style argument placement.
  */
-static uint16_t DemangleSlot(uint16_t slot, mirror::ArtMethod* m)
+static uint16_t DemangleSlot(uint16_t slot, mirror::ArtMethod* m, JDWP::JdwpError* error)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item == nullptr) {
     // We should not get here for a method without code (native, proxy or abstract). Log it and
     // return the slot as is since all registers are arguments.
     LOG(WARNING) << "Trying to demangle slot for method without code " << PrettyMethod(m);
-    return slot;
-  }
-  uint16_t ins_size = code_item->ins_size_;
-  uint16_t locals_size = code_item->registers_size_ - ins_size;
-  if (slot < ins_size) {
-    return slot + locals_size;
+    uint16_t vreg_count = mirror::ArtMethod::NumArgRegisters(m->GetShorty());
+    if (slot < vreg_count) {
+      *error = JDWP::ERR_NONE;
+      return slot;
+    }
   } else {
-    return slot - ins_size;
+    if (slot < code_item->registers_size_) {
+      uint16_t ins_size = code_item->ins_size_;
+      uint16_t locals_size = code_item->registers_size_ - ins_size;
+      *error = JDWP::ERR_NONE;
+      return (slot < ins_size) ? slot + locals_size : slot - ins_size;
+    }
   }
+
+  // Slot is invalid in the method.
+  LOG(ERROR) << "Invalid local slot " << slot << " for method " << PrettyMethod(m);
+  *error = JDWP::ERR_INVALID_SLOT;
+  return DexFile::kDexNoIndex16;
 }
 
 JDWP::JdwpError Dbg::OutputDeclaredFields(JDWP::RefTypeId class_id, bool with_generic, JDWP::ExpandBuf* pReply) {
@@ -2427,6 +2436,9 @@
     if (error != JDWP::ERR_NONE) {
       return error;
     }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
   }
   // Find the frame with the given frame_id.
   std::unique_ptr<Context> context(Context::Create());
@@ -2455,73 +2467,81 @@
   return JDWP::ERR_NONE;
 }
 
+constexpr JDWP::JdwpError kStackFrameLocalAccessError = JDWP::ERR_ABSENT_INFORMATION;
+
+static std::string GetStackContextAsString(const StackVisitor& visitor)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return StringPrintf(" at DEX pc 0x%08x in method %s", visitor.GetDexPc(false),
+                      PrettyMethod(visitor.GetMethod()).c_str());
+}
+
+static JDWP::JdwpError FailGetLocalValue(const StackVisitor& visitor, uint16_t vreg,
+                                         JDWP::JdwpTag tag)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  LOG(ERROR) << "Failed to read " << tag << " local from register v" << vreg
+             << GetStackContextAsString(visitor);
+  return kStackFrameLocalAccessError;
+}
+
 JDWP::JdwpError Dbg::GetLocalValue(const StackVisitor& visitor, ScopedObjectAccessUnchecked& soa,
                                    int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t width) {
   mirror::ArtMethod* m = visitor.GetMethod();
-  uint16_t reg = DemangleSlot(slot, m);
+  JDWP::JdwpError error = JDWP::ERR_NONE;
+  uint16_t vreg = DemangleSlot(slot, m, &error);
+  if (error != JDWP::ERR_NONE) {
+    return error;
+  }
   // TODO: check that the tag is compatible with the actual type of the slot!
-  // TODO: check slot is valid for this method or return INVALID_SLOT error.
-  constexpr JDWP::JdwpError kFailureErrorCode = JDWP::ERR_ABSENT_INFORMATION;
   switch (tag) {
     case JDWP::JT_BOOLEAN: {
       CHECK_EQ(width, 1U);
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kIntVReg, &intVal)) {
-        VLOG(jdwp) << "get boolean local " << reg << " = " << intVal;
-        JDWP::Set1(buf + 1, intVal != 0);
-      } else {
-        VLOG(jdwp) << "failed to get boolean local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kIntVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get boolean local " << vreg << " = " << intVal;
+      JDWP::Set1(buf + 1, intVal != 0);
       break;
     }
     case JDWP::JT_BYTE: {
       CHECK_EQ(width, 1U);
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kIntVReg, &intVal)) {
-        VLOG(jdwp) << "get byte local " << reg << " = " << intVal;
-        JDWP::Set1(buf + 1, intVal);
-      } else {
-        VLOG(jdwp) << "failed to get byte local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kIntVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get byte local " << vreg << " = " << intVal;
+      JDWP::Set1(buf + 1, intVal);
       break;
     }
     case JDWP::JT_SHORT:
     case JDWP::JT_CHAR: {
       CHECK_EQ(width, 2U);
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kIntVReg, &intVal)) {
-        VLOG(jdwp) << "get short/char local " << reg << " = " << intVal;
-        JDWP::Set2BE(buf + 1, intVal);
-      } else {
-        VLOG(jdwp) << "failed to get short/char local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kIntVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get short/char local " << vreg << " = " << intVal;
+      JDWP::Set2BE(buf + 1, intVal);
       break;
     }
     case JDWP::JT_INT: {
       CHECK_EQ(width, 4U);
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kIntVReg, &intVal)) {
-        VLOG(jdwp) << "get int local " << reg << " = " << intVal;
-        JDWP::Set4BE(buf + 1, intVal);
-      } else {
-        VLOG(jdwp) << "failed to get int local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kIntVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get int local " << vreg << " = " << intVal;
+      JDWP::Set4BE(buf + 1, intVal);
       break;
     }
     case JDWP::JT_FLOAT: {
       CHECK_EQ(width, 4U);
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kFloatVReg, &intVal)) {
-        VLOG(jdwp) << "get float local " << reg << " = " << intVal;
-        JDWP::Set4BE(buf + 1, intVal);
-      } else {
-        VLOG(jdwp) << "failed to get float local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kFloatVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get float local " << vreg << " = " << intVal;
+      JDWP::Set4BE(buf + 1, intVal);
       break;
     }
     case JDWP::JT_ARRAY:
@@ -2533,47 +2553,44 @@
     case JDWP::JT_THREAD_GROUP: {
       CHECK_EQ(width, sizeof(JDWP::ObjectId));
       uint32_t intVal;
-      if (visitor.GetVReg(m, reg, kReferenceVReg, &intVal)) {
-        mirror::Object* o = reinterpret_cast<mirror::Object*>(intVal);
-        VLOG(jdwp) << "get " << tag << " object local " << reg << " = " << o;
-        if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
-          LOG(FATAL) << "Register " << reg << " expected to hold " << tag << " object: " << o;
-        }
-        tag = TagFromObject(soa, o);
-        JDWP::SetObjectId(buf + 1, gRegistry->Add(o));
-      } else {
-        VLOG(jdwp) << "failed to get " << tag << " object local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVReg(m, vreg, kReferenceVReg, &intVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      mirror::Object* o = reinterpret_cast<mirror::Object*>(intVal);
+      VLOG(jdwp) << "get " << tag << " object local " << vreg << " = " << o;
+      if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
+        LOG(FATAL) << StringPrintf("Found invalid object %#" PRIxPTR " in register v%u",
+                                   reinterpret_cast<uintptr_t>(o), vreg)
+                                   << GetStackContextAsString(visitor);
+        UNREACHABLE();
+      }
+      tag = TagFromObject(soa, o);
+      JDWP::SetObjectId(buf + 1, gRegistry->Add(o));
       break;
     }
     case JDWP::JT_DOUBLE: {
       CHECK_EQ(width, 8U);
       uint64_t longVal;
-      if (visitor.GetVRegPair(m, reg, kDoubleLoVReg, kDoubleHiVReg, &longVal)) {
-        VLOG(jdwp) << "get double local " << reg << " = " << longVal;
-        JDWP::Set8BE(buf + 1, longVal);
-      } else {
-        VLOG(jdwp) << "failed to get double local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVRegPair(m, vreg, kDoubleLoVReg, kDoubleHiVReg, &longVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get double local " << vreg << " = " << longVal;
+      JDWP::Set8BE(buf + 1, longVal);
       break;
     }
     case JDWP::JT_LONG: {
       CHECK_EQ(width, 8U);
       uint64_t longVal;
-      if (visitor.GetVRegPair(m, reg, kLongLoVReg, kLongHiVReg, &longVal)) {
-        VLOG(jdwp) << "get long local " << reg << " = " << longVal;
-        JDWP::Set8BE(buf + 1, longVal);
-      } else {
-        VLOG(jdwp) << "failed to get long local " << reg;
-        return kFailureErrorCode;
+      if (!visitor.GetVRegPair(m, vreg, kLongLoVReg, kLongHiVReg, &longVal)) {
+        return FailGetLocalValue(visitor, vreg, tag);
       }
+      VLOG(jdwp) << "get long local " << vreg << " = " << longVal;
+      JDWP::Set8BE(buf + 1, longVal);
       break;
     }
     default:
       LOG(FATAL) << "Unknown tag " << tag;
-      break;
+      UNREACHABLE();
   }
 
   // Prepend tag, which may have been updated.
@@ -2594,6 +2611,9 @@
     if (error != JDWP::ERR_NONE) {
       return error;
     }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
   }
   // Find the frame with the given frame_id.
   std::unique_ptr<Context> context(Context::Create());
@@ -2620,46 +2640,50 @@
   return JDWP::ERR_NONE;
 }
 
+template<typename T>
+static JDWP::JdwpError FailSetLocalValue(const StackVisitor& visitor, uint16_t vreg,
+                                         JDWP::JdwpTag tag, T value)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  LOG(ERROR) << "Failed to write " << tag << " local " << value
+             << " (0x" << std::hex << value << ") into register v" << vreg
+             << GetStackContextAsString(visitor);
+  return kStackFrameLocalAccessError;
+}
+
 JDWP::JdwpError Dbg::SetLocalValue(StackVisitor& visitor, int slot, JDWP::JdwpTag tag,
                                    uint64_t value, size_t width) {
   mirror::ArtMethod* m = visitor.GetMethod();
-  uint16_t reg = DemangleSlot(slot, m);
+  JDWP::JdwpError error = JDWP::ERR_NONE;
+  uint16_t vreg = DemangleSlot(slot, m, &error);
+  if (error != JDWP::ERR_NONE) {
+    return error;
+  }
   // TODO: check that the tag is compatible with the actual type of the slot!
-  // TODO: check slot is valid for this method or return INVALID_SLOT error.
-  constexpr JDWP::JdwpError kFailureErrorCode = JDWP::ERR_ABSENT_INFORMATION;
   switch (tag) {
     case JDWP::JT_BOOLEAN:
     case JDWP::JT_BYTE:
       CHECK_EQ(width, 1U);
-      if (!visitor.SetVReg(m, reg, static_cast<uint32_t>(value), kIntVReg)) {
-        VLOG(jdwp) << "failed to set boolean/byte local " << reg << " = "
-                   << static_cast<uint32_t>(value);
-        return kFailureErrorCode;
+      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
       }
       break;
     case JDWP::JT_SHORT:
     case JDWP::JT_CHAR:
       CHECK_EQ(width, 2U);
-      if (!visitor.SetVReg(m, reg, static_cast<uint32_t>(value), kIntVReg)) {
-        VLOG(jdwp) << "failed to set short/char local " << reg << " = "
-                   << static_cast<uint32_t>(value);
-        return kFailureErrorCode;
+      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
       }
       break;
     case JDWP::JT_INT:
       CHECK_EQ(width, 4U);
-      if (!visitor.SetVReg(m, reg, static_cast<uint32_t>(value), kIntVReg)) {
-        VLOG(jdwp) << "failed to set int local " << reg << " = "
-                   << static_cast<uint32_t>(value);
-        return kFailureErrorCode;
+      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kIntVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
       }
       break;
     case JDWP::JT_FLOAT:
       CHECK_EQ(width, 4U);
-      if (!visitor.SetVReg(m, reg, static_cast<uint32_t>(value), kFloatVReg)) {
-        VLOG(jdwp) << "failed to set float local " << reg << " = "
-                   << static_cast<uint32_t>(value);
-        return kFailureErrorCode;
+      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(value), kFloatVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, static_cast<uint32_t>(value));
       }
       break;
     case JDWP::JT_ARRAY:
@@ -2670,38 +2694,35 @@
     case JDWP::JT_THREAD:
     case JDWP::JT_THREAD_GROUP: {
       CHECK_EQ(width, sizeof(JDWP::ObjectId));
-      JDWP::JdwpError error;
       mirror::Object* o = gRegistry->Get<mirror::Object*>(static_cast<JDWP::ObjectId>(value),
                                                           &error);
       if (error != JDWP::ERR_NONE) {
         VLOG(jdwp) << tag << " object " << o << " is an invalid object";
         return JDWP::ERR_INVALID_OBJECT;
-      } else if (!visitor.SetVReg(m, reg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)),
-                          kReferenceVReg)) {
-        VLOG(jdwp) << "failed to set " << tag << " object local " << reg << " = " << o;
-        return kFailureErrorCode;
+      }
+      if (!visitor.SetVReg(m, vreg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)),
+                                 kReferenceVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, reinterpret_cast<uintptr_t>(o));
       }
       break;
     }
     case JDWP::JT_DOUBLE: {
       CHECK_EQ(width, 8U);
-      if (!visitor.SetVRegPair(m, reg, value, kDoubleLoVReg, kDoubleHiVReg)) {
-        VLOG(jdwp) << "failed to set double local " << reg << " = " << value;
-        return kFailureErrorCode;
+      if (!visitor.SetVRegPair(m, vreg, value, kDoubleLoVReg, kDoubleHiVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, value);
       }
       break;
     }
     case JDWP::JT_LONG: {
       CHECK_EQ(width, 8U);
-      if (!visitor.SetVRegPair(m, reg, value, kLongLoVReg, kLongHiVReg)) {
-        VLOG(jdwp) << "failed to set double local " << reg << " = " << value;
-        return kFailureErrorCode;
+      if (!visitor.SetVRegPair(m, vreg, value, kLongLoVReg, kLongHiVReg)) {
+        return FailSetLocalValue(visitor, vreg, tag, value);
       }
       break;
     }
     default:
       LOG(FATAL) << "Unknown tag " << tag;
-      break;
+      UNREACHABLE();
   }
   return JDWP::ERR_NONE;
 }
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 57ca2b1..2724d91 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -79,7 +79,9 @@
 
 static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
                                                jboolean samplingEnabled, jint intervalUs) {
-  Trace::Start("[DDMS]", -1, bufferSize, flags, true, samplingEnabled, intervalUs);
+  Trace::Start("[DDMS]", -1, bufferSize, flags, Trace::TraceOutputMode::kDDMS,
+               samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
+               intervalUs);
 }
 
 static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
@@ -102,7 +104,9 @@
   if (traceFilename.c_str() == NULL) {
     return;
   }
-  Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, false, samplingEnabled, intervalUs);
+  Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, Trace::TraceOutputMode::kFile,
+               samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
+               intervalUs);
 }
 
 static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
@@ -112,7 +116,9 @@
   if (traceFilename.c_str() == NULL) {
     return;
   }
-  Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, false, samplingEnabled, intervalUs);
+  Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, Trace::TraceOutputMode::kFile,
+               samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
+               intervalUs);
 }
 
 static jint VMDebug_getMethodTracingMode(JNIEnv*, jclass) {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3cb6b36..0ca9d24 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -253,7 +253,10 @@
   mirror::Field* result = GetDeclaredField(soa.Self(), klass, name_string);
   if (result == nullptr) {
     std::string name_str = name_string->ToModifiedUtf8();
-    soa.Self()->ThrowNewException("Ljava/lang/NoSuchFieldException;", name_str.c_str());
+    // We may have a pending exception if we failed to resolve.
+    if (!soa.Self()->IsExceptionPending()) {
+      soa.Self()->ThrowNewException("Ljava/lang/NoSuchFieldException;", name_str.c_str());
+    }
     return nullptr;
   }
   return soa.AddLocalReference<jobject>(result);
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 0fe78b3..721b7a3 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -44,7 +44,7 @@
   }
   mirror::Class* calling_class = nullptr;
   if (!VerifyAccess(self, obj, field->GetDeclaringClass(), field->GetAccessFlags(),
-                    &calling_class)) {
+                    &calling_class, 1)) {
     ThrowIllegalAccessException(
             StringPrintf("Class %s cannot access %s field %s of class %s",
                 calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -276,9 +276,9 @@
     break;
   case Primitive::kPrimShort:
     if (is_volatile) {
-      o->SetFieldShortVolatile<false>(offset, new_value.GetZ());
+      o->SetFieldShortVolatile<false>(offset, new_value.GetS());
     } else {
-      o->SetFieldShort<false>(offset, new_value.GetZ());
+      o->SetFieldShort<false>(offset, new_value.GetS());
     }
     break;
   case Primitive::kPrimNot:
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index d845e40..4e94de4 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -587,7 +587,7 @@
   // If method is not set to be accessible, verify it can be accessed by the caller.
   mirror::Class* calling_class = nullptr;
   if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags(),
-                                   &calling_class)) {
+                                   &calling_class, 2)) {
     ThrowIllegalAccessException(
         StringPrintf("Class %s cannot access %s method %s of class %s",
             calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -794,11 +794,11 @@
 }
 
 bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class** calling_class) {
+                  uint32_t access_flags, mirror::Class** calling_class, size_t num_frames) {
   if ((access_flags & kAccPublic) != 0) {
     return true;
   }
-  NthCallerVisitor visitor(self, 2);
+  NthCallerVisitor visitor(self, num_frames);
   visitor.WalkStack();
   if (UNLIKELY(visitor.caller == nullptr)) {
     // The caller is an attached native thread.
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 6bef664..ff970e5 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -73,7 +73,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class** calling_class)
+                  uint32_t access_flags, mirror::Class** calling_class, size_t num_frames)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 void InvalidReceiverError(mirror::Object* o, mirror::Class* c)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d7dd6d0..23a7db6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1013,8 +1013,8 @@
                  -1,
                  static_cast<int>(method_trace_file_size_),
                  0,
-                 false,
-                 false,
+                 Trace::TraceOutputMode::kFile,
+                 Trace::TraceMode::kMethodTracing,
                  0);
   }
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 3734903..ea0a642 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -328,7 +328,7 @@
 }
 
 void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int flags,
-                  bool direct_to_ddms, bool sampling_enabled, int interval_us) {
+                  TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) {
   Thread* self = Thread::Current();
   {
     MutexLock mu(self, *Locks::trace_lock_);
@@ -339,7 +339,7 @@
   }
 
   // Check interval if sampling is enabled
-  if (sampling_enabled && interval_us <= 0) {
+  if (trace_mode == TraceMode::kSampling && interval_us <= 0) {
     LOG(ERROR) << "Invalid sampling interval: " << interval_us;
     ScopedObjectAccess soa(self);
     ThrowRuntimeException("Invalid sampling interval: %d", interval_us);
@@ -348,7 +348,7 @@
 
   // Open trace file if not going directly to ddms.
   std::unique_ptr<File> trace_file;
-  if (!direct_to_ddms) {
+  if (output_mode != TraceOutputMode::kDDMS) {
     if (trace_fd < 0) {
       trace_file.reset(OS::CreateEmptyFile(trace_filename));
     } else {
@@ -377,8 +377,8 @@
       LOG(ERROR) << "Trace already in progress, ignoring this request";
     } else {
       enable_stats = (flags && kTraceCountAllocs) != 0;
-      the_trace_ = new Trace(trace_file.release(), buffer_size, flags, sampling_enabled);
-      if (sampling_enabled) {
+      the_trace_ = new Trace(trace_file.release(), buffer_size, flags, trace_mode);
+      if (trace_mode == TraceMode::kSampling) {
         CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, NULL, &RunSamplingThread,
                                             reinterpret_cast<void*>(interval_us)),
                                             "Sampling profiler thread");
@@ -427,7 +427,7 @@
     stop_alloc_counting = (the_trace->flags_ & kTraceCountAllocs) != 0;
     the_trace->FinishTracing();
 
-    if (the_trace->sampling_enabled_) {
+    if (the_trace->trace_mode_ == TraceMode::kSampling) {
       MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
       runtime->GetThreadList()->ForEach(ClearThreadStackTraceAndClockBase, nullptr);
     } else {
@@ -465,16 +465,21 @@
   MutexLock mu(Thread::Current(), *Locks::trace_lock_);
   if (the_trace_ == NULL) {
     return kTracingInactive;
-  } else if (the_trace_->sampling_enabled_) {
-    return kSampleProfilingActive;
   } else {
-    return kMethodTracingActive;
+    switch (the_trace_->trace_mode_) {
+      case TraceMode::kSampling:
+        return kSampleProfilingActive;
+      case TraceMode::kMethodTracing:
+        return kMethodTracingActive;
+    }
+    LOG(FATAL) << "Unreachable";
+    UNREACHABLE();
   }
 }
 
-Trace::Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled)
+Trace::Trace(File* trace_file, int buffer_size, int flags, TraceMode trace_mode)
     : trace_file_(trace_file), buf_(new uint8_t[buffer_size]()), flags_(flags),
-      sampling_enabled_(sampling_enabled), clock_source_(default_clock_source_),
+      trace_mode_(trace_mode), clock_source_(default_clock_source_),
       buffer_size_(buffer_size), start_time_(MicroTime()),
       clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0), overflow_(false) {
   // Set up the beginning of the trace.
diff --git a/runtime/trace.h b/runtime/trace.h
index dd8186a..80f926f 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -51,10 +51,20 @@
     kTraceCountAllocs = 1,
   };
 
+  enum class TraceOutputMode {
+    kFile,
+    kDDMS
+  };
+
+  enum class TraceMode {
+    kMethodTracing,
+    kSampling
+  };
+
   static void SetDefaultClockSource(TraceClockSource clock_source);
 
   static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags,
-                    bool direct_to_ddms, bool sampling_enabled, int interval_us)
+                    TraceOutputMode output_mode, TraceMode trace_mode, int interval_us)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_,
@@ -107,7 +117,7 @@
   static void StoreExitingThreadInfo(Thread* thread);
 
  private:
-  explicit Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled);
+  explicit Trace(File* trace_file, int buffer_size, int flags, TraceMode trace_mode);
 
   // The sampling interval in microseconds is passed as an argument.
   static void* RunSamplingThread(void* arg) LOCKS_EXCLUDED(Locks::trace_lock_);
@@ -148,7 +158,7 @@
   const int flags_;
 
   // True if traceview should sample instead of instrumenting method entry/exit.
-  const bool sampling_enabled_;
+  const TraceMode trace_mode_;
 
   const TraceClockSource clock_source_;
 
diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java
index 5c6ca13..59f7001 100644
--- a/test/046-reflect/src/Main.java
+++ b/test/046-reflect/src/Main.java
@@ -720,6 +720,10 @@
         }
     }
 
+    static void checkPrivateFieldAccess() {
+        (new OtherClass()).test();
+    }
+
     public static void main(String[] args) throws Exception {
         Main test = new Main();
         test.run();
@@ -733,6 +737,7 @@
         checkUnique();
         checkParametrizedTypeEqualsAndHashCode();
         checkGenericArrayTypeEqualsAndHashCode();
+        checkPrivateFieldAccess();
     }
 }
 
@@ -804,41 +809,41 @@
 }
 
 class FieldNoisyInit {
-  static {
-    System.out.println("FieldNoisyInit is initializing");
-    //Throwable th = new Throwable();
-    //th.printStackTrace();
-  }
+    static {
+        System.out.println("FieldNoisyInit is initializing");
+        //Throwable th = new Throwable();
+        //th.printStackTrace();
+    }
 }
 
 class FieldNoisyInitUser {
-  static {
-    System.out.println("FieldNoisyInitUser is initializing");
-  }
-  public static int staticField;
-  public static FieldNoisyInit noisy;
+    static {
+        System.out.println("FieldNoisyInitUser is initializing");
+    }
+    public static int staticField;
+    public static FieldNoisyInit noisy;
 }
 
 class MethodNoisyInit {
-  static {
-    System.out.println("MethodNoisyInit is initializing");
-    //Throwable th = new Throwable();
-    //th.printStackTrace();
-  }
+    static {
+        System.out.println("MethodNoisyInit is initializing");
+        //Throwable th = new Throwable();
+        //th.printStackTrace();
+    }
 }
 
 class MethodNoisyInitUser {
-  static {
-    System.out.println("MethodNoisyInitUser is initializing");
-  }
-  public static void staticMethod() {}
-  public void createMethodNoisyInit(MethodNoisyInit ni) {}
+    static {
+        System.out.println("MethodNoisyInitUser is initializing");
+    }
+    public static void staticMethod() {}
+    public void createMethodNoisyInit(MethodNoisyInit ni) {}
 }
 
 class Thrower {
-  public Thrower() throws UnsupportedOperationException {
-    throw new UnsupportedOperationException();
-  }
+    public Thrower() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
 }
 
 class ParametrizedTypeTest {
@@ -850,3 +855,17 @@
     public void aMethod(T[] names) {}
     public void aMethodIdentical(T[] names) {}
 }
+
+class OtherClass {
+    private static final long LONG = 1234;
+    public void test() {
+        try {
+            Field field = getClass().getDeclaredField("LONG");
+            if (1234 != field.getLong(null)) {
+              System.out.println("ERROR: values don't match");
+            }
+        } catch (Exception e) {
+            System.out.println(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/467-regalloc-pair/expected.txt b/test/467-regalloc-pair/expected.txt
new file mode 100644
index 0000000..da39d9d
--- /dev/null
+++ b/test/467-regalloc-pair/expected.txt
@@ -0,0 +1 @@
+In interface
diff --git a/test/467-regalloc-pair/info.txt b/test/467-regalloc-pair/info.txt
new file mode 100644
index 0000000..882a29c
--- /dev/null
+++ b/test/467-regalloc-pair/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing's register allocator
+that used to trip when compiling TestCase.testCase on x86.
diff --git a/test/467-regalloc-pair/smali/TestCase.smali b/test/467-regalloc-pair/smali/TestCase.smali
new file mode 100644
index 0000000..a3101fe
--- /dev/null
+++ b/test/467-regalloc-pair/smali/TestCase.smali
@@ -0,0 +1,59 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LTestCase;
+
+.super Ljava/lang/Object;
+
+.method public static testCase([BLMain;)V
+    .registers 12
+    const/4 v2, 0
+    array-length v0, v10
+    div-int/lit8 v0, v0, 7
+    invoke-static {v2, v0}, Ljava/lang/Math;->max(II)I
+    move-result v7
+    move v6, v2
+    move v3, v2
+    :label5
+    if-ge v6, v7, :label1
+    const-wide/16 v0, 0
+    move-wide v4, v0
+    move v1, v2
+    move v0, v3
+    :label4
+    const/4 v3, 6
+    if-ge v1, v3, :label2
+    const/16 v3, 8
+    shl-long/2addr v4, v3
+    add-int/lit8 v3, v0, 1
+    aget-byte v0, v10, v0
+    if-gez v0, :label3
+    add-int/lit16 v0, v0, 256
+    :label3
+    int-to-long v8, v0
+    or-long/2addr v4, v8
+    add-int/lit8 v0, v1, 1
+    move v1, v0
+    move v0, v3
+    goto :label4
+    :label2
+    add-int/lit8 v3, v0, 1
+    aget-byte v0, v10, v0
+    invoke-interface {v11, v4, v5, v0}, LItf;->invokeInterface(JI)V
+    add-int/lit8 v0, v6, 1
+    move v6, v0
+    goto :label5
+    :label1
+    return-void
+.end method
diff --git a/test/467-regalloc-pair/src/Main.java b/test/467-regalloc-pair/src/Main.java
new file mode 100644
index 0000000..aac07fd
--- /dev/null
+++ b/test/467-regalloc-pair/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+interface Itf {
+  public void invokeInterface(long l, int i);
+}
+
+public class Main implements Itf {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("TestCase");
+    Method m = c.getMethod("testCase", byte[].class, Main.class);
+    m.invoke(null, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, new Main());
+  }
+
+  public void invokeInterface(long l, int i) {
+    System.out.println("In interface");
+  }
+}
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index c51bd20..2c555d5 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -19,6 +19,11 @@
   exit 1
 fi
 
+if [ $ANDROID_SERIAL == 03a79ae90ae5889b ] || [ $ANDROID_SERIAL == HT4CTJT03670 ] || [ $ANDROID_SERIAL == HT49CJT00070 ]; then
+  echo "Not run because of localhost failures. Investigating."
+  exit 0
+fi
+
 # Jar containing all the tests.
 test_jar=out/host/linux-x86/framework/apache-harmony-jdwp-tests-hostdex.jar
 junit_jar=out/host/linux-x86/framework/junit.jar
@@ -56,6 +61,7 @@
 # Run the tests using vogar.
 vogar --vm-command=$art \
       --vm-arg $image \
+      --verbose \
       $args \
       $device_dir \
       --vm-arg -Ximage-compiler-option \