merge in mnc-release history after reset to mnc-dev
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 58236e2..ff4659a 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -33,6 +33,7 @@
 #include "dex/pass_driver_me_post_opt.h"
 #include "dex/pass_manager.h"
 #include "dex/quick/mir_to_lir.h"
+#include "dex/verified_method.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "elf_writer_quick.h"
@@ -624,6 +625,10 @@
     return nullptr;
   }
 
+  if (driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()) {
+    return nullptr;
+  }
+
   DCHECK(driver->GetCompilerOptions().IsCompilationEnabled());
 
   Runtime* const runtime = Runtime::Current();
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 9b141cc..2bc8042 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -41,6 +41,7 @@
                                              bool compile) {
   std::unique_ptr<VerifiedMethod> verified_method(new VerifiedMethod);
   verified_method->has_verification_failures_ = method_verifier->HasFailures();
+  verified_method->has_runtime_throw_ = method_verifier->HasInstructionThatWillThrow();
   if (compile) {
     /* Generate a register map. */
     if (!verified_method->GenerateGcMap(method_verifier)) {
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 242e3df..bad4495 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -75,6 +75,10 @@
     return has_verification_failures_;
   }
 
+  bool HasRuntimeThrow() const {
+    return has_runtime_throw_;
+  }
+
   void SetStringInitPcRegMap(SafeMap<uint32_t, std::set<uint32_t>>& string_init_pc_reg_map) {
     string_init_pc_reg_map_ = string_init_pc_reg_map;
   }
@@ -121,6 +125,7 @@
   SafeCastSet safe_cast_set_;
 
   bool has_verification_failures_;
+  bool has_runtime_throw_ = false;
 
   // Copy of mapping generated by verifier of dex PCs of string init invocations
   // to the set of other registers that the receiver has been copied into.
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index e98e572..f3bda2f 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -165,6 +165,7 @@
   void StackArgsIntsFirstImpl();
   void StackArgsFloatsFirstImpl();
   void StackArgsMixedImpl();
+  void StackArgsSignExtendedMips64Impl();
 
   JNIEnv* env_;
   jmethodID jmethod_;
@@ -1715,4 +1716,49 @@
 
 JNI_TEST(StackArgsMixed)
 
+void Java_MyClassNatives_stackArgsSignExtendedMips64(JNIEnv*, jclass, jint i1, jint i2, jint i3,
+                                                     jint i4, jint i5, jint i6, jint i7, jint i8) {
+  EXPECT_EQ(i1, 1);
+  EXPECT_EQ(i2, 2);
+  EXPECT_EQ(i3, 3);
+  EXPECT_EQ(i4, 4);
+  EXPECT_EQ(i5, 5);
+  EXPECT_EQ(i6, 6);
+  EXPECT_EQ(i7, 7);
+  EXPECT_EQ(i8, -8);
+
+#if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+  // Mips64 ABI requires that arguments passed through stack be sign-extended 8B slots.
+  // First 8 arguments are passed through registers, check i7 and i8.
+  uint32_t stack1_high = *(&i7 + 1);
+  uint32_t stack2_high = *(&i8 + 1);
+
+  EXPECT_EQ(stack1_high, static_cast<uint32_t>(0));
+  EXPECT_EQ(stack2_high, static_cast<uint32_t>(0xffffffff));
+#else
+  LOG(INFO) << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
+            << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
+            << kRuntimeISA << std::endl;
+#endif
+}
+
+void JniCompilerTest::StackArgsSignExtendedMips64Impl() {
+  SetUpForTest(true, "stackArgsSignExtendedMips64", "(IIIIIIII)V",
+               reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsSignExtendedMips64));
+  jint i1 = 1;
+  jint i2 = 2;
+  jint i3 = 3;
+  jint i4 = 4;
+  jint i5 = 5;
+  jint i6 = 6;
+  jint i7 = 7;
+  jint i8 = -8;
+
+  env_->CallStaticVoidMethod(jklass_, jmethod_, i1, i2, i3, i4, i5, i6, i7, i8);
+}
+
+JNI_TEST(StackArgsSignExtendedMips64)
+
 }  // namespace art
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc
index 8100a29..daf7d67 100644
--- a/compiler/optimizing/boolean_simplifier.cc
+++ b/compiler/optimizing/boolean_simplifier.cc
@@ -141,6 +141,12 @@
   block->MergeWith(false_block);
   block->MergeWith(merge_block);
 
