Merge "Support callee save floating point registers on x64."
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 2a6dfef..d5889f5 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1048,9 +1048,13 @@
     // TODO - add Mips implementation.
     return false;
   }
+  RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info);  // result reg
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src_i = info->args[0];
   RegLocation rl_i = IsWide(size) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
-  RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info);  // result reg
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (IsWide(size)) {
     if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) {
@@ -1080,9 +1084,13 @@
 }
 
 bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
+  RegLocation rl_dest = InlineTarget(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src = info->args[0];
   rl_src = LoadValue(rl_src, kCoreReg);
-  RegLocation rl_dest = InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   RegStorage sign_reg = AllocTemp();
   // abs(x) = y<=x>>31, (x+y)^y.
@@ -1094,9 +1102,13 @@
 }
 
 bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
+  RegLocation rl_dest = InlineTargetWide(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src = info->args[0];
   rl_src = LoadValueWide(rl_src, kCoreReg);
-  RegLocation rl_dest = InlineTargetWide(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
 
   // If on x86 or if we would clobber a register needed later, just copy the source first.
@@ -1171,8 +1183,12 @@
     // TODO - add Mips implementation
     return false;
   }
-  RegLocation rl_src = info->args[0];
   RegLocation rl_dest = InlineTarget(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
+  RegLocation rl_src = info->args[0];
   StoreValue(rl_dest, rl_src);
   return true;
 }
@@ -1182,8 +1198,12 @@
     // TODO - add Mips implementation
     return false;
   }
-  RegLocation rl_src = info->args[0];
   RegLocation rl_dest = InlineTargetWide(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
+  RegLocation rl_src = info->args[0];
   StoreValueWide(rl_dest, rl_src);
   return true;
 }
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 4825db6..89c5648 100755
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -599,8 +599,12 @@
 }
 
 bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
-  RegLocation rl_src = info->args[0];
   RegLocation rl_dest = InlineTargetWide(info);  // double place for result
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
+  RegLocation rl_src = info->args[0];
   rl_src = LoadValueWide(rl_src, kFPReg);
   RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
   NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
@@ -722,9 +726,13 @@
 
 bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
   if (is_double) {
+    RegLocation rl_dest = InlineTargetWide(info);
+    if (rl_dest.s_reg_low == INVALID_SREG) {
+      // Result is unused, the code is dead. Inlining successful, no code generated.
+      return true;
+    }
     RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
     RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
-    RegLocation rl_dest = InlineTargetWide(info);
     RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
 
     // Avoid src2 corruption by OpRegCopyWide.
@@ -775,9 +783,13 @@
     branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
     StoreValueWide(rl_dest, rl_result);
   } else {
+    RegLocation rl_dest = InlineTarget(info);
+    if (rl_dest.s_reg_low == INVALID_SREG) {
+      // Result is unused, the code is dead. Inlining successful, no code generated.
+      return true;
+    }
     RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
     RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
-    RegLocation rl_dest = InlineTarget(info);
     RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
 
     // Avoid src2 corruption by OpRegCopyWide.
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index ba9c611..03156dc 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -948,12 +948,16 @@
   }
 
   // Get the two arguments to the invoke and place them in GP registers.
+  RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src1 = info->args[0];
   RegLocation rl_src2 = (is_long) ? info->args[2] : info->args[1];
   rl_src1 = (is_long) ? LoadValueWide(rl_src1, kCoreReg) : LoadValue(rl_src1, kCoreReg);
   rl_src2 = (is_long) ? LoadValueWide(rl_src2, kCoreReg) : LoadValue(rl_src2, kCoreReg);
 