+  // No need to update any dominance information, as we are simplifying
+  // a simple diamond shape, where the join block is merged with the
+  // entry block. Any following blocks would have had the join block
+  // as a dominator, and `MergeWith` handles changing that to the
+  // entry block.
+
   // Remove the original condition if it is now unused.
   if (!if_condition->HasUses()) {
     if_condition->GetBlock()->RemoveInstructionOrPhi(if_condition);
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 900dabe..ebc0adc 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1180,9 +1180,7 @@
       }
     }
     ValueRange* narrowed_range = existing_range->Narrow(range);
-    if (narrowed_range != nullptr) {
-      GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
-    }
+    GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
   }
 
   // Special case that we may simultaneously narrow two MonotonicValueRange's to
@@ -1388,7 +1386,7 @@
     if (array_length->IsPhi()) {
       // Input 1 of the phi contains the real array.length once the loop body is
       // entered. That value will be used for bound analysis. The graph is still
-      // strickly in SSA form.
+      // strictly in SSA form.
       array_length = array_length->AsPhi()->InputAt(1)->AsArrayLength();
     }
 
@@ -1730,6 +1728,10 @@
         ValueBound upper = ValueBound(new_array, -right_const);
         ValueRange* range = new (GetGraph()->GetArena())
             ValueRange(GetGraph()->GetArena(), lower, upper);
+        ValueRange* existing_range = LookupValueRange(left, new_array->GetBlock());
+        if (existing_range != nullptr) {
+          range = existing_range->Narrow(range);
+        }
         GetValueRangeMap(new_array->GetBlock())->Overwrite(left->GetId(), range);
       }
     }
@@ -1780,7 +1782,13 @@
          it != first_constant_index_bounds_check_map_.end();
          ++it) {
       HBoundsCheck* bounds_check = it->second;
-      HArrayLength* array_length = bounds_check->InputAt(1)->AsArrayLength();
+      HInstruction* array_length = bounds_check->InputAt(1);
+      if (!array_length->IsArrayLength()) {
+        // Prior deoptimizations may have changed the array length to a phi.
+        // TODO(mingyao): propagate the range to the phi?
+        DCHECK(array_length->IsPhi()) << array_length->DebugName();
+        continue;
+      }
       HIntConstant* lower_bound_const_instr = nullptr;
       int32_t lower_bound_const = INT_MIN;
       size_t counter = 0;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index ed39923..b564aca 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -2062,8 +2062,13 @@
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_WIDE:
     case Instruction::MOVE_RESULT_OBJECT:
-      UpdateLocal(instruction.VRegA(), latest_result_);
-      latest_result_ = nullptr;
+      if (latest_result_ == nullptr) {
+        // Only dead code can lead to this situation, where the verifier
+        // does not reject the method.
+      } else {
+        UpdateLocal(instruction.VRegA(), latest_result_);
+        latest_result_ = nullptr;
+      }
       break;
 
     case Instruction::CMP_LONG: {
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index bfed1a8..4db3b43 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -180,7 +180,10 @@
                              std::function<void(HGraph*)> hook_before_codegen,
                              bool has_result,
                              Expected expected) {
-  graph->BuildDominatorTree();
+  // Tests may have already computed it.
+  if (graph->GetReversePostOrder().IsEmpty()) {
+    graph->BuildDominatorTree();
+  }
   SsaLivenessAnalysis liveness(graph, codegen);
   liveness.Analyze();
 
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 6fbe75e..2362cc1 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -67,6 +67,7 @@
   ArenaBitVector affected_loops(allocator, graph_->GetBlocks().Size(), false);
 
   MarkReachableBlocks(graph_->GetEntryBlock(), &live_blocks);
+  bool removed_one_or_more_blocks = false;
 
   // Remove all dead blocks. Iterate in post order because removal needs the
   // block's chain of dominators and nested loops need to be updated from the
@@ -83,9 +84,17 @@
       MaybeRecordDeadBlock(block);
       MarkLoopHeadersContaining(*block, &affected_loops);
       block->DisconnectAndDelete();
+      removed_one_or_more_blocks = true;
     }
   }
 