-  RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
 
   /*
@@ -988,6 +992,11 @@
 }
 
 bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+  RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src_address = info->args[0];  // long address
   RegLocation rl_address;
   if (!cu_->target64) {
@@ -996,7 +1005,6 @@
   } else {
     rl_address = LoadValueWide(rl_src_address, kCoreReg);
   }
-  RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   // Unaligned access is allowed on x86.
   LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
@@ -1238,10 +1246,14 @@
 }
 
 bool X86Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
+  RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
+  if (rl_dest.s_reg_low == INVALID_SREG) {
+    // Result is unused, the code is dead. Inlining successful, no code generated.
+    return true;
+  }
   RegLocation rl_src_i = info->args[0];
   RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg)
                                    : LoadValue(rl_src_i, kCoreReg);
-  RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (size == k64) {
     if (cu_->instruction_set == kX86_64) {
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 291b14c..4d74c4e 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -17,10 +17,10 @@
 #include "graph_checker.h"
 
 #include <map>
-#include <sstream>
 #include <string>
 
 #include "base/bit_vector-inl.h"
+#include "base/stringprintf.h"
 
 namespace art {
 
@@ -45,15 +45,11 @@
       }
     }
     if (p_count_in_block_predecessors != block_count_in_p_successors) {
-      std::stringstream error;
-      error << "Block " << block->GetBlockId()
-            << " lists " << p_count_in_block_predecessors
-            << " occurrences of block " << p->GetBlockId()
-            << " in its predecessors, whereas block " << p->GetBlockId()
-            << " lists " << block_count_in_p_successors
-            << " occurrences of block " << block->GetBlockId()
-            << " in its successors.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
+          "block %d lists %zu occurrences of block %d in its successors.",
+          block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
+          p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
     }
   }
 
@@ -75,35 +71,27 @@
       }
     }
     if (s_count_in_block_successors != block_count_in_s_predecessors) {
-      std::stringstream error;
-      error << "Block " << block->GetBlockId()
-            << " lists " << s_count_in_block_successors
-            << " occurrences of block " << s->GetBlockId()
-            << " in its successors, whereas block " << s->GetBlockId()
-            << " lists " << block_count_in_s_predecessors
-            << " occurrences of block " << block->GetBlockId()
-            << " in its predecessors.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Block %d lists %zu occurrences of block %d in its successors, whereas "
+          "block %d lists %zu occurrences of block %d in its predecessors.",
+          block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
+          s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
     }
   }
 
   // Ensure `block` ends with a branch instruction.
   HInstruction* last_inst = block->GetLastInstruction();
   if (last_inst == nullptr || !last_inst->IsControlFlow()) {
-    std::stringstream error;
-    error  << "Block " << block->GetBlockId()
-           << " does not end with a branch instruction.";
-    errors_.push_back(error.str());
+    AddError(StringPrintf("Block %d does not end with a branch instruction.",
+                          block->GetBlockId()));
   }
 
   // Visit this block's list of phis.
   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     // Ensure this block's list of phis contains only phis.
     if (!it.Current()->IsPhi()) {
-      std::stringstream error;
-      error << "Block " << current_block_->GetBlockId()
-            << " has a non-phi in its phi list.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf("Block %d has a non-phi in its phi list.",
+                            current_block_->GetBlockId()));
     }
     it.Current()->Accept(this);
   }
@@ -113,10 +101,8 @@
        it.Advance()) {
     // Ensure this block's list of instructions does not contains phis.
     if (it.Current()->IsPhi()) {
-      std::stringstream error;
-      error << "Block " << current_block_->GetBlockId()
-            << " has a phi in its non-phi list.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf("Block %d has a phi in its non-phi list.",
+                            current_block_->GetBlockId()));
     }
     it.Current()->Accept(this);
   }
@@ -124,30 +110,24 @@
 
 void GraphChecker::VisitInstruction(HInstruction* instruction) {
   if (seen_ids_.IsBitSet(instruction->GetId())) {
-    std::stringstream error;
-    error << "Duplicate id in graph " << instruction->GetId() << ".";
-    errors_.push_back(error.str());
+    AddError(StringPrintf("Instruction id %d is duplicate in graph.",
+                          instruction->GetId()));
   } else {
     seen_ids_.SetBit(instruction->GetId());
   }
 
   // Ensure `instruction` is associated with `current_block_`.
-  if (instruction->GetBlock() != current_block_) {
-    std::stringstream error;
-    if (instruction->IsPhi()) {
-      error << "Phi ";
-    } else {
-      error << "Instruction ";
-    }
-    error << instruction->GetId() << " in block "
-          << current_block_->GetBlockId();
-    if (instruction->GetBlock() != nullptr) {
-      error << " associated with block "
-            << instruction->GetBlock()->GetBlockId() << ".";
-    } else {
-      error << " not associated with any block.";
-    }
-    errors_.push_back(error.str());
+  if (instruction->GetBlock() == nullptr) {
+    AddError(StringPrintf("%s %d in block %d not associated with any block.",
+                          instruction->IsPhi() ? "Phi" : "Instruction",
+                          instruction->GetId(),
+                          current_block_->GetBlockId()));
+  } else if (instruction->GetBlock() != current_block_) {
+    AddError(StringPrintf("%s %d in block %d associated with block %d.",
+                          instruction->IsPhi() ? "Phi" : "Instruction",
+                          instruction->GetId(),
+                          current_block_->GetBlockId(),
+                          instruction->GetBlock()->GetBlockId()));
   }
 
   // Ensure the inputs of `instruction` are defined in a block of the graph.
@@ -158,11 +138,10 @@
         ? input->GetBlock()->GetPhis()
         : input->GetBlock()->GetInstructions();
     if (!list.Contains(input)) {
-      std::stringstream error;
-      error << "Input " << input->GetId()
-            << " of instruction " << instruction->GetId()
-            << " is not defined in a basic block of the control-flow graph.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf("Input %d of instruction %d is not defined "
+                            "in a basic block of the control-flow graph.",
+                            input->GetId(),
+                            instruction->GetId()));
     }
   }
 
@@ -174,11 +153,10 @@
         ? use->GetBlock()->GetPhis()
         : use->GetBlock()->GetInstructions();
     if (!list.Contains(use)) {
-      std::stringstream error;
-      error << "User " << use->GetId()
-            << " of instruction " << instruction->GetId()
-            << " is not defined in a basic block of the control-flow graph.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf("User %d of instruction %d is not defined "
+                            "in a basic block of the control-flow graph.",
+                            use->GetId(),
+                            instruction->GetId()));
     }
   }
 }
@@ -193,10 +171,9 @@
     for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
       HBasicBlock* successor = block->GetSuccessors().Get(j);
       if (successor->GetPredecessors().Size() > 1) {
-        std::stringstream error;
-        error << "Critical edge between blocks " << block->GetBlockId()
-              << " and "  << successor->GetBlockId() << ".";
-        errors_.push_back(error.str());
+        AddError(StringPrintf("Critical edge between blocks %d and %d.",
+                              block->GetBlockId(),
+                              successor->GetBlockId()));
       }
     }
   }
@@ -212,47 +189,52 @@
   // Ensure the pre-header block is first in the list of
   // predecessors of a loop header.
   if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
-    std::stringstream error;
-    error << "Loop pre-header is not the first predecessor of the loop header "
-          << id << ".";
-    errors_.push_back(error.str());
+    AddError(StringPrintf(
+        "Loop pre-header is not the first predecessor of the loop header %d.",
+        id));
   }
 
   // Ensure the loop header has only two predecessors and that only the
   // second one is a back edge.
-  if (loop_header->GetPredecessors().Size() < 2) {
-    std::stringstream error;
-    error << "Loop header " << id << " has less than two predecessors.";
-    errors_.push_back(error.str());
-  } else if (loop_header->GetPredecessors().Size() > 2) {
-    std::stringstream error;
-    error << "Loop header " << id << " has more than two predecessors.";
-    errors_.push_back(error.str());
+  size_t num_preds = loop_header->GetPredecessors().Size();
+  if (num_preds < 2) {
+    AddError(StringPrintf(
+        "Loop header %d has less than two predecessors: %zu.",
+        id,
+        num_preds));
+  } else if (num_preds > 2) {
+    AddError(StringPrintf(
+        "Loop header %d has more than two predecessors: %zu.",
+        id,
+        num_preds));
   } else {
     HLoopInformation* loop_information = loop_header->GetLoopInformation();
     HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
     if (loop_information->IsBackEdge(first_predecessor)) {
-      std::stringstream error;
-      error << "First predecessor of loop header " << id << " is a back edge.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "First predecessor of loop header %d is a back edge.",
+          id));
     }
     HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
     if (!loop_information->IsBackEdge(second_predecessor)) {
-      std::stringstream error;
-      error << "Second predecessor of loop header " << id
-            << " is not a back edge.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Second predecessor of loop header %d is not a back edge.",
+          id));
     }
   }
 
   // Ensure there is only one back edge per loop.
   size_t num_back_edges =
     loop_header->GetLoopInformation()->GetBackEdges().Size();
-  if (num_back_edges != 1) {
-      std::stringstream error;
-      error << "Loop defined by header " << id << " has "
-            << num_back_edges << " back edge(s).";
-      errors_.push_back(error.str());
+  if (num_back_edges == 0) {
+    AddError(StringPrintf(
+        "Loop defined by header %d has no back edge.",
+        id));
+  } else if (num_back_edges > 1) {
+    AddError(StringPrintf(
+        "Loop defined by header %d has several back edges: %zu.",
+        id,
+        num_back_edges));
   }
 
   // Ensure all blocks in the loop are dominated by the loop header.
@@ -261,10 +243,9 @@
   for (uint32_t i : loop_blocks.Indexes()) {
     HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
     if (!loop_header->Dominates(loop_block)) {
-      std::stringstream error;
-      error << "Loop block " << loop_block->GetBlockId()
-            << " not dominated by loop header " << id;
-      errors_.push_back(error.str());
+      AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
+                            loop_block->GetBlockId(),
+                            id));
     }
   }
 }
@@ -277,12 +258,10 @@
        !use_it.Done(); use_it.Advance()) {
     HInstruction* use = use_it.Current()->GetUser();
     if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
-      std::stringstream error;
-      error << "Instruction " << instruction->GetId()
-            << " in block " << current_block_->GetBlockId()
-            << " does not dominate use " << use->GetId()
-            << " in block " << use->GetBlock()->GetBlockId() << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf("Instruction %d in block %d does not dominate "
+                            "use %d in block %d.",
+                            instruction->GetId(), current_block_->GetBlockId(),
+                            use->GetId(), use->GetBlock()->GetBlockId()));
     }
   }
 
@@ -294,13 +273,12 @@
       HInstruction* env_instruction = environment->GetInstructionAt(i);
       if (env_instruction != nullptr
           && !env_instruction->StrictlyDominates(instruction)) {
-        std::stringstream error;
-        error << "Instruction " << env_instruction->GetId()
-              << " in environment of instruction " << instruction->GetId()
-              << " from block " << current_block_->GetBlockId()
-              << " does not dominate instruction " << instruction->GetId()
-              << ".";
-        errors_.push_back(error.str());
+        AddError(StringPrintf("Instruction %d in environment of instruction %d "
+                              "from block %d does not dominate instruction %d.",
+                              env_instruction->GetId(),
+                              instruction->GetId(),
+                              current_block_->GetBlockId(),
+                              instruction->GetId()));
       }
     }
   }
@@ -311,25 +289,21 @@
 
   // Ensure the first input of a phi is not itself.
   if (phi->InputAt(0) == phi) {
-      std::stringstream error;
-      error << "Loop phi " << phi->GetId()
-            << " in block " << phi->GetBlock()->GetBlockId()
-            << " is its own first input.";
-      errors_.push_back(error.str());
+    AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
+                          phi->GetId(),
+                          phi->GetBlock()->GetBlockId()));
   }
 
-  // Ensure the number of phi inputs is the same as the number of
+  // Ensure the number of inputs of a phi is the same as the number of
   // its predecessors.
   const GrowableArray<HBasicBlock*>& predecessors =
     phi->GetBlock()->GetPredecessors();
   if (phi->InputCount() != predecessors.Size()) {
-    std::stringstream error;
-    error << "Phi " << phi->GetId()
-          << " in block " << phi->GetBlock()->GetBlockId()
-          << " has " << phi->InputCount() << " inputs, but block "
-          << phi->GetBlock()->GetBlockId() << " has "
-          << predecessors.Size() << " predecessors.";
-    errors_.push_back(error.str());
+    AddError(StringPrintf(
+        "Phi %d in block %d has %zu inputs, "
+        "but block %d has %zu predecessors.",
+        phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
+        phi->GetBlock()->GetBlockId(), predecessors.Size()));
   } else {
     // Ensure phi input at index I either comes from the Ith
     // predecessor or from a block that dominates this predecessor.
@@ -338,13 +312,11 @@
       HBasicBlock* predecessor = predecessors.Get(i);
       if (!(input->GetBlock() == predecessor
             || input->GetBlock()->Dominates(predecessor))) {
-        std::stringstream error;
-        error << "Input " << input->GetId() << " at index " << i
-              << " of phi " << phi->GetId()
-              << " from block " << phi->GetBlock()->GetBlockId()
-              << " is not defined in predecessor number " << i
-              << " nor in a block dominating it.";
-        errors_.push_back(error.str());
+        AddError(StringPrintf(
+            "Input %d at index %zu of phi %d from block %d is not defined in "
+            "predecessor number %zu nor in a block dominating it.",
+            input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
+            i));
       }
     }
   }
@@ -369,69 +341,61 @@
   if (input->IsIntConstant()) {
     int value = input->AsIntConstant()->GetValue();
     if (value != 0 && value != 1) {
-      std::stringstream error;
-      error << "If instruction " << instruction->GetId()
-            << " has a non-boolean constant input whose value is: "
-            << value << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "If instruction %d has a non-Boolean constant input "
+          "whose value is: %d.",
+          instruction->GetId(),
+          value));
     }
   } else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) {
-    std::stringstream error;
-    error << "If instruction " << instruction->GetId()
-          << " has a non-boolean input type: "
-          << instruction->InputAt(0)->GetType() << ".";
-    errors_.push_back(error.str());
+    AddError(StringPrintf(
+        "If instruction %d has a non-Boolean input type: %s.",
+        instruction->GetId(),
+        Primitive::PrettyDescriptor(instruction->InputAt(0)->GetType())));
   }
 }
 
 void SSAChecker::VisitCondition(HCondition* op) {
   VisitInstruction(op);
   if (op->GetType() != Primitive::kPrimBoolean) {
-    std::stringstream error;
-    error << "Condition " << op->DebugName() << " " << op->GetId()
-          << " has a non-boolean result type: "
-          << op->GetType() << ".";
-    errors_.push_back(error.str());
+    AddError(StringPrintf(
+        "Condition %s %d has a non-Boolean result type: %s.",
+        op->DebugName(), op->GetId(),
+        Primitive::PrettyDescriptor(op->GetType())));
   }
   HInstruction* lhs = op->InputAt(0);
   HInstruction* rhs = op->InputAt(1);
   if (lhs->GetType() == Primitive::kPrimNot) {
     if (!op->IsEqual() && !op->IsNotEqual()) {
-      std::stringstream error;
-      error << "Condition " << op->DebugName() << " " << op->GetId()
-            << " uses an object as left-hand side input.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Condition %s %d uses an object as left-hand side input.",
+          op->DebugName(), op->GetId()));
     }
     if (rhs->IsIntConstant() && rhs->AsIntConstant()->GetValue() != 0) {
-      std::stringstream error;
-      error << "Condition " << op->DebugName() << " " << op->GetId()
-            << " compares an object with a non-0 integer: "
-            << rhs->AsIntConstant()->GetValue()
-            << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Condition %s %d compares an object with a non-zero integer: %d.",
+          op->DebugName(), op->GetId(),
+          rhs->AsIntConstant()->GetValue()));
     }
   } else if (rhs->GetType() == Primitive::kPrimNot) {
     if (!op->IsEqual() && !op->IsNotEqual()) {
-      std::stringstream error;
-      error << "Condition " << op->DebugName() << " " << op->GetId()
-            << " uses an object as right-hand side input.";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Condition %s %d uses an object as right-hand side input.",
+          op->DebugName(), op->GetId()));
     }
     if (lhs->IsIntConstant() && lhs->AsIntConstant()->GetValue() != 0) {
-      std::stringstream error;
-      error << "Condition " << op->DebugName() << " " << op->GetId()
-            << " compares a non-0 integer with an object: "
-            << lhs->AsIntConstant()->GetValue()
-            << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Condition %s %d compares a non-zero integer with an object: %d.",
+          op->DebugName(), op->GetId(),
+          lhs->AsIntConstant()->GetValue()));
     }
   } else if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
-    std::stringstream error;
-    error << "Condition " << op->DebugName() << " " << op->GetId()
-          << " has inputs of different type: "
-          << lhs->GetType() << ", and " << rhs->GetType()
-          << ".";
-    errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Condition %s %d has inputs of different types: "
+          "%s, and %s.",
+          op->DebugName(), op->GetId(),
+          Primitive::PrettyDescriptor(lhs->GetType()),
+          Primitive::PrettyDescriptor(rhs->GetType())));
   }
 }
 
@@ -439,41 +403,40 @@
   VisitInstruction(op);
   if (op->IsUShr() || op->IsShr() || op->IsShl()) {
     if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
-      std::stringstream error;
-      error << "Shift operation " << op->DebugName() << " " << op->GetId()
-            << " has a non-int kind second input: "
-            << op->InputAt(1)->DebugName() << " of type " << op->InputAt(1)->GetType()
-            << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Shift operation %s %d has a non-int kind second input: "
+          "%s of type %s.",
+          op->DebugName(), op->GetId(),
+          op->InputAt(1)->DebugName(),
+          Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
     }
   } else {
     if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
-      std::stringstream error;
-      error << "Binary operation " << op->DebugName() << " " << op->GetId()
-            << " has inputs of different type: "
-            << op->InputAt(0)->GetType() << ", and " << op->InputAt(1)->GetType()
-            << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Binary operation %s %d has inputs of different types: "
+          "%s, and %s.",
+          op->DebugName(), op->GetId(),
+          Primitive::PrettyDescriptor(op->InputAt(0)->GetType()),
+          Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
     }
   }
 
   if (op->IsCompare()) {
     if (op->GetType() != Primitive::kPrimInt) {
-      std::stringstream error;
-      error << "Compare operation " << op->GetId()
-            << " has a non-int result type: "
-            << op->GetType() << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Compare operation %d has a non-int result type: %s.",
+          op->GetId(),
+          Primitive::PrettyDescriptor(op->GetType())));
     }
   } else {
     // Use the first input, so that we can also make this check for shift operations.
     if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
-      std::stringstream error;
-      error << "Binary operation " << op->DebugName() << " " << op->GetId()
-            << " has a result type different than its input type: "
-            << op->GetType() << ", and " << op->InputAt(1)->GetType()
-            << ".";
-      errors_.push_back(error.str());
+      AddError(StringPrintf(
+          "Binary operation %s %d has a result type different "
+          "from its input type: %s vs %s.",
+          op->DebugName(), op->GetId(),
+          Primitive::PrettyDescriptor(op->GetType()),
+          Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
     }
   }
 }
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index ae1557b..5ec3003 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -60,6 +60,11 @@
   }
 
  protected:
+  // Report a new error.
+  void AddError(const std::string& error) {
+    errors_.push_back(error);
+  }
+
   ArenaAllocator* const allocator_;
   // The block currently visited.
   HBasicBlock* current_block_ = nullptr;
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 6c86c7b..2059a96 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -48,30 +48,6 @@
 
 namespace art {
 
-static InstructionSet ElfISAToInstructionSet(Elf32_Word isa, Elf32_Word e_flags) {
-  switch (isa) {
-    case EM_ARM:
-      return kArm;
-    case EM_AARCH64:
-      return kArm64;
-    case EM_386:
-      return kX86;
-    case EM_X86_64:
-      return kX86_64;
-    case EM_MIPS:
-      if (((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2) ||
-          ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6)) {
-        return kMips;
-      } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
-        return kMips64;
-      } else {
-        return kNone;
-      }
-    default:
-      return kNone;
-  }
-}
-
 static bool LocationToFilename(const std::string& location, InstructionSet isa,
                                std::string* filename) {
   bool has_system = false;
@@ -219,7 +195,7 @@
       LOG(ERROR) << "unable to read elf header";
       return false;
     }
-    isa = ElfISAToInstructionSet(elf_hdr.e_machine, elf_hdr.e_flags);
+    isa = GetInstructionSetFromELF(elf_hdr.e_machine, elf_hdr.e_flags);
   }
   const char* isa_name = GetInstructionSetString(isa);
   std::string image_filename;
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
index 5ab461b..81ca010 100644
--- a/runtime/arch/instruction_set.cc
+++ b/runtime/arch/instruction_set.cc
@@ -16,6 +16,8 @@
 
 #include "instruction_set.h"
 
+// Explicitly include our own elf.h to avoid Linux and other dependencies.
+#include "../elf.h"
 #include "globals.h"
 
 namespace art {
@@ -63,6 +65,29 @@
   return kNone;
 }
 
+InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) {
+  switch (e_machine) {
+    case EM_ARM:
+      return kArm;
+    case EM_AARCH64:
+      return kArm64;
+    case EM_386:
+      return kX86;
+    case EM_X86_64:
+      return kX86_64;
+    case EM_MIPS: {
+      if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
+          (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
+        return kMips;
+      } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+        return kMips64;
+      }
+      break;
+    }
+  }
+  return kNone;
+}
+
 size_t GetInstructionSetAlignment(InstructionSet isa) {
   switch (isa) {
     case kArm:
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index 9135e58..9cfd2eb 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -80,6 +80,8 @@
 // Note: Returns kNone when the string cannot be parsed to a known value.
 InstructionSet GetInstructionSetFromString(const char* instruction_set);
 
+InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
+
 static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
   switch (isa) {
     case kArm:
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 1b91aa6..a22e274 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1313,35 +1313,7 @@
   CHECK(program_header_only_) << file_->GetPath();
 
   if (executable) {
-    InstructionSet elf_ISA = kNone;
-    switch (GetHeader().e_machine) {
-      case EM_ARM: {
-        elf_ISA = kArm;
-        break;
-      }
-      case EM_AARCH64: {
-        elf_ISA = kArm64;
-        break;
-      }
-      case EM_386: {
-        elf_ISA = kX86;
-        break;
-      }
-      case EM_X86_64: {
-        elf_ISA = kX86_64;
-        break;
-      }
-      case EM_MIPS: {
-        if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
-            (GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
-          elf_ISA = kMips;
-        } else if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
-          elf_ISA = kMips64;
-        }
-        break;
-      }
-    }
-
+    InstructionSet elf_ISA = GetInstructionSetFromELF(GetHeader().e_machine, GetHeader().e_flags);
     if (elf_ISA != kRuntimeISA) {
       std::ostringstream oss;
       oss << "Expected ISA " << kRuntimeISA << " but found " << elf_ISA;
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 15562e5..83ad33e 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -48,7 +48,7 @@
 #endif
 }
 
-template <typename Visitor>
+template <bool kClearCard, typename Visitor>
 inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
                               const Visitor& visitor, const uint8_t minimum_age) const {
   DCHECK_GE(scan_begin, reinterpret_cast<uint8_t*>(bitmap->HeapBegin()));
@@ -66,6 +66,9 @@
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
       bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
       ++cards_scanned;
+      if (kClearCard) {
+        *card_cur = 0;
+      }
     }
     ++card_cur;
   }
@@ -95,6 +98,9 @@
             << "card " << static_cast<size_t>(*card) << " intptr_t " << (start_word & 0xFF);
         bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
         ++cards_scanned;
+        if (kClearCard) {
+          *card = 0;
+        }
       }
       start_word >>= 8;
       start += kCardSize;
@@ -109,6 +115,9 @@
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
       bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
       ++cards_scanned;
+      if (kClearCard) {
+        *card_cur = 0;
+      }
     }
     ++card_cur;
   }
diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h
index 9bd3fba..a84cf34 100644
--- a/runtime/gc/accounting/card_table.h
+++ b/runtime/gc/accounting/card_table.h
@@ -101,7 +101,7 @@
 
   // For every dirty at least minumum age between begin and end invoke the visitor with the
   // specified argument. Returns how many cards the visitor was run on.
-  template <typename Visitor>
+  template <bool kClearCard, typename Visitor>
   size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
               const Visitor& visitor,
               const uint8_t minimum_age = kCardDirty) const
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 80f7968..04fb694 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -687,12 +687,12 @@
   CardScanTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
                accounting::ContinuousSpaceBitmap* bitmap,
                uint8_t* begin, uint8_t* end, uint8_t minimum_age, size_t mark_stack_size,
-               Object** mark_stack_obj)
+               Object** mark_stack_obj, bool clear_card)
       : MarkStackTask<false>(thread_pool, mark_sweep, mark_stack_size, mark_stack_obj),
         bitmap_(bitmap),
         begin_(begin),
         end_(end),
-        minimum_age_(minimum_age) {
+        minimum_age_(minimum_age), clear_card_(clear_card) {
   }
 
  protected:
@@ -700,6 +700,7 @@
   uint8_t* const begin_;
   uint8_t* const end_;
   const uint8_t minimum_age_;
+  const bool clear_card_;
 
   virtual void Finalize() {
     delete this;
@@ -708,7 +709,9 @@
   virtual void Run(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
     ScanObjectParallelVisitor visitor(this);
     accounting::CardTable* card_table = mark_sweep_->GetHeap()->GetCardTable();
-    size_t cards_scanned = card_table->Scan(bitmap_, begin_, end_, visitor, minimum_age_);
+    size_t cards_scanned = clear_card_ ?
+                           card_table->Scan<true>(bitmap_, begin_, end_, visitor, minimum_age_) :
+                           card_table->Scan<false>(bitmap_, begin_, end_, visitor, minimum_age_);
     VLOG(heap) << "Parallel scanning cards " << reinterpret_cast<void*>(begin_) << " - "
         << reinterpret_cast<void*>(end_) << " = " << cards_scanned;
     // Finish by emptying our local mark stack.
@@ -763,6 +766,11 @@
       // Calculate how much address range each task gets.
       const size_t card_delta = RoundUp(address_range / thread_count + 1,
                                         accounting::CardTable::kCardSize);
+      // If paused and the space is neither zygote nor image space, we could clear the dirty
+      // cards to avoid accumulating them to increase card scanning load in the following GC
+      // cycles. We need to keep dirty cards of image space and zygote space in order to track
+      // references to the other spaces.
+      bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
       // Create the worker tasks for this space.
       while (card_begin != card_end) {
         // Add a range of cards.
@@ -777,7 +785,7 @@
         // Add the new task to the thread pool.
         auto* task = new CardScanTask(thread_pool, this, space->GetMarkBitmap(), card_begin,
                                       card_begin + card_increment, minimum_age,
-                                      mark_stack_increment, mark_stack_end);
+                                      mark_stack_increment, mark_stack_end, clear_card);
         thread_pool->AddTask(self, task);
         card_begin += card_increment;
       }
@@ -811,8 +819,14 @@
         }
         TimingLogger::ScopedTiming t(name, GetTimings());
         ScanObjectVisitor visitor(this);
-        card_table->Scan(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
-                         minimum_age);
+        bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
+        if (clear_card) {
+          card_table->Scan<true>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+                                 minimum_age);
+        } else {
+          card_table->Scan<false>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+                                  minimum_age);
+        }
       }
     }
   }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index eed9352..6ba30c6 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2385,8 +2385,8 @@
         // Attempt to see if the card table missed the reference.
         ScanVisitor scan_visitor;
         uint8_t* byte_cover_begin = reinterpret_cast<uint8_t*>(card_table->AddrFromCard(card_addr));
-        card_table->Scan(bitmap, byte_cover_begin,
-                         byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
+        card_table->Scan<false>(bitmap, byte_cover_begin,
+                                byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
       }
 
       // Search to see if any of the roots reference our object.
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index ef63080..5e33380 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -933,8 +933,11 @@
                                            PrettyTypeOf(pretty_object).c_str());
       } else {
         // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+        // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
+        // suspension and move pretty_object.
+        const std::string pretty_type(PrettyTypeOf(pretty_object));
         os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(),
-                                           PrettyTypeOf(pretty_object).c_str());
+                                           pretty_type.c_str());
       }
     }
     // - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5
diff --git a/runtime/primitive.cc b/runtime/primitive.cc
index a639f93..d29a060 100644
--- a/runtime/primitive.cc
+++ b/runtime/primitive.cc
@@ -31,6 +31,11 @@
   "PrimVoid",
 };
 
+const char* Primitive::PrettyDescriptor(Primitive::Type type) {
+  CHECK(Primitive::kPrimNot <= type && type <= Primitive::kPrimVoid) << static_cast<int>(type);
+  return kTypeNames[type];
+}
+
 std::ostream& operator<<(std::ostream& os, const Primitive::Type& type) {
   int32_t int_type = static_cast<int32_t>(type);
   if (type >= Primitive::kPrimNot && type <= Primitive::kPrimVoid) {
diff --git a/runtime/primitive.h b/runtime/primitive.h
index afcc64d..50d171c 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -146,6 +146,8 @@
     }
   }
 
+  static const char* PrettyDescriptor(Type type);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
 };
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 862fe06..a737ccd 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -34,6 +34,7 @@
     test_Math_max_F();
     test_Math_min_D();
     test_Math_max_D();
+    test_Math_sqrt();
     test_Math_ceil();
     test_Math_floor();
     test_Math_rint();
@@ -54,6 +55,7 @@
     test_StrictMath_max_F();
     test_StrictMath_min_D();
     test_StrictMath_max_D();
+    test_StrictMath_sqrt();
     test_StrictMath_ceil();
     test_StrictMath_floor();
     test_StrictMath_rint();
@@ -298,6 +300,7 @@
   }
 
   public static void test_Math_abs_I() {
+    Math.abs(-1);
     Assert.assertEquals(Math.abs(0), 0);
     Assert.assertEquals(Math.abs(123), 123);
     Assert.assertEquals(Math.abs(-123), 123);
@@ -308,6 +311,7 @@
   }
 
   public static void test_Math_abs_J() {
+    Math.abs(-1L);
     Assert.assertEquals(Math.abs(0L), 0L);
     Assert.assertEquals(Math.abs(123L), 123L);
     Assert.assertEquals(Math.abs(-123L), 123L);
@@ -317,6 +321,7 @@
   }
 
   public static void test_Math_min_I() {
+    Math.min(1, 0);
     Assert.assertEquals(Math.min(0, 0), 0);
     Assert.assertEquals(Math.min(1, 0), 0);
     Assert.assertEquals(Math.min(0, 1), 0);
@@ -326,6 +331,7 @@
   }
 
   public static void test_Math_max_I() {
+    Math.max(1, 0);
     Assert.assertEquals(Math.max(0, 0), 0);
     Assert.assertEquals(Math.max(1, 0), 1);
     Assert.assertEquals(Math.max(0, 1), 1);
@@ -335,6 +341,7 @@
   }
 
   public static void test_Math_min_J() {
+    Math.min(1L, 0L);
     Assert.assertEquals(Math.min(0L, 0L), 0L);
     Assert.assertEquals(Math.min(1L, 0L), 0L);
     Assert.assertEquals(Math.min(0L, 1L), 0L);
@@ -344,6 +351,7 @@
   }
 
   public static void test_Math_max_J() {
+    Math.max(1L, 0L);
     Assert.assertEquals(Math.max(0L, 0L), 0L);
     Assert.assertEquals(Math.max(1L, 0L), 1L);
     Assert.assertEquals(Math.max(0L, 1L), 1L);
@@ -353,6 +361,7 @@
   }
 
   public static void test_Math_min_F() {
+    Math.min(1.0f, Float.NaN);
     Assert.assertTrue(Float.isNaN(Math.min(1.0f, Float.NaN)));
     Assert.assertTrue(Float.isNaN(Math.min(Float.NaN, 1.0f)));
     Assert.assertEquals(Math.min(-0.0f, 0.0f), -0.0f);
@@ -367,6 +376,7 @@
   }
 
   public static void test_Math_max_F() {
+    Math.max(1.0f, Float.NaN);
     Assert.assertTrue(Float.isNaN(Math.max(1.0f, Float.NaN)));
     Assert.assertTrue(Float.isNaN(Math.max(Float.NaN, 1.0f)));
     Assert.assertEquals(Math.max(-0.0f, 0.0f), 0.0f);
@@ -381,6 +391,7 @@
   }
 
   public static void test_Math_min_D() {
+    Math.min(1.0d, Double.NaN);
     Assert.assertTrue(Double.isNaN(Math.min(1.0d, Double.NaN)));
     Assert.assertTrue(Double.isNaN(Math.min(Double.NaN, 1.0d)));
     Assert.assertEquals(Math.min(-0.0d, 0.0d), -0.0d);
@@ -395,6 +406,7 @@
   }
 
   public static void test_Math_max_D() {
+    Math.max(1.0d, Double.NaN);
     Assert.assertTrue(Double.isNaN(Math.max(1.0d, Double.NaN)));
     Assert.assertTrue(Double.isNaN(Math.max(Double.NaN, 1.0d)));
     Assert.assertEquals(Math.max(-0.0d, 0.0d), 0.0d);
@@ -408,7 +420,15 @@
     Assert.assertEquals(Math.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE);
   }
 
+  public static void test_Math_sqrt() {
+    Math.sqrt(+4.0);
+    Assert.assertEquals(Math.sqrt(+4.0), +2.0d, 0.0);
+    Assert.assertEquals(Math.sqrt(+49.0), +7.0d, 0.0);
+    Assert.assertEquals(Math.sqrt(+1.44), +1.2d, 0.0);
+  }
+
   public static void test_Math_ceil() {
+    Math.ceil(-0.9);
     Assert.assertEquals(Math.ceil(+0.0), +0.0d, 0.0);
     Assert.assertEquals(Math.ceil(-0.0), -0.0d, 0.0);
     Assert.assertEquals(Math.ceil(-0.9), -0.0d, 0.0);
@@ -430,6 +450,7 @@
   }
 
   public static void test_Math_floor() {
+    Math.floor(+2.1);
     Assert.assertEquals(Math.floor(+0.0), +0.0d, 0.0);
     Assert.assertEquals(Math.floor(-0.0), -0.0d, 0.0);
     Assert.assertEquals(Math.floor(+2.0), +2.0d, 0.0);
@@ -448,6 +469,7 @@
   }
 
   public static void test_Math_rint() {
+    Math.rint(+2.1);
     Assert.assertEquals(Math.rint(+0.0), +0.0d, 0.0);
     Assert.assertEquals(Math.rint(-0.0), -0.0d, 0.0);
     Assert.assertEquals(Math.rint(+2.0), +2.0d, 0.0);
@@ -466,6 +488,7 @@
   }
 
   public static void test_Math_round_D() {
+    Math.round(2.1d);
     Assert.assertEquals(Math.round(+0.0d), (long)+0.0);
     Assert.assertEquals(Math.round(-0.0d), (long)+0.0);
     Assert.assertEquals(Math.round(2.0d), 2l);
@@ -487,6 +510,7 @@
   }
 
   public static void test_Math_round_F() {
+    Math.round(2.1f);
     Assert.assertEquals(Math.round(+0.0f), (int)+0.0);
     Assert.assertEquals(Math.round(-0.0f), (int)+0.0);
     Assert.assertEquals(Math.round(2.0f), 2);
@@ -507,6 +531,7 @@
   }
 
   public static void test_StrictMath_abs_I() {
+    StrictMath.abs(-1);
     Assert.assertEquals(StrictMath.abs(0), 0);
     Assert.assertEquals(StrictMath.abs(123), 123);
     Assert.assertEquals(StrictMath.abs(-123), 123);
@@ -517,6 +542,7 @@
   }
 
   public static void test_StrictMath_abs_J() {
+    StrictMath.abs(-1L);
     Assert.assertEquals(StrictMath.abs(0L), 0L);
     Assert.assertEquals(StrictMath.abs(123L), 123L);
     Assert.assertEquals(StrictMath.abs(-123L), 123L);
@@ -526,6 +552,7 @@
   }
 
   public static void test_StrictMath_min_I() {
+    StrictMath.min(1, 0);
     Assert.assertEquals(StrictMath.min(0, 0), 0);
     Assert.assertEquals(StrictMath.min(1, 0), 0);
     Assert.assertEquals(StrictMath.min(0, 1), 0);
@@ -535,6 +562,7 @@
   }
 
   public static void test_StrictMath_max_I() {
+    StrictMath.max(1, 0);
     Assert.assertEquals(StrictMath.max(0, 0), 0);
     Assert.assertEquals(StrictMath.max(1, 0), 1);
     Assert.assertEquals(StrictMath.max(0, 1), 1);
@@ -544,6 +572,7 @@
   }
 
   public static void test_StrictMath_min_J() {
+    StrictMath.min(1L, 0L);
     Assert.assertEquals(StrictMath.min(0L, 0L), 0L);
     Assert.assertEquals(StrictMath.min(1L, 0L), 0L);
     Assert.assertEquals(StrictMath.min(0L, 1L), 0L);
@@ -553,6 +582,7 @@
   }
 
   public static void test_StrictMath_max_J() {
+    StrictMath.max(1L, 0L);
     Assert.assertEquals(StrictMath.max(0L, 0L), 0L);
     Assert.assertEquals(StrictMath.max(1L, 0L), 1L);
     Assert.assertEquals(StrictMath.max(0L, 1L), 1L);
@@ -562,6 +592,7 @@
   }
 
   public static void test_StrictMath_min_F() {
+    StrictMath.min(1.0f, Float.NaN);
     Assert.assertTrue(Float.isNaN(StrictMath.min(1.0f, Float.NaN)));
     Assert.assertTrue(Float.isNaN(StrictMath.min(Float.NaN, 1.0f)));
     Assert.assertEquals(StrictMath.min(-0.0f, 0.0f), -0.0f);
@@ -576,6 +607,7 @@
   }
 
   public static void test_StrictMath_max_F() {
+    StrictMath.max(1.0f, Float.NaN);
     Assert.assertTrue(Float.isNaN(StrictMath.max(1.0f, Float.NaN)));
     Assert.assertTrue(Float.isNaN(StrictMath.max(Float.NaN, 1.0f)));
     Assert.assertEquals(StrictMath.max(-0.0f, 0.0f), 0.0f);
@@ -590,6 +622,7 @@
   }
 
   public static void test_StrictMath_min_D() {
+    StrictMath.min(1.0d, Double.NaN);
     Assert.assertTrue(Double.isNaN(StrictMath.min(1.0d, Double.NaN)));
     Assert.assertTrue(Double.isNaN(StrictMath.min(Double.NaN, 1.0d)));
     Assert.assertEquals(StrictMath.min(-0.0d, 0.0d), -0.0d);
@@ -604,6 +637,7 @@
   }
 
   public static void test_StrictMath_max_D() {
+    StrictMath.max(1.0d, Double.NaN);
     Assert.assertTrue(Double.isNaN(StrictMath.max(1.0d, Double.NaN)));
     Assert.assertTrue(Double.isNaN(StrictMath.max(Double.NaN, 1.0d)));
     Assert.assertEquals(StrictMath.max(-0.0d, 0.0d), 0.0d);
@@ -617,7 +651,15 @@
     Assert.assertEquals(StrictMath.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE);
   }
 
+  public static void test_StrictMath_sqrt() {
+    StrictMath.sqrt(+4.0);
+    Assert.assertEquals(StrictMath.sqrt(+4.0), +2.0d, 0.0);
+    Assert.assertEquals(StrictMath.sqrt(+49.0), +7.0d, 0.0);
+    Assert.assertEquals(StrictMath.sqrt(+1.44), +1.2d, 0.0);
+  }
+
   public static void test_StrictMath_ceil() {
+    StrictMath.ceil(-0.9);
     Assert.assertEquals(StrictMath.ceil(+0.0), +0.0d, 0.0);
     Assert.assertEquals(StrictMath.ceil(-0.0), -0.0d, 0.0);
     Assert.assertEquals(StrictMath.ceil(-0.9), -0.0d, 0.0);
@@ -639,6 +681,7 @@
   }
 
   public static void test_StrictMath_floor() {
+    StrictMath.floor(+2.1);
     Assert.assertEquals(StrictMath.floor(+0.0), +0.0d, 0.0);
     Assert.assertEquals(StrictMath.floor(-0.0), -0.0d, 0.0);
     Assert.assertEquals(StrictMath.floor(+2.0), +2.0d, 0.0);
@@ -657,6 +700,7 @@
   }
 
   public static void test_StrictMath_rint() {
+    StrictMath.rint(+2.1);
     Assert.assertEquals(StrictMath.rint(+0.0), +0.0d, 0.0);
     Assert.assertEquals(StrictMath.rint(-0.0), -0.0d, 0.0);
     Assert.assertEquals(StrictMath.rint(+2.0), +2.0d, 0.0);
@@ -675,6 +719,7 @@
   }
 
   public static void test_StrictMath_round_D() {
+    StrictMath.round(2.1d);
     Assert.assertEquals(StrictMath.round(+0.0d), (long)+0.0);
     Assert.assertEquals(StrictMath.round(-0.0d), (long)+0.0);
     Assert.assertEquals(StrictMath.round(2.0d), 2l);
@@ -696,6 +741,7 @@
   }
 
   public static void test_StrictMath_round_F() {
+    StrictMath.round(2.1f);
     Assert.assertEquals(StrictMath.round(+0.0f), (int)+0.0);
     Assert.assertEquals(StrictMath.round(-0.0f), (int)+0.0);
     Assert.assertEquals(StrictMath.round(2.0f), 2);
@@ -716,6 +762,7 @@
   }
 
   public static void test_Float_floatToRawIntBits() {
+    Float.floatToRawIntBits(-1.0f);
     Assert.assertEquals(Float.floatToRawIntBits(-1.0f), 0xbf800000);
     Assert.assertEquals(Float.floatToRawIntBits(0.0f), 0);
     Assert.assertEquals(Float.floatToRawIntBits(1.0f), 0x3f800000);
@@ -725,6 +772,7 @@
   }
 
   public static void test_Float_intBitsToFloat() {
+    Float.intBitsToFloat(0xbf800000);
     Assert.assertEquals(Float.intBitsToFloat(0xbf800000), -1.0f);
     Assert.assertEquals(Float.intBitsToFloat(0x00000000), 0.0f);
     Assert.assertEquals(Float.intBitsToFloat(0x3f800000), 1.0f);
@@ -734,6 +782,7 @@
   }
 
   public static void test_Double_doubleToRawLongBits() {
+    Double.doubleToRawLongBits(-1.0);
     Assert.assertEquals(Double.doubleToRawLongBits(-1.0), 0xbff0000000000000L);
     Assert.assertEquals(Double.doubleToRawLongBits(0.0), 0x0000000000000000L);
     Assert.assertEquals(Double.doubleToRawLongBits(1.0), 0x3ff0000000000000L);
@@ -743,6 +792,7 @@
   }
 
   public static void test_Double_longBitsToDouble() {
+    Double.longBitsToDouble(0xbff0000000000000L);
     Assert.assertEquals(Double.longBitsToDouble(0xbff0000000000000L), -1.0);
     Assert.assertEquals(Double.longBitsToDouble(0x0000000000000000L), 0.0);
     Assert.assertEquals(Double.longBitsToDouble(0x3ff0000000000000L), 1.0);
@@ -752,6 +802,7 @@
   }
 
   public static void test_Short_reverseBytes() {
+      Short.reverseBytes((short)0x1357);
       Assert.assertEquals(Short.reverseBytes((short)0x0000), (short)0x0000);
       Assert.assertEquals(Short.reverseBytes((short)0xffff), (short)0xffff);
       Assert.assertEquals(Short.reverseBytes((short)0x8000), (short)0x0080);
@@ -763,6 +814,7 @@
   }
 
   public static void test_Integer_reverseBytes() {
+      Integer.reverseBytes(0x13579bdf);
       Assert.assertEquals(Integer.reverseBytes(0x00000000), 0x00000000);
       Assert.assertEquals(Integer.reverseBytes(0xffffffff), 0xffffffff);
       Assert.assertEquals(Integer.reverseBytes(0x80000000), 0x00000080);
@@ -772,6 +824,7 @@
   }
 
   public static void test_Long_reverseBytes() {
+      Long.reverseBytes(0x13579bdf2468ace0L);
       Assert.assertEquals(Long.reverseBytes(0x0000000000000000L), 0x0000000000000000L);
       Assert.assertEquals(Long.reverseBytes(0xffffffffffffffffL), 0xffffffffffffffffL);
       Assert.assertEquals(Long.reverseBytes(0x8000000000000000L), 0x0000000000000080L);
@@ -780,6 +833,7 @@
   }
 
   public static void test_Integer_reverse() {
+    Integer.reverse(0x12345678);
     Assert.assertEquals(Integer.reverse(1), 0x80000000);
     Assert.assertEquals(Integer.reverse(-1), 0xffffffff);
     Assert.assertEquals(Integer.reverse(0), 0);
@@ -790,6 +844,7 @@
   }
 
   public static void test_Long_reverse() {
+    Long.reverse(0x1234567812345678L);
     Assert.assertEquals(Long.reverse(1L), 0x8000000000000000L);
     Assert.assertEquals(Long.reverse(-1L), 0xffffffffffffffffL);
     Assert.assertEquals(Long.reverse(0L), 0L);
@@ -844,6 +899,7 @@
     b[1] = 0x12;
     b[2] = 0x11;
     long address = (long)address_of.invoke(runtime, b);
+    peek_short.invoke(null, address, false);
     Assert.assertEquals((short)peek_short.invoke(null, address, false), 0x1213);  // Aligned read
     Assert.assertEquals((short)peek_short.invoke(null, address + 1, false), 0x1112);  // Unaligned read
   }
@@ -856,6 +912,7 @@
     b[3] = 0x12;
     b[4] = 0x11;
     long address = (long)address_of.invoke(runtime, b);
+    peek_int.invoke(null, address, false);
     Assert.assertEquals((int)peek_int.invoke(null, address, false), 0x12131415);
     Assert.assertEquals((int)peek_int.invoke(null, address + 1, false), 0x11121314);
   }
@@ -872,6 +929,7 @@
     b[7] = 0x12;
     b[8] = 0x11;
     long address = (long)address_of.invoke(runtime, b);
+    peek_long.invoke(null, address, false);
     Assert.assertEquals((long)peek_long.invoke(null, address, false), 0x1213141516171819L);
     Assert.assertEquals((long)peek_long.invoke(null, address + 1, false), 0x1112131415161718L);
   }
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 48f9bd3..df2243c 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -16,54 +16,36 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 public class Main implements Runnable {
 
     // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
     // ART on timeout when running on the host.
-    public final static long TIMEOUT_VALUE = 12;
+    private final static long TIMEOUT_VALUE = 7;
 
-    public final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.
+    private final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.
+
+    private final static int THREAD_COUNT = 16;
+
+    // Use a couple of different forms of synchronizing to test some of these...
+    private final static AtomicInteger counter = new AtomicInteger();
+    private final static Object gate = new Object();
+    private volatile static int waitCount = 0;
 
     public static void main(String[] args) throws Exception {
-        Thread[] threads = new Thread[16];
+        Thread[] threads = new Thread[THREAD_COUNT];
 
-        // Use a cyclic system of synchronous queues to pass a boolean token around.
-        //
-        // The combinations are:
-        //
-        // Worker receives:    true     false    false    true
-        // Worker has OOM:     false    false    true     true
-        //    |
-        //    v
-        // Value to pass:      true     false    false    false
-        // Exit out of loop:   false    true     true     true
-        // Wait on in queue:   true     false    false    true
-        //
-        // Finally, the workers are supposed to wait on the barrier to synchronize the GC run.
-
-        CyclicBarrier barrier = new CyclicBarrier(threads.length);
-        List<SynchronousQueue<Boolean>> queues = new ArrayList<SynchronousQueue<Boolean>>(
-            threads.length);
-        for (int i = 0; i < threads.length; i++) {
-            queues.add(new SynchronousQueue<Boolean>());
-        }
+        // This barrier is used to synchronize the threads starting to allocate.
+        // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
+        //       before filling the heap.
+        CyclicBarrier startBarrier = new CyclicBarrier(threads.length);
 
         for (int i = 0; i < threads.length; i++) {
-            threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length),
-                                             barrier));
+            threads[i] = new Thread(new Main(startBarrier));
+            threads[i].start();
         }
-        for (Thread thread : threads) {
-            thread.start();
-        }
-
-        // Push off the cycle.
-        checkTimeout(queues.get(0).offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
 
         // Wait for the threads to finish.
         for (Thread thread : threads) {
@@ -72,85 +54,84 @@
 
         // Allocate objects to definitely run GC before quitting.
         try {
-            for (int i = 0; i < 1000; i++) {
-                new ArrayList<Object>(i);
+            ArrayList<Object> l = new ArrayList<Object>();
+            for (int i = 0; i < 100000; i++) {
+                l.add(new ArrayList<Object>(i));
             }
         } catch (OutOfMemoryError oom) {
         }
+        new ArrayList<Object>(50);
     }
 
-    private static void checkTimeout(Object o) {
-        checkTimeout(o != null);
+    private Main(CyclicBarrier startBarrier) {
+        this.startBarrier = startBarrier;
     }
 
-    private static void checkTimeout(boolean b) {
-        if (!b) {
-            // Something went wrong.
-            System.out.println("Bad things happened, timeout.");
-            System.exit(1);
-        }
-    }
-
-    private final int id;
-    private final SynchronousQueue<Boolean> waitOn;
-    private final SynchronousQueue<Boolean> pushTo;
-    private final CyclicBarrier finalBarrier;
-
-    private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo,
-        CyclicBarrier finalBarrier) {
-        this.id = id;
-        this.waitOn = waitOn;
-        this.pushTo = pushTo;
-        this.finalBarrier = finalBarrier;
-    }
+    private ArrayList<Object> store;
+    private CyclicBarrier startBarrier;
 
     public void run() {
         try {
             work();
-        } catch (Exception exc) {
-            // Any exception is bad.
-            exc.printStackTrace(System.err);
+        } catch (Throwable t) {
+            // Any exception or error getting here is bad.
+            try {
+                // May need allocations...
+                t.printStackTrace(System.err);
+            } catch (Throwable tInner) {
+            }
             System.exit(1);
         }
     }
 
-    public void work() throws BrokenBarrierException, InterruptedException, TimeoutException {
+    private void work() throws Exception {
+        // Any exceptions except an OOME in the allocation loop are bad and handed off to the
+        // caller which should abort the whole runtime.
+
         ArrayList<Object> l = new ArrayList<Object>();
+        store = l;  // Keep it alive.
 
-        // Main loop.
-        for (int i = 0; ; i++) {
-          Boolean receivedB = waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES);
-          checkTimeout(receivedB);
-          boolean received = receivedB;
+        // Wait for the start signal.
+        startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);
 
-          // This is the first stage, try to allocate up till MAX_SIZE.
-          boolean oom = i >= MAX_SIZE;
-          try {
-            l.add(new ArrayList<Object>(i));
-          } catch (OutOfMemoryError oome) {
-            oom = true;
-          }
-
-          if (!received || oom) {
-            // First stage, always push false.
-            checkTimeout(pushTo.offer(Boolean.FALSE, TIMEOUT_VALUE, TimeUnit.MINUTES));
-
-            // If we received true, wait for the false to come around.
-            if (received) {
-              checkTimeout(waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES));
+        // Allocate.
+        try {
+            for (int i = 0; i < MAX_SIZE; i++) {
+                l.add(new ArrayList<Object>(i));
             }
-
-            // Break out of the loop.
-            break;
-          } else {
-            // Pass on true.
-            checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
-          }
+        } catch (OutOfMemoryError oome) {
+            // Fine, we're done.
         }
 
-        // We have reached the final point. Wait on the barrier, but at most a minute.
-        finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES);
+        // Atomically increment the counter and check whether we were last.
+        int number = counter.incrementAndGet();
 
-        // Done.
+        if (number < THREAD_COUNT) {
+            // Not last.
+            synchronized (gate) {
+                // Increment the wait counter.
+                waitCount++;
+                gate.wait(TIMEOUT_VALUE * 1000 * 60);
+            }
+        } else {
+            // Last. Wait until waitCount == THREAD_COUNT - 1.
+            for (int loops = 0; ; loops++) {
+                synchronized (gate) {
+                    if (waitCount == THREAD_COUNT - 1) {
+                        // OK, everyone's waiting. Notify and break out.
+                        gate.notifyAll();
+                        break;
+                    } else if (loops > 40) {
+                        // 1s wait, too many tries.
+                        System.out.println("Waited too long for the last thread.");
+                        System.exit(1);
+                    }
+                }
+                // Wait a bit.
+                Thread.sleep(25);
+            }
+        }
+
+        store = null;  // Allow GC to reclaim it.
     }
 }
diff --git a/test/116-nodex2oat/run b/test/116-nodex2oat/run
index 7f90bf7..72488f0 100755
--- a/test/116-nodex2oat/run
+++ b/test/116-nodex2oat/run
@@ -14,6 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+flags="${@}"
+
 # Make sure we can run without an oat file,
 echo "Run -Xnodex2oat"
 ${RUN} ${flags} --runtime-option -Xnodex2oat