+  // If we removed at least one block, we need to recompute the full
+  // dominator tree.
+  if (removed_one_or_more_blocks) {
+    graph_->ClearDominanceInformation();
+    graph_->ComputeDominanceInformation();
+  }
+
   // Connect successive blocks created by dead branches. Order does not matter.
   for (HReversePostOrderIterator it(*graph_); !it.Done();) {
     HBasicBlock* block  = it.Current();
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index c01364a..88490d0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -116,9 +116,24 @@
   //     dominators and the reverse post order.
   SimplifyCFG();
 
-  // (5) Compute the immediate dominator of each block. We visit
-  //     the successors of a block only when all its forward branches
-  //     have been processed.
+  // (5) Compute the dominance information and the reverse post order.
+  ComputeDominanceInformation();
+}
+
+void HGraph::ClearDominanceInformation() {
+  for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+    it.Current()->ClearDominanceInformation();
+  }
+  reverse_post_order_.Reset();
+}
+
+void HBasicBlock::ClearDominanceInformation() {
+  dominated_blocks_.Reset();
+  dominator_ = nullptr;
+}
+
+void HGraph::ComputeDominanceInformation() {
+  DCHECK(reverse_post_order_.IsEmpty());
   GrowableArray<size_t> visits(arena_, blocks_.Size());
   visits.SetSize(blocks_.Size());
   reverse_post_order_.Add(entry_block_);
@@ -1037,8 +1052,7 @@
   }
   predecessors_.Reset();
 
-  // Disconnect the block from its successors and update their dominators
-  // and phis.
+  // Disconnect the block from its successors and update their phis.
   for (size_t i = 0, e = successors_.Size(); i < e; ++i) {
     HBasicBlock* successor = successors_.Get(i);
     // Delete this block from the list of predecessors.
@@ -1049,19 +1063,6 @@
     // dominator of `successor` which violates the order DCHECKed at the top.
     DCHECK(!successor->predecessors_.IsEmpty());
 
-    // Recompute the successor's dominator.
-    HBasicBlock* old_dominator = successor->GetDominator();
-    HBasicBlock* new_dominator = successor->predecessors_.Get(0);
-    for (size_t j = 1, f = successor->predecessors_.Size(); j < f; ++j) {
-      new_dominator = graph_->FindCommonDominator(
-          new_dominator, successor->predecessors_.Get(j));
-    }
-    if (old_dominator != new_dominator) {
-      successor->SetDominator(new_dominator);
-      old_dominator->RemoveDominatedBlock(successor);
-      new_dominator->AddDominatedBlock(successor);
-    }
-
     // Remove this block's entries in the successor's phis.
     if (successor->predecessors_.Size() == 1u) {
       // The successor has just one predecessor left. Replace phis with the only
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 394e3fc..b36d9b8 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -170,6 +170,9 @@
     return true;
   }
 
+  void ComputeDominanceInformation();
+  void ClearDominanceInformation();
+
   void BuildDominatorTree();
   void TransformToSsa();
   void SimplifyCFG();
@@ -547,11 +550,10 @@
     LOG(FATAL) << "Unreachable";
     UNREACHABLE();
   }
+  void ClearDominanceInformation();
 
   int NumberOfBackEdges() const {
-    return loop_information_ == nullptr
-        ? 0
-        : loop_information_->NumberOfBackEdges();
+    return IsLoopHeader() ? loop_information_->NumberOfBackEdges() : 0;
   }
 
   HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 810b4f8..8958932 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -618,7 +618,8 @@
                                             const DexFile& dex_file) const {
   CompilerDriver* compiler_driver = GetCompilerDriver();
   CompiledMethod* method = nullptr;
-  if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)) {
+  if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) &&
+      !compiler_driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()) {
      method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
                          method_idx, jclass_loader, dex_file);
   } else {
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index a8b55d1..5e49b93 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -839,7 +839,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
-    StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
     StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
@@ -855,7 +855,7 @@
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
-    StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
@@ -871,7 +871,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
-    StoreToOffset(kStoreWord, scratch, dest_base.AsMips64().AsGpuRegister(),
+    StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
                   dest_offset.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
@@ -894,7 +894,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
-    StoreToOffset(kStoreWord, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 5ae291a..d02ab14 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1052,9 +1052,12 @@
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset r1, 4
-    sub   sp, #8         @ space for return value argument
+    vpush {d0}           @ save fp return value
     .cfi_adjust_cfa_offset 8
-    strd r0, [sp]        @ r0/r1 -> [sp] for fpr_res
+    sub   sp, #8         @ space for return value argument. Note: AAPCS stack alignment is 8B, no
+                         @ need to align by 16.
+    .cfi_adjust_cfa_offset 8
+    vstr  d0, [sp]       @ d0 -> [sp] for fpr_res
     mov   r2, r0         @ pass return value as gpr_res
     mov   r3, r1
     mov   r0, r9         @ pass Thread::Current
@@ -1065,6 +1068,8 @@
 
     mov   r2, r0         @ link register saved by instrumentation
     mov   lr, r1         @ r1 is holding link register if we're to bounce to deoptimize
+    vpop  {d0}           @ restore fp return value
+    .cfi_adjust_cfa_offset -8
     pop   {r0, r1}       @ restore return value
     .cfi_adjust_cfa_offset -8
     .cfi_restore r0
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 7f68c6f..b662821 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1373,7 +1373,7 @@
     dla     $t9, art_quick_invoke_interface_trampoline
     .cpreturn
     jalr    $zero, $t9
-    lwu     $a0, MIRROR_LONG_ARRAY_DATA_OFFSET($a0)  # load the target method
+    ld      $a0, MIRROR_LONG_ARRAY_DATA_OFFSET($a0)  # load the target method
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 549eac2..45fb9c4 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -1188,7 +1188,7 @@
    * Create an over-sized buffer to hold the contents of "buf".  Copy it in,
    * filling in the area around it with guard data.
    */
-  static void* Create(const void* original_buf, size_t len, bool mod_okay) {
+  static void* Create(void* original_buf, size_t len, bool mod_okay) {
     const size_t new_len = LengthIncludingRedZones(len);
     uint8_t* const new_buf = DebugAlloc(new_len);
 
@@ -1227,13 +1227,14 @@
    * Create a guarded copy of a primitive array.  Modifications to the copied
    * data are allowed.  Returns a pointer to the copied data.
    */
-  static void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* is_copy) {
+  static void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* is_copy,
+                                   void* original_ptr) {
     ScopedObjectAccess soa(env);
 
     mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
     size_t component_size = a->GetClass()->GetComponentSize();
     size_t byte_count = a->GetLength() * component_size;
-    void* result = Create(a->GetRawData(component_size, 0), byte_count, true);
+    void* result = Create(original_ptr, byte_count, true);
     if (is_copy != nullptr) {
       *is_copy = JNI_TRUE;
     }
@@ -1244,22 +1245,22 @@
    * Perform the array "release" operation, which may or may not copy data
    * back into the managed heap, and may or may not release the underlying storage.
    */
-  static void* ReleaseGuardedPACopy(const char* function_name, JNIEnv* env, jarray java_array,
-                                   void* embedded_buf, int mode) {
+  static void* ReleaseGuardedPACopy(const char* function_name, JNIEnv* env,
+                                    jarray java_array ATTRIBUTE_UNUSED, void* embedded_buf,
+                                    int mode) {
     ScopedObjectAccess soa(env);
-    mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
-
     if (!GuardedCopy::Check(function_name, embedded_buf, true)) {
       return nullptr;
     }
+    GuardedCopy* const copy = FromEmbedded(embedded_buf);
+    void* original_ptr = copy->original_ptr_;
     if (mode != JNI_ABORT) {
-      size_t len = FromEmbedded(embedded_buf)->original_length_;
-      memcpy(a->GetRawData(a->GetClass()->GetComponentSize(), 0), embedded_buf, len);
+      memcpy(original_ptr, embedded_buf, copy->original_length_);
     }
     if (mode != JNI_COMMIT) {
-      return Destroy(embedded_buf);
+      Destroy(embedded_buf);
     }
-    return embedded_buf;
+    return original_ptr;
   }
 
 
@@ -1286,7 +1287,7 @@
   }
 
  private:
-  GuardedCopy(const void* original_buf, size_t len, uLong adler) :
+  GuardedCopy(void* original_buf, size_t len, uLong adler) :
     magic_(kGuardMagic), adler_(adler), original_ptr_(original_buf), original_length_(len) {
   }
 
@@ -1414,7 +1415,7 @@
 
   const uint32_t magic_;
   const uLong adler_;
-  const void* const original_ptr_;
+  void* const original_ptr_;
   const size_t original_length_;
 };
 const char* const GuardedCopy::kCanary = "JNI BUFFER RED ZONE";
@@ -2307,10 +2308,11 @@
     JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
     if (sc.Check(soa, true, "Eap", args)) {
       JniValueType result;
-      result.p = baseEnv(env)->GetPrimitiveArrayCritical(env, array, is_copy);
-      if (result.p != nullptr && soa.ForceCopy()) {
-        result.p = GuardedCopy::CreateGuardedPACopy(env, array, is_copy);
+      void* ptr = baseEnv(env)->GetPrimitiveArrayCritical(env, array, is_copy);
+      if (ptr != nullptr && soa.ForceCopy()) {
+        ptr = GuardedCopy::CreateGuardedPACopy(env, array, is_copy, ptr);
       }
+      result.p = ptr;
       if (sc.Check(soa, false, "p", &result)) {
         return const_cast<void*>(result.p);
       }
@@ -2325,7 +2327,7 @@
     JniValueType args[4] = {{.E = env}, {.a = array}, {.p = carray}, {.r = mode}};
     if (sc.Check(soa, true, "Eapr", args)) {
       if (soa.ForceCopy()) {
-        GuardedCopy::ReleaseGuardedPACopy(__FUNCTION__, env, array, carray, mode);
+        carray = GuardedCopy::ReleaseGuardedPACopy(__FUNCTION__, env, array, carray, mode);
       }
       baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
       JniValueType result;
@@ -3062,26 +3064,26 @@
     JniValueType args[3] = {{.E = env}, {.s = string}, {.p = is_copy}};
     if (sc.Check(soa, true, "Esp", args)) {
       JniValueType result;
+      void* ptr;
       if (utf) {
         CHECK(!critical);
-        result.u = baseEnv(env)->GetStringUTFChars(env, string, is_copy);
+        ptr = const_cast<char*>(baseEnv(env)->GetStringUTFChars(env, string, is_copy));
+        result.u = reinterpret_cast<char*>(ptr);
       } else {
-        if (critical) {
-          result.p = baseEnv(env)->GetStringCritical(env, string, is_copy);
-        } else {
-          result.p = baseEnv(env)->GetStringChars(env, string, is_copy);
-        }
+        ptr = const_cast<jchar*>(critical ? baseEnv(env)->GetStringCritical(env, string, is_copy) :
+            baseEnv(env)->GetStringChars(env, string, is_copy));
+        result.p = ptr;
       }
       // TODO: could we be smarter about not copying when local_is_copy?
-      if (result.p != nullptr && soa.ForceCopy()) {
+      if (ptr != nullptr && soa.ForceCopy()) {
         if (utf) {
           size_t length_in_bytes = strlen(result.u) + 1;
           result.u =
-              reinterpret_cast<const char*>(GuardedCopy::Create(result.u, length_in_bytes, false));
+              reinterpret_cast<const char*>(GuardedCopy::Create(ptr, length_in_bytes, false));
         } else {
           size_t length_in_bytes = baseEnv(env)->GetStringLength(env, string) * 2;
           result.p =
-              reinterpret_cast<const jchar*>(GuardedCopy::Create(result.p, length_in_bytes, false));
+              reinterpret_cast<const jchar*>(GuardedCopy::Create(ptr, length_in_bytes, false));
         }
         if (is_copy != nullptr) {
           *is_copy = JNI_TRUE;
@@ -3175,47 +3177,43 @@
     JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
     if (sc.Check(soa, true, "Eap", args) && sc.CheckPrimitiveArrayType(soa, array, type)) {
       JniValueType result;
+      void* ptr = nullptr;
       switch (type) {
         case Primitive::kPrimBoolean:
-          result.p = baseEnv(env)->GetBooleanArrayElements(env, down_cast<jbooleanArray>(array),
-                                                           is_copy);
+          ptr = baseEnv(env)->GetBooleanArrayElements(env, down_cast<jbooleanArray>(array),
+                                                      is_copy);
           break;
         case Primitive::kPrimByte:
-          result.p = baseEnv(env)->GetByteArrayElements(env, down_cast<jbyteArray>(array),
-                                                        is_copy);
+          ptr = baseEnv(env)->GetByteArrayElements(env, down_cast<jbyteArray>(array), is_copy);
           break;
         case Primitive::kPrimChar:
-          result.p = baseEnv(env)->GetCharArrayElements(env, down_cast<jcharArray>(array),
-                                                        is_copy);
+          ptr = baseEnv(env)->GetCharArrayElements(env, down_cast<jcharArray>(array), is_copy);
           break;
         case Primitive::kPrimShort:
-          result.p = baseEnv(env)->GetShortArrayElements(env, down_cast<jshortArray>(array),
-                                                         is_copy);
+          ptr = baseEnv(env)->GetShortArrayElements(env, down_cast<jshortArray>(array), is_copy);
           break;
         case Primitive::kPrimInt:
-          result.p = baseEnv(env)->GetIntArrayElements(env, down_cast<jintArray>(array), is_copy);
+          ptr = baseEnv(env)->GetIntArrayElements(env, down_cast<jintArray>(array), is_copy);
           break;
         case Primitive::kPrimLong:
-          result.p = baseEnv(env)->GetLongArrayElements(env, down_cast<jlongArray>(array),
-                                                        is_copy);
+          ptr = baseEnv(env)->GetLongArrayElements(env, down_cast<jlongArray>(array), is_copy);
           break;
         case Primitive::kPrimFloat:
-          result.p = baseEnv(env)->GetFloatArrayElements(env, down_cast<jfloatArray>(array),
-                                                         is_copy);
+          ptr = baseEnv(env)->GetFloatArrayElements(env, down_cast<jfloatArray>(array), is_copy);
           break;
         case Primitive::kPrimDouble:
-          result.p = baseEnv(env)->GetDoubleArrayElements(env, down_cast<jdoubleArray>(array),
-                                                          is_copy);
+          ptr = baseEnv(env)->GetDoubleArrayElements(env, down_cast<jdoubleArray>(array), is_copy);
           break;
         default:
           LOG(FATAL) << "Unexpected primitive type: " << type;
       }
-      if (result.p != nullptr && soa.ForceCopy()) {
-        result.p = GuardedCopy::CreateGuardedPACopy(env, array, is_copy);
+      if (ptr != nullptr && soa.ForceCopy()) {
+        ptr = GuardedCopy::CreateGuardedPACopy(env, array, is_copy, ptr);
         if (is_copy != nullptr) {
           *is_copy = JNI_TRUE;
         }
       }
+      result.p = ptr;
       if (sc.Check(soa, false, "p", &result)) {
         return const_cast<void*>(result.p);
       }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 57557e2..d428267 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -745,7 +745,7 @@
 
 void Heap::DecrementDisableMovingGC(Thread* self) {
   MutexLock mu(self, *gc_complete_lock_);
-  CHECK_GE(disable_moving_gc_count_, 0U);
+  CHECK_GT(disable_moving_gc_count_, 0U);
   --disable_moving_gc_count_;
 }
 
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index 0731f30..9d54eba 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -36,11 +36,11 @@
 }
 
 // The default SIGSTKSZ on linux is 8K.  If we do any logging in a signal
-// handler this is too small.  We allocate 16K instead or the minimum signal
-// stack size.
+// handler or do a stack unwind, this is too small.  We allocate 32K
+// instead of the minimum signal stack size.
 // TODO: We shouldn't do logging (with locks) in signal handlers.
 static constexpr int kHostAltSigStackSize =
-    16 * KB < MINSIGSTKSZ ? MINSIGSTKSZ : 16 * KB;
+    32 * KB < MINSIGSTKSZ ? MINSIGSTKSZ : 32 * KB;
 
 void Thread::SetUpAlternateSignalStack() {
   // Create and set an alternate signal stack.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 5436100..bcad9b6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3728,6 +3728,7 @@
   } else {
     const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
     if (array_type.IsZero()) {
+      have_pending_runtime_throw_failure_ = true;
       // Null array class; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type. TODO: have a proper notion of bottom here.
       if (!is_primitive || insn_type.IsCategory1Types()) {
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index cd691a3..204b18e 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -244,6 +244,10 @@
   bool HasCheckCasts() const;
   bool HasVirtualOrInterfaceInvokes() const;
   bool HasFailures() const;
+  bool HasInstructionThatWillThrow() const {
+    return have_pending_runtime_throw_failure_;
+  }
+
   const RegType& ResolveCheckedClass(uint32_t class_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Returns the method of a quick invoke or null if it cannot be found.
diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java
index 7c3fd25..a1e62b3 100644
--- a/test/401-optimizing-compiler/src/Main.java
+++ b/test/401-optimizing-compiler/src/Main.java
@@ -110,6 +110,11 @@
     if (result != 42) {
       throw new Error("Unexpected result: " + result);
     }
+
+    String s = $opt$StringInit();
+    if (!s.equals("hello world")) {
+      throw new Error("Unexpected string: " + s);
+    }
   }
 
   public static void invokePrivate() {
@@ -230,5 +235,9 @@
     return array.length;
   }
 
+  public static String $opt$StringInit() {
+    return new String("hello world");
+  }
+
   Object o;
 }
diff --git a/test/499-bce-phi-array-length/src/Main.java b/test/499-bce-phi-array-length/src/Main.java
index c8c84a1..e917bc1 100644
--- a/test/499-bce-phi-array-length/src/Main.java
+++ b/test/499-bce-phi-array-length/src/Main.java
@@ -32,11 +32,33 @@
     return result;
   }
 
+  public static int bar(int start, int[] array) {
+    int result = 0;
+    for (int i = start; i < 3; i++) {
+      result += array[i];
+      for (int j = 0; j < 2; ++j) {
+        result += array[j];
+        // The following operations would lead to BCE wanting to add another
+        // deoptimization, but it crashed assuming the input of a `HBoundsCheck`
+        // must be a `HArrayLength`.
+        result += array[0];
+        result += array[1];
+        result += array[2];
+      }
+    }
+    return result;
+  }
+
   public static void main(String[] args) {
     int[] a = new int[] { 1, 2, 3, 4, 5 };
     int result = foo(1, a);
     if (result != 11) {
       throw new Error("Got " + result + ", expected " + 11);
     }
+
+    result = bar(1, a);
+    if (result != 35) {
+      throw new Error("Got " + result + ", expected " + 35);
+    }
   }
 }
diff --git a/test/513-array-deopt/src/Main.java b/test/513-array-deopt/src/Main.java
index a0ae4c3..5ee4d55 100644
--- a/test/513-array-deopt/src/Main.java
+++ b/test/513-array-deopt/src/Main.java
@@ -19,19 +19,36 @@
     a[0] = 0;
     a[1] = 0;
     a[2] = 0;
-    // Up to this point, we record that the lower bound is 2.
+    // Up to this point, we record that the lower bound (inclusive) is 3.
     // The next instruction will record that the lower bound is 5.
     // The deoptimization code used to assume the lower bound has
-    // to be check it will add for the deoptimization (here, it
-    // would be 2).
+    // to be the one it will add for the deoptimization check (here, it
+    // would be 3).
     return new int[a.length - 5];
   }
 
+  public static int[] foo(int[] a) {
+    a[0] = 0;
+    a[1] = 0;
+    a[2] = 0;
+    // Up to this point, we record that the lower bound (inclusive) is 3.
+    // The next instruction will record that the lower bound is 1.
+    // The deoptimization code used to assume the lower bound has
+    // to be the one it will add for the deoptimization check (here, it
+    // would be 3).
+    return new int[a.length - 1];
+  }
+
   public static void main(String[] args) {
     int[] a = new int[5];
-    a = bar(a);
-    if (a.length != 0) {
-      throw new Error("Expected 0, got " + a.length);
+    int[] result = bar(a);
+    if (result.length != 0) {
+      throw new Error("Expected 0, got " + result.length);
+    }
+
+    result = foo(a);
+    if (result.length != 4) {
+      throw new Error("Expected 5, got " + result.length);
     }
   }
 }
diff --git a/test/515-dce-dominator/expected.txt b/test/515-dce-dominator/expected.txt
new file mode 100644
index 0000000..ccaf6f8
--- /dev/null
+++ b/test/515-dce-dominator/expected.txt
@@ -0,0 +1 @@
+Enter
diff --git a/test/515-dce-dominator/info.txt b/test/515-dce-dominator/info.txt
new file mode 100644
index 0000000..af706e0
--- /dev/null
+++ b/test/515-dce-dominator/info.txt
@@ -0,0 +1,3 @@
+Regression test for the DCE phase of optimizing, where
+we need to recompute the full dominance information of
+the graph when blocks get removed.
diff --git a/test/515-dce-dominator/smali/Dominator.smali b/test/515-dce-dominator/smali/Dominator.smali
new file mode 100644
index 0000000..a504aba
--- /dev/null
+++ b/test/515-dce-dominator/smali/Dominator.smali
@@ -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.
+
+.class public LDominator;
+
+.super Ljava/lang/Object;
+
+.method public static method(I)I
+   .registers 2
+   const/4 v0, 0
+   :b1
+   if-ne v0, v0, :b3
+   :b2
+   if-eq v0, p0, :b4
+   :b5
+   if-eq v0, p0, :b2
+   goto :b6
+   :b4
+   goto :b7
+   :b3
+   goto :b6
+   :b6
+   goto :b7
+   :b7
+   return v1
+.end method
diff --git a/test/515-dce-dominator/src/Main.java b/test/515-dce-dominator/src/Main.java
new file mode 100644
index 0000000..bf9ee25
--- /dev/null
+++ b/test/515-dce-dominator/src/Main.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    // Workaround for b/18051191.
+    System.out.println("Enter");
+    Class<?> c = Class.forName("Dominator");
+    Method m = c.getMethod("method", int.class);
+    Object[] arguments = { 5 };
+    m.invoke(null, arguments);
+  }
+}
diff --git a/test/516-dead-move-result/expected.txt b/test/516-dead-move-result/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/516-dead-move-result/expected.txt
diff --git a/test/516-dead-move-result/info.txt b/test/516-dead-move-result/info.txt
new file mode 100644
index 0000000..49d9489
--- /dev/null
+++ b/test/516-dead-move-result/info.txt
@@ -0,0 +1,3 @@
+Regression test for the graph builder in optimizing,
+where a move-result was bogus, but it passed the verifier
+because it was dead code.
diff --git a/test/516-dead-move-result/smali/MoveResult.smali b/test/516-dead-move-result/smali/MoveResult.smali
new file mode 100644
index 0000000..9650b58
--- /dev/null
+++ b/test/516-dead-move-result/smali/MoveResult.smali
@@ -0,0 +1,25 @@
+# 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 LMoveResult;
+
+.super Ljava/lang/Object;
+
+.method public static method()V
+   .registers 1
+   goto :b1
+   move-result v0
+   :b1
+   return-void
+.end method
diff --git a/test/516-dead-move-result/src/Main.java b/test/516-dead-move-result/src/Main.java
new file mode 100644
index 0000000..90580a8
--- /dev/null
+++ b/test/516-dead-move-result/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class Main {
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("MoveResult");
+    Method m = c.getMethod("method");
+    Object[] arguments = { };
+    m.invoke(null, arguments);
+  }
+}
diff --git a/test/518-null-array-get/expected.txt b/test/518-null-array-get/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/518-null-array-get/expected.txt
diff --git a/test/518-null-array-get/info.txt b/test/518-null-array-get/info.txt
new file mode 100644
index 0000000..407f590
--- /dev/null
+++ b/test/518-null-array-get/info.txt
@@ -0,0 +1,3 @@
+Regression test for Quick and Optimizing that used
+to crash on an aget-object + int-to-byte sequence
+(accepted by the verifier in the case the array was null).
diff --git a/test/518-null-array-get/smali/NullArray.smali b/test/518-null-array-get/smali/NullArray.smali
new file mode 100644
index 0000000..52abc38
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArray.smali
@@ -0,0 +1,26 @@
+# 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 LNullArray;
+
+.super Ljava/lang/Object;
+
+.method public static method()B
+   .registers 2
+   const/4 v0, 0
+   const/4 v1, 0
+   aget-object v0, v0, v1
+   int-to-byte v0, v0
+   return v0
+.end method
diff --git a/test/518-null-array-get/src/Main.java b/test/518-null-array-get/src/Main.java
new file mode 100644
index 0000000..66e50aa
--- /dev/null
+++ b/test/518-null-array-get/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.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("NullArray");
+    Method m = c.getMethod("method");
+    Object[] arguments = { };
+    try {
+      m.invoke(null, arguments);
+      throw new Error("Expected an InvocationTargetException");
+    } catch (InvocationTargetException e) {
+      if (!(e.getCause() instanceof NullPointerException)) {
+        throw new Error("Expected a NullPointerException");
+      }
+    }
+  }
+}
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 8b4a9a4..19c13f7 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -94,6 +94,9 @@
         float f4, int i5, float f5, int i6, float f6, int i7, float f7, int i8, float f8, int i9,
         float f9, int i10, float f10);
 
+    native static void stackArgsSignExtendedMips64(int i1, int i2, int i3, int i4, int i5, int i6,
+        int i7, int i8);
+
     static native double logD(double d);
     static native float logF(float f);
     static native boolean returnTrue();