Merge "ART: Remember whether the cache was pruned"
diff --git a/Android.mk b/Android.mk
index e89f617..a518d2f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,9 +270,9 @@
 test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist)
 	ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests
 
-# Valgrind. Currently only 32b gtests. TODO: change this from 32-bit only to both 32-bit and 64-bit.
+# Valgrind.
 .PHONY: valgrind-test-art-host
-valgrind-test-art-host: valgrind-test-art-host-gtest32
+valgrind-test-art-host: valgrind-test-art-host-gtest
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: valgrind-test-art-host32
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5d8e3ba..cd9d80f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -376,7 +376,8 @@
       support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64),
       dex_files_for_oat_file_(nullptr),
       compiled_method_storage_(swap_fd),
-      profile_compilation_info_(profile_compilation_info) {
+      profile_compilation_info_(profile_compilation_info),
+      max_arena_alloc_(0) {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
 
@@ -2487,6 +2488,9 @@
                    parallel_thread_pool_.get(),
                    parallel_thread_count_,
                    timings);
+    const ArenaPool* const arena_pool = Runtime::Current()->GetArenaPool();
+    const size_t arena_alloc = arena_pool->GetBytesAllocated();
+    max_arena_alloc_ = std::max(arena_alloc, max_arena_alloc_);
     Runtime::Current()->ReclaimArenaPoolMemory();
   }
   VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
@@ -2726,12 +2730,9 @@
 
 std::string CompilerDriver::GetMemoryUsageString(bool extended) const {
   std::ostringstream oss;
-  Runtime* const runtime = Runtime::Current();
-  const ArenaPool* const arena_pool = runtime->GetArenaPool();
-  const gc::Heap* const heap = runtime->GetHeap();
-  const size_t arena_alloc = arena_pool->GetBytesAllocated();
+  const gc::Heap* const heap = Runtime::Current()->GetHeap();
   const size_t java_alloc = heap->GetBytesAllocated();
-  oss << "arena alloc=" << PrettySize(arena_alloc) << " (" << arena_alloc << "B)";
+  oss << "arena alloc=" << PrettySize(max_arena_alloc_) << " (" << max_arena_alloc_ << "B)";
   oss << " java alloc=" << PrettySize(java_alloc) << " (" << java_alloc << "B)";
 #if defined(__BIONIC__) || defined(__GLIBC__)
   const struct mallinfo info = mallinfo();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 42a5bc1..4ef26dd 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -694,6 +694,7 @@
   // Info for profile guided compilation.
   const ProfileCompilationInfo* const profile_compilation_info_;
 
+  size_t max_arena_alloc_;
   friend class CompileClassVisitor;
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 3bf8921..43bdbf3 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -35,7 +35,6 @@
       include_patch_information_(kDefaultIncludePatchInformation),
       top_k_profile_threshold_(kDefaultTopKProfileThreshold),
       debuggable_(false),
-      native_debuggable_(kDefaultNativeDebuggable),
       generate_debug_info_(kDefaultGenerateDebugInfo),
       generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
       implicit_null_checks_(true),
@@ -92,7 +91,6 @@
     include_patch_information_(include_patch_information),
     top_k_profile_threshold_(top_k_profile_threshold),
     debuggable_(debuggable),
-    native_debuggable_(kDefaultNativeDebuggable),
     generate_debug_info_(generate_debug_info),
     generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
     implicit_null_checks_(implicit_null_checks),
@@ -226,9 +224,6 @@
     generate_mini_debug_info_ = false;
   } else if (option == "--debuggable") {
     debuggable_ = true;
-  } else if (option == "--native-debuggable") {
-    native_debuggable_ = true;
-    debuggable_ = true;
   } else if (option.starts_with("--top-k-profile-threshold=")) {
     ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold_, Usage);
   } else if (option == "--include-patch-information") {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 4db82a6..fbfa7c8 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -49,7 +49,6 @@
   static const size_t kDefaultTinyMethodThreshold = 20;
   static const size_t kDefaultNumDexMethodsThreshold = 900;
   static constexpr double kDefaultTopKProfileThreshold = 90.0;
-  static const bool kDefaultNativeDebuggable = false;
   static const bool kDefaultGenerateDebugInfo = false;
   static const bool kDefaultGenerateMiniDebugInfo = false;
   static const bool kDefaultIncludePatchInformation = false;
@@ -179,7 +178,7 @@
   }
 
   bool GetNativeDebuggable() const {
-    return native_debuggable_;
+    return GetDebuggable() && GetGenerateDebugInfo();
   }
 
   // This flag controls whether the compiler collects debugging information.
@@ -292,7 +291,6 @@
   // When using a profile file only the top K% of the profiled samples will be compiled.
   double top_k_profile_threshold_;
   bool debuggable_;
-  bool native_debuggable_;
   bool generate_debug_info_;
   bool generate_mini_debug_info_;
   bool implicit_null_checks_;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index b1b971f..0b69810 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1542,15 +1542,16 @@
       }
       case kNativeObjectRelocationTypeArtMethodArrayClean:
       case kNativeObjectRelocationTypeArtMethodArrayDirty: {
-        memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(
-            0,
-            ArtMethod::Size(target_ptr_size_),
-            ArtMethod::Alignment(target_ptr_size_)));
+        size_t size = ArtMethod::Size(target_ptr_size_);
+        size_t alignment = ArtMethod::Alignment(target_ptr_size_);
+        memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(0, size, alignment));
+        // Clear padding to avoid non-deterministic data in the image (and placate valgrind).
+        reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(dest)->ClearPadding(size, alignment);
         break;
+      }
       case kNativeObjectRelocationTypeDexCacheArray:
         // Nothing to copy here, everything is done in FixupDexCache().
         break;
-      }
     }
   }
   // Fixup the image method roots.
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index af50363..f198727 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -706,7 +706,7 @@
                                  uint32_t dex_pc,
                                  SlowPathCode* slow_path) {
   if (instruction != nullptr) {
-    // The code generated for some type conversions and comparisons
+    // The code generated for some type conversions
     // may call the runtime, thus normally requiring a subsequent
     // call to this method. However, the method verifier does not
     // produce PC information for certain instructions, which are
@@ -717,7 +717,7 @@
     // CodeGenerator::RecordPcInfo without triggering an error in
     // CodeGenerator::BuildNativeGCMap ("Missing ref for dex pc 0x")
     // thereafter.
-    if (instruction->IsTypeConversion() || instruction->IsCompare()) {
+    if (instruction->IsTypeConversion()) {
       return;
     }
     if (instruction->IsRem()) {
@@ -1110,6 +1110,16 @@
   }
 }
 
+void CodeGenerator::GenerateNullCheck(HNullCheck* instruction) {
+  if (IsImplicitNullCheckAllowed(instruction)) {
+    MaybeRecordStat(kImplicitNullCheckGenerated);
+    GenerateImplicitNullCheck(instruction);
+  } else {
+    MaybeRecordStat(kExplicitNullCheckGenerated);
+    GenerateExplicitNullCheck(instruction);
+  }
+}
+
 void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const {
   LocationSummary* locations = suspend_check->GetLocations();
   HBasicBlock* block = suspend_check->GetBlock();
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 9297fc9..3066048 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -278,6 +278,9 @@
 
   bool CanMoveNullCheckToUser(HNullCheck* null_check);
   void MaybeRecordImplicitNullCheck(HInstruction* instruction);
+  void GenerateNullCheck(HNullCheck* null_check);
+  virtual void GenerateImplicitNullCheck(HNullCheck* null_check) = 0;
+  virtual void GenerateExplicitNullCheck(HNullCheck* null_check) = 0;
 
   // Records a stack map which the runtime might use to set catch phi values
   // during exception delivery.
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 0b7fefa..34fd9ff 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3151,6 +3151,7 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -3671,6 +3672,10 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
@@ -3701,6 +3706,10 @@
   Primitive::Type type = compare->InputAt(0)->GetType();
   Condition less_cond;
   switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt: {
       __ LoadImmediate(out, 0);
       __ cmp(left.AsRegister<Register>(),
@@ -4284,19 +4293,19 @@
   }
 }
 
-void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
   Location obj = instruction->GetLocations()->InAt(0);
 
   __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
@@ -4305,11 +4314,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 06e7c00..5c0f31c 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -274,9 +274,6 @@
                                Location root,
                                Register obj,
                                uint32_t offset);
-
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
                              Label* true_target,
@@ -514,6 +511,9 @@
 
   void GenerateNop();
 
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
+
  private:
   // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
   // and GenerateArrayLoadWithBakerReadBarrier.
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 89b9e2c..a220e59 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2388,6 +2388,10 @@
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   Primitive::Type in_type = compare->InputAt(0)->GetType();
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
@@ -2417,6 +2421,10 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       Register result = OutputRegister(compare);
@@ -2718,8 +2726,8 @@
 
   Primitive::Type type = instruction->GetType();
 
-  if ((type == Primitive::kPrimBoolean) || !Primitive::IsIntegralType(type)) {
-      LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
+  if (!Primitive::IsIntegralType(type)) {
+    LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
     return;
   }
 
@@ -4193,20 +4201,20 @@
   }
 }
 
-void InstructionCodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
 
   BlockPoolsScope block_pools(GetVIXLAssembler());
   Location obj = instruction->GetLocations()->InAt(0);
   __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
@@ -4215,11 +4223,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderARM64::VisitOr(HOr* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 10f1e7f..a1f686e 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -258,8 +258,6 @@
                                uint32_t offset);
 
   void HandleShift(HBinaryOperation* instr);
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
                              vixl::Label* true_target,
@@ -537,6 +535,9 @@
 
   void GenerateNop();
 
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
+
  private:
   // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
   // and GenerateArrayLoadWithBakerReadBarrier.
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f3c12ef..3c2c0b0 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2070,6 +2070,10 @@
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
 
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
@@ -2100,6 +2104,10 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt: {
       Register lhs = locations->InAt(0).AsRegister<Register>();
       Register rhs = locations->InAt(1).AsRegister<Register>();
@@ -2530,6 +2538,7 @@
   Primitive::Type type = instruction->GetType();
 
   switch (type) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -4395,19 +4404,19 @@
   }
 }
 
-void InstructionCodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
   Location obj = instruction->GetLocations()->InAt(0);
 
   __ Lw(ZERO, obj.AsRegister<Register>(), 0);
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   Location obj = instruction->GetLocations()->InAt(0);
 
@@ -4415,11 +4424,7 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 605c794..b720573 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -226,8 +226,6 @@
   void HandleShift(HBinaryOperation* operation);
   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   void GenerateIntCompare(IfCondition cond, LocationSummary* locations);
   void GenerateIntCompareAndBranch(IfCondition cond,
                                    LocationSummary* locations,
@@ -362,6 +360,8 @@
   }
 
   void GenerateNop();
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index c2b84b4..ddc873d 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1691,6 +1691,10 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
 
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
@@ -1719,6 +1723,10 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
@@ -1726,18 +1734,18 @@
       bool use_imm = rhs_location.IsConstant();
       GpuRegister rhs = ZERO;
       if (use_imm) {
-        if (in_type == Primitive::kPrimInt) {
-          int32_t value = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant()->AsConstant());
-          if (value != 0) {
-            rhs = AT;
-            __ LoadConst32(rhs, value);
-          }
-        } else {
+        if (in_type == Primitive::kPrimLong) {
           int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
           if (value != 0) {
             rhs = AT;
             __ LoadConst64(rhs, value);
           }
+        } else {
+          int32_t value = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant()->AsConstant());
+          if (value != 0) {
+            rhs = AT;
+            __ LoadConst32(rhs, value);
+          }
         }
       } else {
         rhs = rhs_location.AsRegister<GpuRegister>();
@@ -2172,8 +2180,8 @@
 
   Primitive::Type type = instruction->GetType();
 
-  if ((type == Primitive::kPrimBoolean) || !Primitive::IsIntegralType(type)) {
-      LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
+  if (!Primitive::IsIntegralType(type)) {
+    LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
     return;
   }
 
@@ -3550,19 +3558,19 @@
   }
 }
 
-void InstructionCodeGeneratorMIPS64::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorMIPS64::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
   Location obj = instruction->GetLocations()->InAt(0);
 
   __ Lw(ZERO, obj.AsRegister<GpuRegister>(), 0);
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorMIPS64::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorMIPS64::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS64(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   Location obj = instruction->GetLocations()->InAt(0);
 
@@ -3570,11 +3578,7 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderMIPS64::VisitOr(HOr* instruction) {
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index ba9eaff..9464a14 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -228,8 +228,6 @@
                       const FieldInfo& field_info,
                       bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
                              Mips64Label* true_target,
@@ -354,6 +352,8 @@
   }
 
   void GenerateNop();
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6b4a18c..9acaa1d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3662,6 +3662,7 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -3692,6 +3693,7 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -4184,6 +4186,10 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
@@ -4219,6 +4225,10 @@
   Condition less_cond = kLess;
 
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt: {
       GenerateIntCompare(left, right);
       break;
@@ -4971,20 +4981,20 @@
   }
 }
 
-void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
 
   __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
@@ -5003,11 +5013,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 0795f3b..c397899 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -271,8 +271,6 @@
   void PushOntoFPStack(Location source, uint32_t temp_offset,
                        uint32_t stack_adjustment, bool is_fp, bool is_wide);
 
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   template<class LabelType>
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
@@ -541,6 +539,8 @@
   }
 
   void GenerateNop();
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
  private:
   // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index c132663..51bc8c2 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1860,6 +1860,10 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
@@ -1890,6 +1894,10 @@
   Condition less_cond = kLess;
 
   switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
     case Primitive::kPrimInt: {
       CpuRegister left_reg = left.AsRegister<CpuRegister>();
       if (right.IsConstant()) {
@@ -3713,6 +3721,7 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -4487,20 +4496,20 @@
   }
 }
 
-void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
-  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+void CodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (CanMoveNullCheckToUser(instruction)) {
     return;
   }
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
 
   __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
-void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
+void CodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
   SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
-  codegen_->AddSlowPath(slow_path);
+  AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
@@ -4519,11 +4528,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
-  if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
-    GenerateImplicitNullCheck(instruction);
-  } else {
-    GenerateExplicitNullCheck(instruction);
-  }
+  codegen_->GenerateNullCheck(instruction);
 }
 
 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index b3d27e1..c3fce6e 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -260,8 +260,6 @@
                                CpuRegister obj,
                                uint32_t offset);
 
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
   void PushOntoFPStack(Location source, uint32_t temp_offset,
                        uint32_t stack_adjustment, bool is_float);
   void GenerateCompareTest(HCondition* condition);
@@ -514,6 +512,8 @@
   }
 
   void GenerateNop();
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
  private:
   // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 4a49c83..1fbb2d5 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -661,19 +661,6 @@
   }
 }
 
-static Primitive::Type PrimitiveKind(Primitive::Type type) {
-  switch (type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimInt:
-      return Primitive::kPrimInt;
-    default:
-      return type;
-  }
-}
-
 static bool IsSameSizeConstant(HInstruction* insn1, HInstruction* insn2) {
   return insn1->IsConstant()
       && insn2->IsConstant()
@@ -716,10 +703,10 @@
   // Ensure that the inputs have the same primitive kind as the phi.
   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
     HInstruction* input = phi->InputAt(i);
-    if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) {
+    if (Primitive::PrimitiveKind(input->GetType()) != Primitive::PrimitiveKind(phi->GetType())) {
         AddError(StringPrintf(
             "Input %d at index %zu of phi %d from block %d does not have the "
-            "same type as the phi: %s versus %s",
+            "same kind as the phi: %s versus %s",
             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
             Primitive::PrettyDescriptor(input->GetType()),
             Primitive::PrettyDescriptor(phi->GetType())));
@@ -910,9 +897,9 @@
   }
   HInstruction* lhs = op->InputAt(0);
   HInstruction* rhs = op->InputAt(1);
-  if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
+  if (Primitive::PrimitiveKind(lhs->GetType()) != Primitive::PrimitiveKind(rhs->GetType())) {
     AddError(StringPrintf(
-        "Condition %s %d has inputs of different types: %s, and %s.",
+        "Condition %s %d has inputs of different kinds: %s, and %s.",
         op->DebugName(), op->GetId(),
         Primitive::PrettyDescriptor(lhs->GetType()),
         Primitive::PrettyDescriptor(rhs->GetType())));
@@ -932,42 +919,39 @@
 
 void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
   VisitInstruction(op);
+  Primitive::Type lhs_type = op->InputAt(0)->GetType();
+  Primitive::Type rhs_type = op->InputAt(1)->GetType();
+  Primitive::Type result_type = op->GetType();
   if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
-    if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
-      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())));
+    if (Primitive::PrimitiveKind(rhs_type) != Primitive::kPrimInt) {
+      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(rhs_type)));
     }
   } else {
-    if (PrimitiveKind(op->InputAt(0)->GetType()) != PrimitiveKind(op->InputAt(1)->GetType())) {
-      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 (Primitive::PrimitiveKind(lhs_type) != Primitive::PrimitiveKind(rhs_type)) {
+      AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
+                            op->DebugName(), op->GetId(),
+                            Primitive::PrettyDescriptor(lhs_type),
+                            Primitive::PrettyDescriptor(rhs_type)));
     }
   }
 
   if (op->IsCompare()) {
-    if (op->GetType() != Primitive::kPrimInt) {
-      AddError(StringPrintf(
-          "Compare operation %d has a non-int result type: %s.",
-          op->GetId(),
-          Primitive::PrettyDescriptor(op->GetType())));
+    if (result_type != Primitive::kPrimInt) {
+      AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
+                            op->GetId(),
+                            Primitive::PrettyDescriptor(result_type)));
     }
   } 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())) {
-      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(0)->GetType())));
+    if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(lhs_type)) {
+      AddError(StringPrintf("Binary operation %s %d has a result kind different "
+                            "from its input kind: %s vs %s.",
+                            op->DebugName(), op->GetId(),
+                            Primitive::PrettyDescriptor(result_type),
+                            Primitive::PrettyDescriptor(lhs_type)));
     }
   }
 }
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index d861e39..573b583 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -293,7 +293,11 @@
   }
 
   if (actual_method != nullptr) {
-    return TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ true);
+    bool result = TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ true);
+    if (result && !invoke_instruction->IsInvokeStaticOrDirect()) {
+      MaybeRecordStat(kInlinedInvokeVirtualOrInterface);
+    }
+    return result;
   }
 
   DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
@@ -1279,10 +1283,14 @@
         // some functionality from the reference type propagation.
         DCHECK(return_replacement->IsPhi());
         size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-        ReferenceTypeInfo::TypeHandle return_handle =
-            handles_->NewHandle(resolved_method->GetReturnType(true /* resolve */, pointer_size));
-        return_replacement->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
-            return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */));
+        mirror::Class* cls = resolved_method->GetReturnType(false /* resolve */, pointer_size);
+        if (cls != nullptr) {
+          ReferenceTypeInfo::TypeHandle return_handle = handles_->NewHandle(cls);
+          return_replacement->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
+              return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */));
+        } else {
+          return_replacement->SetReferenceTypeInfo(graph_->GetInexactObjectRti());
+        }
       }
 
       if (do_rtp) {
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 09f841c..dd2977f 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -34,8 +34,12 @@
   void RecordSimplification() {
     simplification_occurred_ = true;
     simplifications_at_current_position_++;
-    if (stats_) {
-      stats_->RecordStat(kInstructionSimplifications);
+    MaybeRecordStat(kInstructionSimplifications);
+  }
+
+  void MaybeRecordStat(MethodCompilationStat stat) {
+    if (stats_ != nullptr) {
+      stats_->RecordStat(stat);
     }
   }
 
@@ -95,7 +99,7 @@
   void SimplifyRotate(HInvoke* invoke, bool is_left);
   void SimplifySystemArrayCopy(HInvoke* invoke);
   void SimplifyStringEquals(HInvoke* invoke);
-  void SimplifyCompare(HInvoke* invoke, bool has_zero_op);
+  void SimplifyCompare(HInvoke* invoke, bool is_signum, Primitive::Type type);
   void SimplifyIsNaN(HInvoke* invoke);
   void SimplifyFP2Int(HInvoke* invoke);
   void SimplifyMemBarrier(HInvoke* invoke, MemBarrierKind barrier_kind);
@@ -235,7 +239,10 @@
   HInstruction* input_other = instruction->GetLeastConstantLeft();
 
   if (input_cst != nullptr) {
-    if (input_cst->IsZero()) {
+    int64_t cst = Int64FromConstant(input_cst);
+    int64_t mask =
+        (input_other->GetType() == Primitive::kPrimLong) ? kMaxLongShiftValue : kMaxIntShiftValue;
+    if ((cst & mask) == 0) {
       // Replace code looking like
       //    SHL dst, src, 0
       // with
@@ -463,9 +470,7 @@
 
   if (object->IsNullConstant()) {
     check_cast->GetBlock()->RemoveInstruction(check_cast);
-    if (stats_ != nullptr) {
-      stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
-    }
+    MaybeRecordStat(MethodCompilationStat::kRemovedCheckedCast);
     return;
   }
 
@@ -475,9 +480,7 @@
   if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
     if (outcome) {
       check_cast->GetBlock()->RemoveInstruction(check_cast);
-      if (stats_ != nullptr) {
-        stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
-      }
+      MaybeRecordStat(MethodCompilationStat::kRemovedCheckedCast);
       if (!load_class->HasUses()) {
         // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
         // However, here we know that it cannot because the checkcast was successfull, hence
@@ -507,6 +510,7 @@
 
   HGraph* graph = GetGraph();
   if (object->IsNullConstant()) {
+    MaybeRecordStat(kRemovedInstanceOf);
     instruction->ReplaceWith(graph->GetIntConstant(0));
     instruction->GetBlock()->RemoveInstruction(instruction);
     RecordSimplification();
@@ -517,6 +521,7 @@
   // the return value check with the `outcome` check, b/27651442 .
   bool outcome = false;
   if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
+    MaybeRecordStat(kRemovedInstanceOf);
     if (outcome && can_be_null) {
       // Type test will succeed, we just need a null test.
       HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object);
@@ -1614,12 +1619,13 @@
   }
 }
 
-void InstructionSimplifierVisitor::SimplifyCompare(HInvoke* invoke, bool is_signum) {
+void InstructionSimplifierVisitor::SimplifyCompare(HInvoke* invoke,
+                                                   bool is_signum,
+                                                   Primitive::Type type) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
   uint32_t dex_pc = invoke->GetDexPc();
   HInstruction* left = invoke->InputAt(0);
   HInstruction* right;
-  Primitive::Type type = left->GetType();
   if (!is_signum) {
     right = invoke->InputAt(1);
   } else if (type == Primitive::kPrimLong) {
@@ -1696,12 +1702,16 @@
       SimplifyRotate(instruction, true);
       break;
     case Intrinsics::kIntegerCompare:
+      SimplifyCompare(instruction, /* is_signum */ false, Primitive::kPrimInt);
+      break;
     case Intrinsics::kLongCompare:
-      SimplifyCompare(instruction, /* is_signum */ false);
+      SimplifyCompare(instruction, /* is_signum */ false, Primitive::kPrimLong);
       break;
     case Intrinsics::kIntegerSignum:
+      SimplifyCompare(instruction, /* is_signum */ true, Primitive::kPrimInt);
+      break;
     case Intrinsics::kLongSignum:
-      SimplifyCompare(instruction, /* is_signum */ true);
+      SimplifyCompare(instruction, /* is_signum */ true, Primitive::kPrimLong);
       break;
     case Intrinsics::kFloatIsNaN:
     case Intrinsics::kDoubleIsNaN:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 1bb5f5d..e2a54f4 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2543,7 +2543,7 @@
     return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
   }
   bool IsZero() const OVERRIDE {
-    return value_ == 0.0f;
+    return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(0.0f);
   }
   bool IsOne() const OVERRIDE {
     return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
@@ -2585,7 +2585,7 @@
     return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
   }
   bool IsZero() const OVERRIDE {
-    return value_ == 0.0;
+    return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((0.0));
   }
   bool IsOne() const OVERRIDE {
     return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
@@ -3428,7 +3428,10 @@
 // Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1.
 class HCompare : public HBinaryOperation {
  public:
-  HCompare(Primitive::Type type,
+  // Note that `comparison_type` is the type of comparison performed
+  // between the comparison's inputs, not the type of the instantiated
+  // HCompare instruction (which is always Primitive::kPrimInt).
+  HCompare(Primitive::Type comparison_type,
            HInstruction* first,
            HInstruction* second,
            ComparisonBias bias,
@@ -3436,11 +3439,13 @@
       : HBinaryOperation(Primitive::kPrimInt,
                          first,
                          second,
-                         SideEffectsForArchRuntimeCalls(type),
+                         SideEffectsForArchRuntimeCalls(comparison_type),
                          dex_pc) {
     SetPackedField<ComparisonBiasField>(bias);
-    DCHECK_EQ(type, first->GetType());
-    DCHECK_EQ(type, second->GetType());
+    if (kIsDebugBuild) {
+      DCHECK_EQ(comparison_type, Primitive::PrimitiveKind(first->GetType()));
+      DCHECK_EQ(comparison_type, Primitive::PrimitiveKind(second->GetType()));
+    }
   }
 
   template <typename T>
@@ -3485,9 +3490,9 @@
     return GetBias() == ComparisonBias::kGtBias;
   }
 
-  static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) {
-    // MIPS64 uses a runtime call for FP comparisons.
-    return Primitive::IsFloatingPointType(type) ? SideEffects::CanTriggerGC() : SideEffects::None();
+  static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type ATTRIBUTE_UNUSED) {
+    // Comparisons do not require a runtime call in any back end.
+    return SideEffects::None();
   }
 
   DECLARE_INSTRUCTION(Compare);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 7a82063..4d2469c 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -63,6 +63,7 @@
 #include "instruction_simplifier_arm.h"
 #include "intrinsics.h"
 #include "jit/debugger_interface.h"
+#include "jit/jit.h"
 #include "jit/jit_code_cache.h"
 #include "jni/quick/jni_compiler.h"
 #include "licm.h"
@@ -697,7 +698,8 @@
       CodeGenerator::Create(graph,
                             instruction_set,
                             *compiler_driver->GetInstructionSetFeatures(),
-                            compiler_driver->GetCompilerOptions()));
+                            compiler_driver->GetCompilerOptions(),
+                            compilation_stats_.get()));
   if (codegen.get() == nullptr) {
     MaybeRecordStat(MethodCompilationStat::kNotCompiledNoCodegen);
     return nullptr;
@@ -891,7 +893,7 @@
   }
 
   size_t stack_map_size = codegen->ComputeStackMapsSize();
-  uint8_t* stack_map_data = code_cache->ReserveData(self, stack_map_size);
+  uint8_t* stack_map_data = code_cache->ReserveData(self, stack_map_size, method);
   if (stack_map_data == nullptr) {
     return false;
   }
@@ -945,6 +947,8 @@
                                  elf_file.size());
   }
 
+  Runtime::Current()->GetJit()->AddMemoryUsage(method, arena.BytesUsed());
+
   return true;
 }
 
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 179004b..3717926 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -60,6 +60,10 @@
   kIntrinsicRecognized,
   kLoopInvariantMoved,
   kSelectGenerated,
+  kRemovedInstanceOf,
+  kInlinedInvokeVirtualOrInterface,
+  kImplicitNullCheckGenerated,
+  kExplicitNullCheckGenerated,
   kLastStat
 };
 
@@ -133,6 +137,10 @@
       case kIntrinsicRecognized : name = "IntrinsicRecognized"; break;
       case kLoopInvariantMoved : name = "LoopInvariantMoved"; break;
       case kSelectGenerated : name = "SelectGenerated"; break;
+      case kRemovedInstanceOf: name = "RemovedInstanceOf"; break;
+      case kInlinedInvokeVirtualOrInterface: name = "InlinedInvokeVirtualOrInterface"; break;
+      case kImplicitNullCheckGenerated: name = "ImplicitNullCheckGenerated"; break;
+      case kExplicitNullCheckGenerated: name = "ExplicitNullCheckGenerated"; break;
 
       case kLastStat:
         LOG(FATAL) << "invalid stat "
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ce4f38a..2981011 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -255,6 +255,7 @@
   UsageError("");
   UsageError("  --compiler-filter="
                 "(verify-none"
+                "|verify-at-runtime"
                 "|interpret-only"
                 "|space"
                 "|balanced"
@@ -287,8 +288,8 @@
   UsageError("");
   UsageError("  --num-dex-methods=<method-count>: threshold size for a small dex file for");
   UsageError("      compiler filter tuning. If the input has fewer than this many methods");
-  UsageError("      and the filter is not interpret-only or verify-none, overrides the");
-  UsageError("      filter to use speed");
+  UsageError("      and the filter is not interpret-only or verify-none or verify-at-runtime, ");
+  UsageError("      overrides the filter to use speed");
   UsageError("      Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
   UsageError("      Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
   UsageError("");
@@ -317,7 +318,7 @@
   UsageError("  -g");
   UsageError("  --generate-debug-info: Generate debug information for native debugging,");
   UsageError("      such as stack unwinding information, ELF symbols and DWARF sections.");
-  UsageError("      If used without --native-debuggable, it will be best-effort only.");
+  UsageError("      If used without --debuggable, it will be best-effort only.");
   UsageError("      This option does not affect the generated code. (disabled by default)");
   UsageError("");
   UsageError("  --no-generate-debug-info: Do not generate debug information for native debugging.");
@@ -325,13 +326,10 @@
   UsageError("  --generate-mini-debug-info: Generate minimal amount of LZMA-compressed");
   UsageError("      debug information necessary to print backtraces. (disabled by default)");
   UsageError("");
-  UsageError("  --no-generate-mini-debug-info: Do do generated backtrace info.");
+  UsageError("  --no-generate-mini-debug-info: Do not generate backtrace info.");
   UsageError("");
   UsageError("  --debuggable: Produce code debuggable with Java debugger.");
   UsageError("");
-  UsageError("  --native-debuggable: Produce code debuggable with native debugger (like LLDB).");
-  UsageError("      Implies --debuggable.");
-  UsageError("");
   UsageError("  --runtime-arg <argument>: used to specify various arguments for the runtime,");
   UsageError("      such as initial heap size, maximum heap size, and verbose output.");
   UsageError("      Use a separate --runtime-arg switch for each argument.");
@@ -1037,7 +1035,7 @@
         compiler_options_->debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue);
     key_value_store_->Put(
         OatHeader::kNativeDebuggableKey,
-        compiler_options_->native_debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+        compiler_options_->GetNativeDebuggable() ? OatHeader::kTrueValue : OatHeader::kFalseValue);
     if (compiler_options_->IsExtractOnly()) {
       key_value_store_->Put(OatHeader::kCompilationType, OatHeader::kExtractOnlyValue);
     } else if (UseProfileGuidedCompilation()) {
@@ -1452,8 +1450,8 @@
     }
 
     /*
-     * If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
-     * Don't bother to check if we're doing the image.
+     * If we're not in interpret-only or verify-none or verify-at-runtime mode, go ahead and
+     * compile small applications.  Don't bother to check if we're doing the image.
      */
     if (!IsBootImage() &&
         compiler_options_->IsCompilationEnabled() &&
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 84660a3..f70e696 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -140,7 +140,6 @@
   native/java_lang_Class.cc \
   native/java_lang_DexCache.cc \
   native/java_lang_Object.cc \
-  native/java_lang_Runtime.cc \
   native/java_lang_String.cc \
   native/java_lang_StringFactory.cc \
   native/java_lang_System.cc \
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index 03980e3..c7a0ba2 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -26,6 +26,7 @@
 
 #include "base/bit_utils.h"
 #include "base/time_utils.h"
+#include "utils.h"
 
 namespace art {
 
@@ -200,6 +201,13 @@
 }
 
 template <class Value>
+inline void Histogram<Value>::PrintMemoryUse(std::ostream &os) const {
+  os << Name()
+     << ": Avg: " << PrettySize(Mean()) << " Max: "
+     << PrettySize(Max()) << " Min: " << PrettySize(Min()) << "\n";
+}
+
+template <class Value>
 inline void Histogram<Value>::CreateHistogram(CumulativeData* out_data) const {
   DCHECK_GT(sample_size_, 0ull);
   out_data->freq_.clear();
diff --git a/runtime/base/histogram.h b/runtime/base/histogram.h
index ef3a5d7..bcb7b3b 100644
--- a/runtime/base/histogram.h
+++ b/runtime/base/histogram.h
@@ -59,6 +59,7 @@
   double Percentile(double per, const CumulativeData& data) const;
   void PrintConfidenceIntervals(std::ostream& os, double interval,
                                 const CumulativeData& data) const;
+  void PrintMemoryUse(std::ostream& os) const;
   void PrintBins(std::ostream& os, const CumulativeData& data) const;
   void DumpBins(std::ostream& os) const;
   Value GetRange(size_t bucket_idx) const;
diff --git a/runtime/base/length_prefixed_array.h b/runtime/base/length_prefixed_array.h
index d632871..8060263 100644
--- a/runtime/base/length_prefixed_array.h
+++ b/runtime/base/length_prefixed_array.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_
 
 #include <stddef.h>  // for offsetof()
+#include <string.h>  // for memset()
 
 #include "stride_iterator.h"
 #include "base/bit_utils.h"
@@ -84,6 +85,13 @@
     size_ = dchecked_integral_cast<uint32_t>(length);
   }
 
+  // Clear the potentially uninitialized padding between the size_ and actual data.
+  void ClearPadding(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
+    size_t gap_offset = offsetof(LengthPrefixedArray<T>, data);
+    size_t gap_size = OffsetOfElement(0, element_size, alignment) - gap_offset;
+    memset(reinterpret_cast<uint8_t*>(this) + gap_offset, 0, gap_size);
+  }
+
  private:
   T& AtUnchecked(size_t index, size_t element_size, size_t alignment) {
     return *reinterpret_cast<T*>(
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 52beb15..3c69323 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2528,8 +2528,18 @@
   size_t num_32 = 0;
   size_t num_64 = 0;
   if (class_data != nullptr) {
+    // We allow duplicate definitions of the same field in a class_data_item
+    // but ignore the repeated indexes here, b/21868015.
+    uint32_t last_field_idx = DexFile::kDexNoIndex;
     for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) {
-      const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex());
+      uint32_t field_idx = it.GetMemberIndex();
+      // Ordering enforced by DexFileVerifier.
+      DCHECK(last_field_idx == DexFile::kDexNoIndex || last_field_idx <= field_idx);
+      if (UNLIKELY(field_idx == last_field_idx)) {
+        continue;
+      }
+      last_field_idx = field_idx;
+      const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
       const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
       char c = descriptor[0];
       switch (c) {
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index b107b72..a0c6bfb 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -83,7 +83,8 @@
       deoptimized_methods_lock_("deoptimized methods lock"),
       deoptimization_enabled_(false),
       interpreter_handler_table_(kMainHandlerTable),
-      quick_alloc_entry_points_instrumentation_counter_(0) {
+      quick_alloc_entry_points_instrumentation_counter_(0),
+      alloc_entrypoints_instrumented_(false) {
 }
 
 void Instrumentation::InstallStubsForClass(mirror::Class* klass) {
@@ -642,10 +643,12 @@
     MutexLock mu(self, *Locks::runtime_shutdown_lock_);
     SetQuickAllocEntryPointsInstrumented(instrumented);
     ResetQuickAllocEntryPoints();
+    alloc_entrypoints_instrumented_ = instrumented;
   } else {
     MutexLock mu(self, *Locks::runtime_shutdown_lock_);
     SetQuickAllocEntryPointsInstrumented(instrumented);
     ResetQuickAllocEntryPoints();
+    alloc_entrypoints_instrumented_ = instrumented;
   }
 }
 
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index b3cdb41..d07f47b 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -422,7 +422,7 @@
   // Does not hold lock, used to check if someone changed from not instrumented to instrumented
   // during a GC suspend point.
   bool AllocEntrypointsInstrumented() const SHARED_REQUIRES(Locks::mutator_lock_) {
-    return quick_alloc_entry_points_instrumentation_counter_ > 0;
+    return alloc_entrypoints_instrumented_;
   }
 
  private:
@@ -579,6 +579,12 @@
 
   // Greater than 0 if quick alloc entry points instrumented.
   size_t quick_alloc_entry_points_instrumentation_counter_;
+
+  // alloc_entrypoints_instrumented_ is only updated with all the threads suspended, this is done
+  // to prevent races with the GC where the GC relies on thread suspension only see
+  // alloc_entrypoints_instrumented_ change during suspend points.
+  bool alloc_entrypoints_instrumented_;
+
   friend class InstrumentationTest;  // For GetCurrentInstrumentationLevel and ConfigureStubs.
 
   DISALLOW_COPY_AND_ASSIGN(Instrumentation);
diff --git a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
index db18aa7..9868f41 100644
--- a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
+++ b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
@@ -3,9 +3,9 @@
     ubfx    w2, wINST, #8, #4           // w2<- A
     GET_VREG_WIDE d1, w1                // d1<- vB
     GET_VREG_WIDE d0, w2                // d0<- vA
-    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
     bl fmod
     ubfx    w2, wINST, #8, #4           // w2<- A (need to reload - killed across call)
+    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
     GET_INST_OPCODE ip                  // extract opcode from rINST
     SET_VREG_WIDE d0, w2                // vAA<- result
     GOTO_OPCODE ip                      // jump to next instruction
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index cdb27e8..6ae59d8 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -5984,9 +5984,9 @@
     ubfx    w2, wINST, #8, #4           // w2<- A
     GET_VREG_WIDE d1, w1                // d1<- vB
     GET_VREG_WIDE d0, w2                // d0<- vA
-    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
     bl fmod
     ubfx    w2, wINST, #8, #4           // w2<- A (need to reload - killed across call)
+    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
     GET_INST_OPCODE ip                  // extract opcode from rINST
     SET_VREG_WIDE d0, w2                // vAA<- result
     GOTO_OPCODE ip                      // jump to next instruction
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index f08a1a9..d9d7a19 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -58,6 +58,10 @@
     __asm__("");
   }
 
+  // Call __jit_debug_register_code indirectly via global variable.
+  // This gives the debugger an easy way to inject custom code to handle the events.
+  void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
+
   // GDB will inspect contents of this descriptor.
   // Static initialization is necessary to prevent GDB from seeing
   // uninitialized descriptor.
@@ -85,7 +89,7 @@
   __jit_debug_descriptor.relevant_entry_ = entry;
 
   __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
-  __jit_debug_register_code();
+  (*__jit_debug_register_code_ptr)();
   return entry;
 }
 
@@ -102,7 +106,7 @@
 
   __jit_debug_descriptor.relevant_entry_ = entry;
   __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
-  __jit_debug_register_code();
+  (*__jit_debug_register_code_ptr)();
   delete[] entry->symfile_addr_;
   delete entry;
 }
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 5bd9a6b..7e73e5c 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -83,6 +83,8 @@
 void Jit::DumpInfo(std::ostream& os) {
   code_cache_->Dump(os);
   cumulative_timings_.Dump(os);
+  MutexLock mu(Thread::Current(), lock_);
+  memory_use_.PrintMemoryUse(os);
 }
 
 void Jit::AddTimingLogger(const TimingLogger& logger) {
@@ -95,6 +97,8 @@
              jit_compile_method_(nullptr),
              dump_info_on_shutdown_(false),
              cumulative_timings_("JIT timings"),
+             memory_use_("Memory used for compilation", 16),
+             lock_("JIT memory use lock"),
              save_profiling_info_(false),
              generate_debug_info_(false) {
 }
@@ -433,5 +437,16 @@
   return true;
 }
 
+void Jit::AddMemoryUsage(ArtMethod* method, size_t bytes) {
+  if (bytes > 4 * MB) {
+    LOG(INFO) << "Compiler allocated "
+              << PrettySize(bytes)
+              << " to compile "
+              << PrettyMethod(method);
+  }
+  MutexLock mu(Thread::Current(), lock_);
+  memory_use_.AddValue(bytes);
+}
+
 }  // namespace jit
 }  // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index d5c2134..37d0bdb 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -17,14 +17,11 @@
 #ifndef ART_RUNTIME_JIT_JIT_H_
 #define ART_RUNTIME_JIT_JIT_H_
 
-#include <unordered_map>
-
-#include "atomic.h"
+#include "base/arena_allocator.h"
+#include "base/histogram-inl.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
-#include "gc_root.h"
-#include "jni.h"
 #include "object_callbacks.h"
 #include "offline_profiling_info.h"
 #include "thread_pool.h"
@@ -62,9 +59,14 @@
   void DeleteThreadPool();
   // Dump interesting info: #methods compiled, code vs data size, compile / verify cumulative
   // loggers.
-  void DumpInfo(std::ostream& os);
+  void DumpInfo(std::ostream& os) REQUIRES(!lock_);
   // Add a timing logger to cumulative_timings_.
   void AddTimingLogger(const TimingLogger& logger);
+
+  void AddMemoryUsage(ArtMethod* method, size_t bytes)
+      REQUIRES(!lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   JitInstrumentationCache* GetInstrumentationCache() const {
     return instrumentation_cache_.get();
   }
@@ -82,7 +84,7 @@
                          const std::string& app_dir);
   void StopProfileSaver();
 
-  void DumpForSigQuit(std::ostream& os) {
+  void DumpForSigQuit(std::ostream& os) REQUIRES(!lock_) {
     DumpInfo(os);
   }
 
@@ -125,6 +127,8 @@
   // Performance monitoring.
   bool dump_info_on_shutdown_;
   CumulativeLogger cumulative_timings_;
+  Histogram<uint64_t> memory_use_ GUARDED_BY(lock_);
+  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
 
   std::unique_ptr<jit::JitInstrumentationCache> instrumentation_cache_;
   std::unique_ptr<jit::JitCodeCache> code_cache_;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index af47da6..c681ed7 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -40,6 +40,9 @@
 static constexpr int kProtData = PROT_READ | PROT_WRITE;
 static constexpr int kProtCode = PROT_READ | PROT_EXEC;
 
+static constexpr size_t kCodeSizeLogThreshold = 50 * KB;
+static constexpr size_t kStackMapSizeLogThreshold = 50 * KB;
+
 #define CHECKED_MPROTECT(memory, size, prot)                \
   do {                                                      \
     int rc = mprotect(memory, size, prot);                  \
@@ -134,7 +137,10 @@
       number_of_compilations_(0),
       number_of_osr_compilations_(0),
       number_of_deoptimizations_(0),
-      number_of_collections_(0) {
+      number_of_collections_(0),
+      histogram_stack_map_memory_use_("Memory used for stack maps", 16),
+      histogram_code_memory_use_("Memory used for compiled code", 16),
+      histogram_profiling_info_memory_use_("Memory used for profiling info", 16) {
 
   DCHECK_GE(max_capacity, initial_code_capacity + initial_data_capacity);
   code_mspace_ = create_mspace_with_base(code_map_->Begin(), code_end_, false /*locked*/);
@@ -377,6 +383,13 @@
         << " dcache_size=" << PrettySize(DataCacheSizeLocked()) << ": "
         << reinterpret_cast<const void*>(method_header->GetEntryPoint()) << ","
         << reinterpret_cast<const void*>(method_header->GetEntryPoint() + method_header->code_size_);
+    histogram_code_memory_use_.AddValue(code_size);
+    if (code_size > kCodeSizeLogThreshold) {
+      LOG(INFO) << "JIT allocated "
+                << PrettySize(code_size)
+                << " for compiled code of "
+                << PrettyMethod(method);
+    }
   }
 
   return reinterpret_cast<uint8_t*>(method_header);
@@ -405,7 +418,7 @@
   FreeData(reinterpret_cast<uint8_t*>(data));
 }
 
-uint8_t* JitCodeCache::ReserveData(Thread* self, size_t size) {
+uint8_t* JitCodeCache::ReserveData(Thread* self, size_t size, ArtMethod* method) {
   size = RoundUp(size, sizeof(void*));
   uint8_t* result = nullptr;
 
@@ -425,15 +438,14 @@
     result = AllocateData(size);
   }
 
-  return result;
-}
-
-uint8_t* JitCodeCache::AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) {
-  uint8_t* result = ReserveData(self, end - begin);
-  if (result == nullptr) {
-    return nullptr;  // Out of space in the data cache.
+  MutexLock mu(self, lock_);
+  histogram_stack_map_memory_use_.AddValue(size);
+  if (size > kStackMapSizeLogThreshold) {
+    LOG(INFO) << "JIT allocated "
+              << PrettySize(size)
+              << " for stack maps of "
+              << PrettyMethod(method);
   }
-  std::copy(begin, end, result);
   return result;
 }
 
@@ -868,6 +880,7 @@
 
   method->SetProfilingInfo(info);
   profiling_infos_.push_back(info);
+  histogram_profiling_info_memory_use_.AddValue(profile_info_size);
   return info;
 }
 
@@ -1021,6 +1034,9 @@
         << number_of_osr_compilations_ << "\n"
      << "Total number of deoptimizations: " << number_of_deoptimizations_ << "\n"
      << "Total number of JIT code cache collections: " << number_of_collections_ << std::endl;
+  histogram_stack_map_memory_use_.PrintMemoryUse(os);
+  histogram_code_memory_use_.PrintMemoryUse(os);
+  histogram_profiling_info_memory_use_.PrintMemoryUse(os);
 }
 
 }  // namespace jit
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 98dd70d..a54f04f 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -20,6 +20,7 @@
 #include "instrumentation.h"
 
 #include "atomic.h"
+#include "base/histogram-inl.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "gc/accounting/bitmap.h"
@@ -109,7 +110,7 @@
   bool ContainsMethod(ArtMethod* method) REQUIRES(!lock_);
 
   // Reserve a region of data of size at least "size". Returns null if there is no more room.
-  uint8_t* ReserveData(Thread* self, size_t size)
+  uint8_t* ReserveData(Thread* self, size_t size, ArtMethod* method)
       SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!lock_);
 
@@ -118,12 +119,6 @@
       SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!lock_);
 
-  // Add a data array of size (end - begin) with the associated contents, returns null if there
-  // is no more room.
-  uint8_t* AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end)
-      SHARED_REQUIRES(Locks::mutator_lock_)
-      REQUIRES(!lock_);
-
   CodeCacheBitmap* GetLiveBitmap() const {
     return live_bitmap_.get();
   }
@@ -332,6 +327,15 @@
   // Number of code cache collections done throughout the lifetime of the JIT.
   size_t number_of_collections_ GUARDED_BY(lock_);
 
+  // Histograms for keeping track of stack map size statistics.
+  Histogram<uint64_t> histogram_stack_map_memory_use_ GUARDED_BY(lock_);
+
+  // Histograms for keeping track of code size statistics.
+  Histogram<uint64_t> histogram_code_memory_use_ GUARDED_BY(lock_);
+
+  // Histograms for keeping track of profiling info statistics.
+  Histogram<uint64_t> histogram_profiling_info_memory_use_ GUARDED_BY(lock_);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(JitCodeCache);
 };
 
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index a092b9f..65002df 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -119,7 +119,8 @@
   }
 
   if ((debug_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
-    runtime->AddCompilerOption("--native-debuggable");
+    runtime->AddCompilerOption("--debuggable");
+    runtime->AddCompilerOption("--generate-debug-info");
     debug_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
   }
 
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
deleted file mode 100644
index df794e1..0000000
--- a/runtime/native/java_lang_Runtime.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-#include "java_lang_Runtime.h"
-
-#include <dlfcn.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include "base/macros.h"
-#include "gc/heap.h"
-#include "handle_scope-inl.h"
-#include "jni_internal.h"
-#include "mirror/class_loader.h"
-#include "runtime.h"
-#include "scoped_thread_state_change.h"
-#include "ScopedUtfChars.h"
-#include "verify_object-inl.h"
-
-#include <sstream>
-#ifdef __ANDROID__
-// This function is provided by android linker.
-extern "C" void android_update_LD_LIBRARY_PATH(const char* ld_library_path);
-#endif  // __ANDROID__
-
-namespace art {
-
-static void Runtime_gc(JNIEnv*, jclass) {
-  if (Runtime::Current()->IsExplicitGcDisabled()) {
-      LOG(INFO) << "Explicit GC skipped.";
-      return;
-  }
-  Runtime::Current()->GetHeap()->CollectGarbage(false);
-}
-
-NO_RETURN static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
-  LOG(INFO) << "System.exit called, status: " << status;
-  Runtime::Current()->CallExitHook(status);
-  exit(status);
-}
-
-static void SetLdLibraryPath(JNIEnv* env, jstring javaLdLibraryPath) {
-#ifdef __ANDROID__
-  if (javaLdLibraryPath != nullptr) {
-    ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath);
-    if (ldLibraryPath.c_str() != nullptr) {
-      android_update_LD_LIBRARY_PATH(ldLibraryPath.c_str());
-    }
-  }
-
-#else
-  LOG(WARNING) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!";
-  UNUSED(javaLdLibraryPath, env);
-#endif
-}
-
-static jstring Runtime_nativeLoad(JNIEnv* env,
-                                  jclass,
-                                  jstring javaFilename,
-                                  jobject javaLoader,
-                                  jstring javaLibrarySearchPath) {
-  ScopedUtfChars filename(env, javaFilename);
-  if (filename.c_str() == nullptr) {
-    return nullptr;
-  }
-
-  int32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
-
-  // Starting with N nativeLoad uses classloader local
-  // linker namespace instead of global LD_LIBRARY_PATH
-  // (23 is Marshmallow). This call is here to preserve
-  // backwards compatibility for the apps targeting sdk
-  // version <= 23
-  if (target_sdk_version == 0) {
-    SetLdLibraryPath(env, javaLibrarySearchPath);
-  }
-
-  std::string error_msg;
-  {
-    JavaVMExt* vm = Runtime::Current()->GetJavaVM();
-    bool success = vm->LoadNativeLibrary(env,
-                                         filename.c_str(),
-                                         javaLoader,
-                                         javaLibrarySearchPath,
-                                         &error_msg);
-    if (success) {
-      return nullptr;
-    }
-  }
-
-  // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
-  env->ExceptionClear();
-  return env->NewStringUTF(error_msg.c_str());
-}
-
-static jlong Runtime_maxMemory(JNIEnv*, jclass) {
-  return Runtime::Current()->GetHeap()->GetMaxMemory();
-}
-
-static jlong Runtime_totalMemory(JNIEnv*, jclass) {
-  return Runtime::Current()->GetHeap()->GetTotalMemory();
-}
-
-static jlong Runtime_freeMemory(JNIEnv*, jclass) {
-  return Runtime::Current()->GetHeap()->GetFreeMemory();
-}
-
-static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Runtime, freeMemory, "!()J"),
-  NATIVE_METHOD(Runtime, gc, "()V"),
-  NATIVE_METHOD(Runtime, maxMemory, "!()J"),
-  NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
-  NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),
-  NATIVE_METHOD(Runtime, totalMemory, "!()J"),
-};
-
-void register_java_lang_Runtime(JNIEnv* env) {
-  REGISTER_NATIVE_METHODS("java/lang/Runtime");
-}
-
-}  // namespace art
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index d377457..aff9b61 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -342,15 +342,15 @@
 
   // Starting with N nativeLoad uses classloader local
   // linker namespace instead of global LD_LIBRARY_PATH
-  // (23 is Marshmallow)
-  if (target_sdk_version <= 23) {
+  // (23 is Marshmallow). This call is here to preserve
+  // backwards compatibility for the apps targeting sdk
+  // version <= 23
+  if (target_sdk_version == 0) {
     SetLdLibraryPath(env, javaLibrarySearchPath);
   }
 
   std::string error_msg;
   {
-    art::ScopedObjectAccess soa(env);
-    art::StackHandleScope<1> hs(soa.Self());
     art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
     bool success = vm->LoadNativeLibrary(env,
                                          filename.c_str(),
diff --git a/runtime/primitive.h b/runtime/primitive.h
index 2454a21..9c19ad5 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -166,6 +166,20 @@
     return type == kPrimLong || type == kPrimDouble;
   }
 
+  // Return the general kind of `type`, fusing integer-like types as kPrimInt.
+  static Type PrimitiveKind(Type type) {
+    switch (type) {
+      case kPrimBoolean:
+      case kPrimByte:
+      case kPrimShort:
+      case kPrimChar:
+      case kPrimInt:
+        return kPrimInt;
+      default:
+        return type;
+    }
+  }
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
 };
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 66a3828..364ae5d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -94,7 +94,6 @@
 #include "native/java_lang_Class.h"
 #include "native/java_lang_DexCache.h"
 #include "native/java_lang_Object.h"
-#include "native/java_lang_Runtime.h"
 #include "native/java_lang_String.h"
 #include "native/java_lang_StringFactory.h"
 #include "native/java_lang_System.h"
@@ -1341,7 +1340,6 @@
   register_java_lang_reflect_Method(env);
   register_java_lang_reflect_Proxy(env);
   register_java_lang_ref_Reference(env);
-  register_java_lang_Runtime(env);
   register_java_lang_String(env);
   register_java_lang_StringFactory(env);
   register_java_lang_System(env);
diff --git a/test/003-omnibus-opcodes/src/FloatMath.java b/test/003-omnibus-opcodes/src/FloatMath.java
index 96befe9..fcdb4fe 100644
--- a/test/003-omnibus-opcodes/src/FloatMath.java
+++ b/test/003-omnibus-opcodes/src/FloatMath.java
@@ -135,7 +135,8 @@
     static float[] floatOperTest(float x, float y) {
         System.out.println("FloatMath.floatOperTest");
 
-        float[] results = new float[9];
+        float[] results = new float[10];
+        float tmp;
 
         /* this seems to generate "op-float" instructions */
         results[0] = x + y;
@@ -145,7 +146,21 @@
         results[4] = x % -y;
 
         /* this seems to generate "op-float/2addr" instructions */
-        results[8] = x + (((((x + y) - y) * y) / y) % y);
+        tmp = x;
+        tmp += y;
+        results[5] = tmp;
+        tmp = x;
+        tmp -= y;
+        results[6] = tmp;
+        tmp = x;
+        tmp *= y;
+        results[7] = tmp;
+        tmp = x;
+        tmp /= y;
+        results[8] = tmp;
+        tmp = x;
+        tmp %= -y;
+        results[9] = tmp;
 
         return results;
     }
@@ -155,7 +170,11 @@
         Main.assertTrue(results[2] > -210000.01f && results[2] < -209999.99f);
         Main.assertTrue(results[3] > -23333.34f && results[3] < -23333.32f);
         Main.assertTrue(results[4] > 0.999f && results[4] < 1.001f);
-        Main.assertTrue(results[8] > 70000.99f && results[8] < 70001.01f);
+        Main.assertTrue(results[5] > 69996.99f && results[5] < 69997.01f);
+        Main.assertTrue(results[6] > 70002.99f && results[6] < 70003.01f);
+        Main.assertTrue(results[7] > -210000.01f && results[7] < -209999.99f);
+        Main.assertTrue(results[8] > -23333.34f && results[8] < -23333.32f);
+        Main.assertTrue(results[9] > 0.999f && results[9] < 1.001f);
     }
 
     /*
@@ -165,7 +184,8 @@
     static double[] doubleOperTest(double x, double y) {
         System.out.println("FloatMath.doubleOperTest");
 
-        double[] results = new double[9];
+        double[] results = new double[10];
+        double tmp;
 
         /* this seems to generate "op-double" instructions */
         results[0] = x + y;
@@ -175,7 +195,21 @@
         results[4] = x % -y;
 
         /* this seems to generate "op-double/2addr" instructions */
-        results[8] = x + (((((x + y) - y) * y) / y) % y);
+        tmp = x;
+        tmp += y;
+        results[5] = tmp;
+        tmp = x;
+        tmp -= y;
+        results[6] = tmp;
+        tmp = x;
+        tmp *= y;
+        results[7] = tmp;
+        tmp = x;
+        tmp /= y;
+        results[8] = tmp;
+        tmp = x;
+        tmp %= -y;
+        results[9] = tmp;
 
         return results;
     }
@@ -185,7 +219,11 @@
         Main.assertTrue(results[2] > -210000.01 && results[2] < -209999.99);
         Main.assertTrue(results[3] > -23333.34 && results[3] < -23333.32);
         Main.assertTrue(results[4] > 0.999 && results[4] < 1.001);
-        Main.assertTrue(results[8] > 70000.99 && results[8] < 70001.01);
+        Main.assertTrue(results[5] > 69996.99 && results[5] < 69997.01);
+        Main.assertTrue(results[6] > 70002.99 && results[6] < 70003.01);
+        Main.assertTrue(results[7] > -210000.01 && results[7] < -209999.99);
+        Main.assertTrue(results[8] > -23333.34 && results[8] < -23333.32);
+        Main.assertTrue(results[9] > 0.999 && results[9] < 1.001);
     }
 
     /*
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index f7c721a..53c2e0b 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -414,6 +414,23 @@
     return arg >> 0;
   }
 
+  /// CHECK-START: long Main.Shr64(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const64:i\d+>>  IntConstant 64
+  /// CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Arg>>,<<Const64>>]
+  /// CHECK-DAG:                       Return [<<Shr>>]
+
+  /// CHECK-START: long Main.Shr64(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
+
+  /// CHECK-START: long Main.Shr64(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Shr
+
+  public static long Shr64(long arg) {
+    return arg >> 64;
+  }
+
   /// CHECK-START: long Main.Sub0(long) instruction_simplifier (before)
   /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
   /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
@@ -1671,6 +1688,7 @@
     assertLongEquals(OrSame(arg), arg);
     assertIntEquals(Shl0(arg), arg);
     assertLongEquals(Shr0(arg), arg);
+    assertLongEquals(Shr64(arg), arg);
     assertLongEquals(Sub0(arg), arg);
     assertIntEquals(SubAliasNeg(arg), -arg);
     assertLongEquals(UShr0(arg), arg);
diff --git a/test/529-checker-unresolved/build b/test/529-checker-unresolved/build
deleted file mode 100644
index d85035b..0000000
--- a/test/529-checker-unresolved/build
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-# Stop if something fails.
-set -e
-
-# We can't use src-ex testing infrastructure because src and src-ex are compiled
-# with javac independetely and can't share code (without reflection).
-
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-mv classes/UnresolvedClass.class classes-ex
-mv classes/UnresolvedInterface.class classes-ex
-mv classes/UnresolvedSuperClass.class classes-ex
-
-if [ ${USE_JACK} = "true" ]; then
-  jar cf classes.jill.jar -C classes .
-  jar cf classes-ex.jill.jar -C classes-ex .
-
-  ${JACK} --import classes.jill.jar --output-dex .
-  zip $TEST_NAME.jar classes.dex
-  ${JACK} --import classes-ex.jill.jar --output-dex .
-  zip ${TEST_NAME}-ex.jar classes.dex
-else
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
-    zip $TEST_NAME.jar classes.dex
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
-    zip ${TEST_NAME}-ex.jar classes.dex
-  fi
-fi
diff --git a/test/529-checker-unresolved/src/Unresolved.java b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedClass.java
similarity index 83%
rename from test/529-checker-unresolved/src/Unresolved.java
rename to test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedClass.java
index 20ac6e0..8b3bb3c 100644
--- a/test/529-checker-unresolved/src/Unresolved.java
+++ b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedClass.java
@@ -14,17 +14,7 @@
  * limitations under the License.
  */
 
-interface UnresolvedInterface {
-  void interfaceMethod();
-}
-
-class UnresolvedSuperClass {
-  public void superMethod() {
-    System.out.println("UnresolvedClass.superMethod()");
-  }
-}
-
-class UnresolvedClass extends UnresolvedSuperClass implements UnresolvedInterface {
+public class UnresolvedClass extends UnresolvedSuperClass implements UnresolvedInterface {
   static public void staticMethod() {
     System.out.println("UnresolvedClass.staticMethod()");
   }
diff --git a/runtime/native/java_lang_Runtime.h b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedInterface.java
similarity index 64%
rename from runtime/native/java_lang_Runtime.h
rename to test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedInterface.java
index ceda06b..6e6b14b 100644
--- a/runtime/native/java_lang_Runtime.h
+++ b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-#define ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-
-#include <jni.h>
-
-namespace art {
-
-void register_java_lang_Runtime(JNIEnv* env);
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
+public interface UnresolvedInterface {
+  void interfaceMethod();
+}
diff --git a/runtime/native/java_lang_Runtime.h b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedSuperClass.java
similarity index 64%
copy from runtime/native/java_lang_Runtime.h
copy to test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedSuperClass.java
index ceda06b..dd3be00 100644
--- a/runtime/native/java_lang_Runtime.h
+++ b/test/529-checker-unresolved/src-dex2oat-unresolved/UnresolvedSuperClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,15 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-#define ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-
-#include <jni.h>
-
-namespace art {
-
-void register_java_lang_Runtime(JNIEnv* env);
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
+public class UnresolvedSuperClass {
+  public void superMethod() {
+    System.out.println("UnresolvedClass.superMethod()");
+  }
+}
diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java
index 9c86154..edb8a68 100644
--- a/test/551-checker-shifter-operand/src/Main.java
+++ b/test/551-checker-shifter-operand/src/Main.java
@@ -483,9 +483,7 @@
   /// CHECK:                            Arm64DataProcWithShifterOp
   /// CHECK:                            Arm64DataProcWithShifterOp
   /// CHECK:                            Arm64DataProcWithShifterOp
-  /// CHECK:                            Arm64DataProcWithShifterOp
-  /// CHECK:                            Arm64DataProcWithShifterOp
-  /// CHECK:                            Arm64DataProcWithShifterOp
+  // Note: `b << 32`, `b >> 32` and `b >>> 32` are optimized away by generic simplifier.
 
   /// CHECK-START-ARM64: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm64 (after)
   /// CHECK-NOT:                        Shl
diff --git a/test/566-checker-signum/src/Main.java b/test/566-checker-signum/src/Main.java
index 0ad0042..5f2cf3d 100644
--- a/test/566-checker-signum/src/Main.java
+++ b/test/566-checker-signum/src/Main.java
@@ -16,65 +16,213 @@
 
 public class Main {
 
-  /// CHECK-START: int Main.sign32(int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerSignum
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int sign32(int x) {
+  /// CHECK-START: int Main.signBoolean(boolean) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<Phi>>,<<Method>>] intrinsic:IntegerSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signBoolean(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<Phi>>,<<Zero>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signBoolean(boolean) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.signBoolean(boolean) select_generator (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<Sel:i\d+>>    Select [<<Zero>>,<<One>>,<<Arg>>]
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<Sel>>,<<Zero>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signBoolean(boolean) select_generator (after)
+  /// CHECK-NOT:                     Phi
+
+  /// CHECK-START: int Main.signBoolean(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<Arg>>,<<Zero>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signBoolean(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                     Select
+
+  private static int signBoolean(boolean x) {
+    return Integer.signum(x ? 1 : 0);
+  }
+
+  /// CHECK-START: int Main.signByte(byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signByte(byte) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signByte(byte) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int signByte(byte x) {
     return Integer.signum(x);
   }
 
-  /// CHECK-START: int Main.sign64(long) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:LongSignum
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int sign64(long x) {
+  /// CHECK-START: int Main.signShort(short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signShort(short) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signShort(short) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int signShort(short x) {
+    return Integer.signum(x);
+  }
+
+  /// CHECK-START: int Main.signChar(char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signChar(char) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signChar(char) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int signChar(char x) {
+    return Integer.signum(x);
+  }
+
+  /// CHECK-START: int Main.signInt(int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signInt(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signInt(int) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int signInt(int x) {
+    return Integer.signum(x);
+  }
+
+  /// CHECK-START: int Main.signLong(long) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:LongSignum
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signLong(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.signLong(long) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int signLong(long x) {
     return Long.signum(x);
   }
 
-  public static void main(String args[]) {
-    expectEquals(-1, sign32(Integer.MIN_VALUE));
-    expectEquals(-1, sign32(-12345));
-    expectEquals(-1, sign32(-1));
-    expectEquals(0, sign32(0));
-    expectEquals(1, sign32(1));
-    expectEquals(1, sign32(12345));
-    expectEquals(1, sign32(Integer.MAX_VALUE));
+
+  public static void testSignBoolean() {
+    expectEquals(0, signBoolean(false));
+    expectEquals(1, signBoolean(true));
+  }
+
+  public static void testSignByte() {
+    expectEquals(-1, signByte((byte)Byte.MIN_VALUE));
+    expectEquals(-1, signByte((byte)-64));
+    expectEquals(-1, signByte((byte)-1));
+    expectEquals(0, signByte((byte)0));
+    expectEquals(1, signByte((byte)1));
+    expectEquals(1, signByte((byte)64));
+    expectEquals(1, signByte((byte)Byte.MAX_VALUE));
+  }
+
+  public static void testSignShort() {
+    expectEquals(-1, signShort((short)Short.MIN_VALUE));
+    expectEquals(-1, signShort((short)-12345));
+    expectEquals(-1, signShort((short)-1));
+    expectEquals(0, signShort((short)0));
+    expectEquals(1, signShort((short)1));
+    expectEquals(1, signShort((short)12345));
+    expectEquals(1, signShort((short)Short.MAX_VALUE));
+  }
+
+  public static void testSignChar() {
+    expectEquals(0, signChar((char)0));
+    expectEquals(1, signChar((char)1));
+    expectEquals(1, signChar((char)12345));
+    expectEquals(1, signChar((char)Character.MAX_VALUE));
+  }
+
+  public static void testSignInt() {
+    expectEquals(-1, signInt(Integer.MIN_VALUE));
+    expectEquals(-1, signInt(-12345));
+    expectEquals(-1, signInt(-1));
+    expectEquals(0, signInt(0));
+    expectEquals(1, signInt(1));
+    expectEquals(1, signInt(12345));
+    expectEquals(1, signInt(Integer.MAX_VALUE));
 
     for (int i = -11; i <= 11; i++) {
       int expected = 0;
       if (i < 0) expected = -1;
       else if (i > 0) expected = 1;
-      expectEquals(expected, sign32(i));
+      expectEquals(expected, signInt(i));
     }
+  }
 
-    expectEquals(-1, sign64(Long.MIN_VALUE));
-    expectEquals(-1, sign64(-12345L));
-    expectEquals(-1, sign64(-1L));
-    expectEquals(0, sign64(0L));
-    expectEquals(1, sign64(1L));
-    expectEquals(1, sign64(12345L));
-    expectEquals(1, sign64(Long.MAX_VALUE));
+  public static void testSignLong() {
+    expectEquals(-1, signLong(Long.MIN_VALUE));
+    expectEquals(-1, signLong(-12345L));
+    expectEquals(-1, signLong(-1L));
+    expectEquals(0, signLong(0L));
+    expectEquals(1, signLong(1L));
+    expectEquals(1, signLong(12345L));
+    expectEquals(1, signLong(Long.MAX_VALUE));
 
-    expectEquals(-1, sign64(0x800000007FFFFFFFL));
-    expectEquals(-1, sign64(0x80000000FFFFFFFFL));
-    expectEquals(1, sign64(0x000000007FFFFFFFL));
-    expectEquals(1, sign64(0x00000000FFFFFFFFL));
-    expectEquals(1, sign64(0x7FFFFFFF7FFFFFFFL));
-    expectEquals(1, sign64(0x7FFFFFFFFFFFFFFFL));
+    expectEquals(-1, signLong(0x800000007FFFFFFFL));
+    expectEquals(-1, signLong(0x80000000FFFFFFFFL));
+    expectEquals(1, signLong(0x000000007FFFFFFFL));
+    expectEquals(1, signLong(0x00000000FFFFFFFFL));
+    expectEquals(1, signLong(0x7FFFFFFF7FFFFFFFL));
+    expectEquals(1, signLong(0x7FFFFFFFFFFFFFFFL));
 
     for (long i = -11L; i <= 11L; i++) {
       int expected = 0;
       if (i < 0) expected = -1;
       else if (i > 0) expected = 1;
-      expectEquals(expected, sign64(i));
+      expectEquals(expected, signLong(i));
     }
 
     for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) {
-      expectEquals(-1, sign64(i));
+      expectEquals(-1, signLong(i));
     }
 
     for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) {
-      expectEquals(1, sign64(i));
+      expectEquals(1, signLong(i));
     }
+  }
+
+
+  public static void main(String args[]) {
+    testSignBoolean();
+    testSignByte();
+    testSignShort();
+    testSignChar();
+    testSignInt();
+    testSignLong();
 
     System.out.println("passed");
   }
diff --git a/test/567-checker-compare/src/Main.java b/test/567-checker-compare/src/Main.java
index 951d2c7..f95ff1a 100644
--- a/test/567-checker-compare/src/Main.java
+++ b/test/567-checker-compare/src/Main.java
@@ -16,98 +16,902 @@
 
 public class Main {
 
-  /// CHECK-START: int Main.compare32(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int compare32(int x, int y) {
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<PhiX:i\d+>>   Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<PhiY:i\d+>>   Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<PhiX>>,<<PhiY>>,<<Method>>] intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<PhiX:i\d+>>   Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<PhiY:i\d+>>   Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<PhiX>>,<<PhiY>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) select_generator (after)
+  /// CHECK:         <<ArgX:z\d+>>   ParameterValue
+  /// CHECK:         <<ArgY:z\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>    IntConstant 1
+  /// CHECK-DAG:     <<SelX:i\d+>>   Select [<<Zero>>,<<One>>,<<ArgX>>]
+  /// CHECK-DAG:     <<SelY:i\d+>>   Select [<<Zero>>,<<One>>,<<ArgY>>]
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<SelX>>,<<SelY>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) select_generator (after)
+  /// CHECK-NOT:                     Phi
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:         <<ArgX:z\d+>>   ParameterValue
+  /// CHECK:         <<ArgY:z\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>> Compare [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBooleans(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                     Select
+
+  private static int compareBooleans(boolean x, boolean y) {
+    return Integer.compare((x ? 1 : 0), (y ? 1 : 0));
+  }
+
+  /// CHECK-START: int Main.compareBytes(byte, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBytes(byte, byte) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareBytes(byte, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int compareBytes(byte x, byte y) {
     return Integer.compare(x, y);
   }
 
-  /// CHECK-START: int Main.compare64(long, long) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:LongCompare
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int compare64(long x, long y) {
+  /// CHECK-START: int Main.compareShorts(short, short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShorts(short, short) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShorts(short, short) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int compareShorts(short x, short y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareChars(char, char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareChars(char, char) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareChars(char, char) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int compareChars(char x, char y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareInts(int, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareInts(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareInts(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int compareInts(int x, int y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareLongs(long, long) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:LongCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareLongs(long, long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareLongs(long, long) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  private static int compareLongs(long x, long y) {
     return Long.compare(x, y);
   }
 
-  public static void main(String args[]) {
-    expectEquals(-1, compare32(Integer.MIN_VALUE, Integer.MIN_VALUE + 1));
-    expectEquals(-1, compare32(Integer.MIN_VALUE, -1));
-    expectEquals(-1, compare32(Integer.MIN_VALUE, 0));
-    expectEquals(-1, compare32(Integer.MIN_VALUE, 1));
-    expectEquals(-1, compare32(Integer.MIN_VALUE, Integer.MAX_VALUE));
-    expectEquals(-1, compare32(-1, 0));
-    expectEquals(-1, compare32(-1, 1));
-    expectEquals(-1, compare32(0, 1));
 
-    expectEquals(0, compare32(Integer.MIN_VALUE, Integer.MIN_VALUE));
-    expectEquals(0, compare32(-1, -1));
-    expectEquals(0, compare32(0, 0));
-    expectEquals(0, compare32(1, 1));
-    expectEquals(0, compare32(Integer.MAX_VALUE, Integer.MAX_VALUE));
+  /// CHECK-START: int Main.compareByteShort(byte, short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-    expectEquals(1, compare32(0, -1));
-    expectEquals(1, compare32(1, -1));
-    expectEquals(1, compare32(1, 0));
-    expectEquals(1, compare32(Integer.MAX_VALUE, Integer.MIN_VALUE));
-    expectEquals(1, compare32(Integer.MAX_VALUE, -1));
-    expectEquals(1, compare32(Integer.MAX_VALUE, 0));
-    expectEquals(1, compare32(Integer.MAX_VALUE, 1));
-    expectEquals(1, compare32(Integer.MAX_VALUE, Integer.MAX_VALUE - 1));
+  /// CHECK-START: int Main.compareByteShort(byte, short) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareByteShort(byte, short) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareByteShort(byte x, short y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareByteChar(byte, char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareByteChar(byte, char) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareByteChar(byte, char) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareByteChar(byte x, char y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareByteInt(byte, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareByteInt(byte, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareByteInt(byte, int) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareByteInt(byte x, int y) {
+    return Integer.compare(x, y);
+  }
+
+
+  /// CHECK-START: int Main.compareShortByte(short, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortByte(short, byte) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortByte(short, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareShortByte(short x, byte y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareShortChar(short, char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortChar(short, char) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortChar(short, char) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareShortChar(short x, char y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareShortInt(short, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortInt(short, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareShortInt(short, int) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareShortInt(short x, int y) {
+    return Integer.compare(x, y);
+  }
+
+
+  /// CHECK-START: int Main.compareCharByte(char, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharByte(char, byte) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharByte(char, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareCharByte(char x, byte y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareCharShort(char, short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharShort(char, short) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharShort(char, short) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareCharShort(char x, short y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareCharInt(char, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharInt(char, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareCharInt(char, int) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareCharInt(char x, int y) {
+    return Integer.compare(x, y);
+  }
+
+
+  /// CHECK-START: int Main.compareIntByte(int, byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntByte(int, byte) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntByte(int, byte) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareIntByte(int x, byte y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareIntShort(int, short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntShort(int, short) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntShort(int, short) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareIntShort(int x, short y) {
+    return Integer.compare(x, y);
+  }
+
+  /// CHECK-START: int Main.compareIntChar(int, char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerCompare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntChar(int, char) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Result:i\d+>> Compare
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.compareIntChar(int, char) instruction_simplifier (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int compareIntChar(int x, char y) {
+    return Integer.compare(x, y);
+  }
+
+
+  public static void testCompareBooleans() {
+    expectEquals(-1, compareBooleans(false, true));
+
+    expectEquals(0, compareBooleans(false, false));
+    expectEquals(0, compareBooleans(true, true));
+
+    expectEquals(1, compareBooleans(true, false));
+  }
+
+  public static void testCompareBytes() {
+    expectEquals(-1, compareBytes(Byte.MIN_VALUE, (byte)(Byte.MIN_VALUE + 1)));
+    expectEquals(-1, compareBytes(Byte.MIN_VALUE, (byte)-1));
+    expectEquals(-1, compareBytes(Byte.MIN_VALUE, (byte)0));
+    expectEquals(-1, compareBytes(Byte.MIN_VALUE, (byte)1));
+    expectEquals(-1, compareBytes(Byte.MIN_VALUE, Byte.MAX_VALUE));
+    expectEquals(-1, compareBytes((byte)-1, (byte)0));
+    expectEquals(-1, compareBytes((byte)-1, (byte)1));
+    expectEquals(-1, compareBytes((byte)0, (byte)1));
+
+    expectEquals(0, compareBytes(Byte.MIN_VALUE, Byte.MIN_VALUE));
+    expectEquals(0, compareBytes((byte)-1, (byte)-1));
+    expectEquals(0, compareBytes((byte)0, (byte)0));
+    expectEquals(0, compareBytes((byte)1, (byte)1));
+    expectEquals(0, compareBytes(Byte.MAX_VALUE, Byte.MAX_VALUE));
+
+    expectEquals(1, compareBytes((byte)0, (byte)-1));
+    expectEquals(1, compareBytes((byte)1, (byte)-1));
+    expectEquals(1, compareBytes((byte)1, (byte)0));
+    expectEquals(1, compareBytes(Byte.MAX_VALUE, Byte.MIN_VALUE));
+    expectEquals(1, compareBytes(Byte.MAX_VALUE, (byte)-1));
+    expectEquals(1, compareBytes(Byte.MAX_VALUE, (byte)0));
+    expectEquals(1, compareBytes(Byte.MAX_VALUE, (byte)1));
+    expectEquals(1, compareBytes(Byte.MAX_VALUE, (byte)(Byte.MAX_VALUE - 1)));
+
+    for (byte i = -11; i <= 11; i++) {
+      for (byte j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareBytes(i, j));
+      }
+    }
+  }
+
+  public static void testCompareShorts() {
+    expectEquals(-1, compareShorts(Short.MIN_VALUE, (short)(Short.MIN_VALUE + 1)));
+    expectEquals(-1, compareShorts(Short.MIN_VALUE, (short)-1));
+    expectEquals(-1, compareShorts(Short.MIN_VALUE, (short)0));
+    expectEquals(-1, compareShorts(Short.MIN_VALUE, (short)1));
+    expectEquals(-1, compareShorts(Short.MIN_VALUE, (short)Short.MAX_VALUE));
+    expectEquals(-1, compareShorts((short)-1, (short)0));
+    expectEquals(-1, compareShorts((short)-1, (short)1));
+    expectEquals(-1, compareShorts((short)0, (short)1));
+
+    expectEquals(0, compareShorts(Short.MIN_VALUE, Short.MIN_VALUE));
+    expectEquals(0, compareShorts((short)-1, (short)-1));
+    expectEquals(0, compareShorts((short)0, (short)0));
+    expectEquals(0, compareShorts((short)1, (short)1));
+    expectEquals(0, compareShorts(Short.MAX_VALUE, Short.MAX_VALUE));
+
+    expectEquals(1, compareShorts((short)0, (short)-1));
+    expectEquals(1, compareShorts((short)1, (short)-1));
+    expectEquals(1, compareShorts((short)1, (short)0));
+    expectEquals(1, compareShorts(Short.MAX_VALUE, Short.MIN_VALUE));
+    expectEquals(1, compareShorts(Short.MAX_VALUE, (short)-1));
+    expectEquals(1, compareShorts(Short.MAX_VALUE, (short)0));
+    expectEquals(1, compareShorts(Short.MAX_VALUE, (short)1));
+    expectEquals(1, compareShorts(Short.MAX_VALUE, (short)(Short.MAX_VALUE - 1)));
+
+    for (short i = -11; i <= 11; i++) {
+      for (short j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareShorts(i, j));
+      }
+    }
+  }
+
+  public static void testCompareChars() {
+    expectEquals(-1, compareChars((char)0, Character.MAX_VALUE));
+    expectEquals(-1, compareChars((char)0, (char)1));
+
+    expectEquals(0, compareChars((char)0, (char)0));
+    expectEquals(0, compareChars((char)1, (char)1));
+    expectEquals(0, compareChars(Character.MAX_VALUE, Character.MAX_VALUE));
+
+    expectEquals(1, compareChars((char)1, (char)0));
+    expectEquals(1, compareChars(Character.MAX_VALUE, (char)0));
+    expectEquals(1, compareChars(Character.MAX_VALUE, (char)1));
+    expectEquals(1, compareChars(Character.MAX_VALUE, (char)(Character.MAX_VALUE - 1)));
+
+    for (char i = 0; i <= 11; i++) {
+      for (char j = 0; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareChars(i, j));
+      }
+    }
+  }
+
+  public static void testCompareInts() {
+    expectEquals(-1, compareInts(Integer.MIN_VALUE, Integer.MIN_VALUE + 1));
+    expectEquals(-1, compareInts(Integer.MIN_VALUE, -1));
+    expectEquals(-1, compareInts(Integer.MIN_VALUE, 0));
+    expectEquals(-1, compareInts(Integer.MIN_VALUE, 1));
+    expectEquals(-1, compareInts(Integer.MIN_VALUE, Integer.MAX_VALUE));
+    expectEquals(-1, compareInts(-1, 0));
+    expectEquals(-1, compareInts(-1, 1));
+    expectEquals(-1, compareInts(0, 1));
+
+    expectEquals(0, compareInts(Integer.MIN_VALUE, Integer.MIN_VALUE));
+    expectEquals(0, compareInts(-1, -1));
+    expectEquals(0, compareInts(0, 0));
+    expectEquals(0, compareInts(1, 1));
+    expectEquals(0, compareInts(Integer.MAX_VALUE, Integer.MAX_VALUE));
+
+    expectEquals(1, compareInts(0, -1));
+    expectEquals(1, compareInts(1, -1));
+    expectEquals(1, compareInts(1, 0));
+    expectEquals(1, compareInts(Integer.MAX_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareInts(Integer.MAX_VALUE, -1));
+    expectEquals(1, compareInts(Integer.MAX_VALUE, 0));
+    expectEquals(1, compareInts(Integer.MAX_VALUE, 1));
+    expectEquals(1, compareInts(Integer.MAX_VALUE, Integer.MAX_VALUE - 1));
 
     for (int i = -11; i <= 11; i++) {
       for (int j = -11; j <= 11; j++) {
         int expected = 0;
         if (i < j) expected = -1;
         else if (i > j) expected = 1;
-        expectEquals(expected, compare32(i, j));
+        expectEquals(expected, compareInts(i, j));
       }
     }
+  }
 
-    expectEquals(-1, compare64(Long.MIN_VALUE, Long.MIN_VALUE + 1L));
-    expectEquals(-1, compare64(Long.MIN_VALUE, -1L));
-    expectEquals(-1, compare64(Long.MIN_VALUE, 0L));
-    expectEquals(-1, compare64(Long.MIN_VALUE, 1L));
-    expectEquals(-1, compare64(Long.MIN_VALUE, Long.MAX_VALUE));
-    expectEquals(-1, compare64(-1L, 0L));
-    expectEquals(-1, compare64(-1L, 1L));
-    expectEquals(-1, compare64(0L, 1L));
+  public static void testCompareLongs() {
+    expectEquals(-1, compareLongs(Long.MIN_VALUE, Long.MIN_VALUE + 1L));
+    expectEquals(-1, compareLongs(Long.MIN_VALUE, -1L));
+    expectEquals(-1, compareLongs(Long.MIN_VALUE, 0L));
+    expectEquals(-1, compareLongs(Long.MIN_VALUE, 1L));
+    expectEquals(-1, compareLongs(Long.MIN_VALUE, Long.MAX_VALUE));
+    expectEquals(-1, compareLongs(-1L, 0L));
+    expectEquals(-1, compareLongs(-1L, 1L));
+    expectEquals(-1, compareLongs(0L, 1L));
 
-    expectEquals(0, compare64(Long.MIN_VALUE, Long.MIN_VALUE));
-    expectEquals(0, compare64(-1L, -1L));
-    expectEquals(0, compare64(0L, 0L));
-    expectEquals(0, compare64(1L, 1L));
-    expectEquals(0, compare64(Long.MAX_VALUE, Long.MAX_VALUE));
+    expectEquals(0, compareLongs(Long.MIN_VALUE, Long.MIN_VALUE));
+    expectEquals(0, compareLongs(-1L, -1L));
+    expectEquals(0, compareLongs(0L, 0L));
+    expectEquals(0, compareLongs(1L, 1L));
+    expectEquals(0, compareLongs(Long.MAX_VALUE, Long.MAX_VALUE));
 
-    expectEquals(1, compare64(0L, -1L));
-    expectEquals(1, compare64(1L, -1L));
-    expectEquals(1, compare64(1L, 0L));
-    expectEquals(1, compare64(Long.MAX_VALUE, Long.MIN_VALUE));
-    expectEquals(1, compare64(Long.MAX_VALUE, -1L));
-    expectEquals(1, compare64(Long.MAX_VALUE, 0L));
-    expectEquals(1, compare64(Long.MAX_VALUE, 1L));
-    expectEquals(1, compare64(Long.MAX_VALUE, Long.MAX_VALUE - 1L));
+    expectEquals(1, compareLongs(0L, -1L));
+    expectEquals(1, compareLongs(1L, -1L));
+    expectEquals(1, compareLongs(1L, 0L));
+    expectEquals(1, compareLongs(Long.MAX_VALUE, Long.MIN_VALUE));
+    expectEquals(1, compareLongs(Long.MAX_VALUE, -1L));
+    expectEquals(1, compareLongs(Long.MAX_VALUE, 0L));
+    expectEquals(1, compareLongs(Long.MAX_VALUE, 1L));
+    expectEquals(1, compareLongs(Long.MAX_VALUE, Long.MAX_VALUE - 1L));
 
-    expectEquals(-1, compare64(0x111111117FFFFFFFL, 0x11111111FFFFFFFFL));
-    expectEquals(0, compare64(0x111111117FFFFFFFL, 0x111111117FFFFFFFL));
-    expectEquals(1, compare64(0x11111111FFFFFFFFL, 0x111111117FFFFFFFL));
+    expectEquals(-1, compareLongs(0x111111117FFFFFFFL, 0x11111111FFFFFFFFL));
+    expectEquals(0, compareLongs(0x111111117FFFFFFFL, 0x111111117FFFFFFFL));
+    expectEquals(1, compareLongs(0x11111111FFFFFFFFL, 0x111111117FFFFFFFL));
 
     for (long i = -11L; i <= 11L; i++) {
       for (long j = -11L; j <= 11L; j++) {
         int expected = 0;
         if (i < j) expected = -1;
         else if (i > j) expected = 1;
-        expectEquals(expected, compare64(i, j));
+        expectEquals(expected, compareLongs(i, j));
       }
     }
 
     for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) {
-      expectEquals(-1, compare64(i, 0));
+      expectEquals(-1, compareLongs(i, 0));
     }
 
     for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) {
-      expectEquals(1, compare64(i, 0));
+      expectEquals(1, compareLongs(i, 0));
     }
+  }
+
+
+  public static void testCompareByteShort() {
+    expectEquals(-1, compareByteShort(Byte.MIN_VALUE, (short)-1));
+    expectEquals(-1, compareByteShort(Byte.MIN_VALUE, (short)0));
+    expectEquals(-1, compareByteShort(Byte.MIN_VALUE, (short)1));
+    expectEquals(-1, compareByteShort(Byte.MIN_VALUE, Short.MAX_VALUE));
+    expectEquals(-1, compareByteShort((byte)-1, (short)0));
+    expectEquals(-1, compareByteShort((byte)-1, (short)1));
+    expectEquals(-1, compareByteShort((byte)0, (short)1));
+    expectEquals(-1, compareByteShort(Byte.MAX_VALUE, (short)(Short.MAX_VALUE - 1)));
+    expectEquals(-1, compareByteShort(Byte.MAX_VALUE, Short.MAX_VALUE));
+
+    expectEquals(0, compareByteShort((byte)-1, (short)-1));
+    expectEquals(0, compareByteShort((byte)0, (short)0));
+    expectEquals(0, compareByteShort((byte)1, (short)1));
+
+    expectEquals(1, compareByteShort(Byte.MIN_VALUE, Short.MIN_VALUE));
+    expectEquals(1, compareByteShort(Byte.MIN_VALUE, (short)(Short.MIN_VALUE + 1)));
+    expectEquals(1, compareByteShort((byte)0, (short)-1));
+    expectEquals(1, compareByteShort((byte)1, (short)-1));
+    expectEquals(1, compareByteShort((byte)1, (short)0));
+    expectEquals(1, compareByteShort(Byte.MAX_VALUE, Short.MIN_VALUE));
+    expectEquals(1, compareByteShort(Byte.MAX_VALUE, (short)-1));
+    expectEquals(1, compareByteShort(Byte.MAX_VALUE, (short)0));
+    expectEquals(1, compareByteShort(Byte.MAX_VALUE, (short)1));
+
+    for (byte i = -11; i <= 11; i++) {
+      for (short j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareByteShort(i, j));
+      }
+    }
+  }
+
+  public static void testCompareByteChar() {
+    expectEquals(-1, compareByteChar(Byte.MIN_VALUE, (char)0));
+    expectEquals(-1, compareByteChar(Byte.MIN_VALUE, (char)1));
+    expectEquals(-1, compareByteChar(Byte.MIN_VALUE, Character.MAX_VALUE));
+    expectEquals(-1, compareByteChar((byte)-1, (char)0));
+    expectEquals(-1, compareByteChar((byte)-1, (char)1));
+    expectEquals(-1, compareByteChar((byte)0, (char)1));
+    expectEquals(-1, compareByteChar(Byte.MAX_VALUE, (char)(Character.MAX_VALUE - 1)));
+    expectEquals(-1, compareByteChar(Byte.MAX_VALUE, Character.MAX_VALUE));
+
+    expectEquals(0, compareByteChar((byte)0, (char)0));
+    expectEquals(0, compareByteChar((byte)1, (char)1));
+
+    expectEquals(1, compareByteChar((byte)1, (char)0));
+    expectEquals(1, compareByteChar(Byte.MAX_VALUE, (char)0));
+    expectEquals(1, compareByteChar(Byte.MAX_VALUE, (char)1));
+
+    for (byte i = -11; i <= 11; i++) {
+      for (char j = 0; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareByteChar(i, j));
+      }
+    }
+  }
+
+  public static void testCompareByteInt() {
+    expectEquals(-1, compareByteInt(Byte.MIN_VALUE, -1));
+    expectEquals(-1, compareByteInt(Byte.MIN_VALUE, 0));
+    expectEquals(-1, compareByteInt(Byte.MIN_VALUE, 1));
+    expectEquals(-1, compareByteInt(Byte.MIN_VALUE, Integer.MAX_VALUE));
+    expectEquals(-1, compareByteInt((byte)-1, 0));
+    expectEquals(-1, compareByteInt((byte)-1, 1));
+    expectEquals(-1, compareByteInt((byte)0, 1));
+    expectEquals(-1, compareByteInt(Byte.MAX_VALUE, Integer.MAX_VALUE - 1));
+    expectEquals(-1, compareByteInt(Byte.MAX_VALUE, Integer.MAX_VALUE));
+
+    expectEquals(0, compareByteInt((byte)-1, -1));
+    expectEquals(0, compareByteInt((byte)0, 0));
+    expectEquals(0, compareByteInt((byte)1, 1));
+
+    expectEquals(1, compareByteInt(Byte.MIN_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareByteInt(Byte.MIN_VALUE, Integer.MIN_VALUE + 1));
+    expectEquals(1, compareByteInt((byte)0, -1));
+    expectEquals(1, compareByteInt((byte)1, -1));
+    expectEquals(1, compareByteInt((byte)1, 0));
+    expectEquals(1, compareByteInt(Byte.MAX_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareByteInt(Byte.MAX_VALUE, -1));
+    expectEquals(1, compareByteInt(Byte.MAX_VALUE, 0));
+    expectEquals(1, compareByteInt(Byte.MAX_VALUE, 1));
+
+    for (byte i = -11; i <= 11; i++) {
+      for (int j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareByteInt(i, j));
+      }
+    }
+  }
+
+
+  public static void testCompareShortByte() {
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, Byte.MIN_VALUE));
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, (byte)(Byte.MIN_VALUE + 1)));
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, (byte)-1));
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, (byte)0));
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, (byte)1));
+    expectEquals(-1, compareShortByte(Short.MIN_VALUE, Byte.MAX_VALUE));
+    expectEquals(-1, compareShortByte((short)-1, (byte)0));
+    expectEquals(-1, compareShortByte((short)-1, (byte)1));
+    expectEquals(-1, compareShortByte((short)0, (byte)1));
+
+    expectEquals(0, compareShortByte((short)-1, (byte)-1));
+    expectEquals(0, compareShortByte((short)0, (byte)0));
+    expectEquals(0, compareShortByte((short)1, (byte)1));
+
+    expectEquals(1, compareShortByte((short)0, (byte)-1));
+    expectEquals(1, compareShortByte((short)1, (byte)-1));
+    expectEquals(1, compareShortByte((short)1, (byte)0));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, Byte.MIN_VALUE));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, (byte)-1));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, (byte)0));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, (byte)1));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, (byte)(Byte.MAX_VALUE - 1)));
+    expectEquals(1, compareShortByte(Short.MAX_VALUE, Byte.MAX_VALUE));
+
+    for (short i = -11; i <= 11; i++) {
+      for (byte j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareShortByte(i, j));
+      }
+    }
+  }
+
+  public static void testCompareShortChar() {
+    expectEquals(-1, compareShortChar(Short.MIN_VALUE, (char)0));
+    expectEquals(-1, compareShortChar(Short.MIN_VALUE, (char)1));
+    expectEquals(-1, compareShortChar(Short.MIN_VALUE, Character.MAX_VALUE));
+    expectEquals(-1, compareShortChar((short)-1, (char)0));
+    expectEquals(-1, compareShortChar((short)-1, (char)1));
+    expectEquals(-1, compareShortChar((short)0, (char)1));
+    expectEquals(-1, compareShortChar(Short.MAX_VALUE, (char)(Character.MAX_VALUE - 1)));
+    expectEquals(-1, compareShortChar(Short.MAX_VALUE, Character.MAX_VALUE));
+
+    expectEquals(0, compareShortChar((short)0, (char)0));
+    expectEquals(0, compareShortChar((short)1, (char)1));
+
+    expectEquals(1, compareShortChar((short)1, (char)0));
+    expectEquals(1, compareShortChar(Short.MAX_VALUE, (char)0));
+    expectEquals(1, compareShortChar(Short.MAX_VALUE, (char)1));
+
+    for (short i = -11; i <= 11; i++) {
+      for (char j = 0; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareShortChar(i, j));
+      }
+    }
+  }
+
+  public static void testCompareShortInt() {
+    expectEquals(-1, compareShortInt(Short.MIN_VALUE, -1));
+    expectEquals(-1, compareShortInt(Short.MIN_VALUE, 0));
+    expectEquals(-1, compareShortInt(Short.MIN_VALUE, 1));
+    expectEquals(-1, compareShortInt(Short.MIN_VALUE, Integer.MAX_VALUE));
+    expectEquals(-1, compareShortInt((short)-1, 0));
+    expectEquals(-1, compareShortInt((short)-1, 1));
+    expectEquals(-1, compareShortInt((short)0, 1));
+    expectEquals(-1, compareShortInt(Short.MAX_VALUE, Integer.MAX_VALUE - 1));
+    expectEquals(-1, compareShortInt(Short.MAX_VALUE, Integer.MAX_VALUE));
+
+    expectEquals(0, compareShortInt((short)-1, -1));
+    expectEquals(0, compareShortInt((short)0, 0));
+    expectEquals(0, compareShortInt((short)1, 1));
+
+    expectEquals(1, compareShortInt(Short.MIN_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareShortInt(Short.MIN_VALUE, Integer.MIN_VALUE + 1));
+    expectEquals(1, compareShortInt((short)0, -1));
+    expectEquals(1, compareShortInt((short)1, -1));
+    expectEquals(1, compareShortInt((short)1, 0));
+    expectEquals(1, compareShortInt(Short.MAX_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareShortInt(Short.MAX_VALUE, -1));
+    expectEquals(1, compareShortInt(Short.MAX_VALUE, 0));
+    expectEquals(1, compareShortInt(Short.MAX_VALUE, 1));
+
+    for (short i = -11; i <= 11; i++) {
+      for (int j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareShortInt(i, j));
+      }
+    }
+  }
+
+
+  public static void testCompareCharByte() {
+    expectEquals(-1, compareCharByte((char)0, (byte)1));
+    expectEquals(-1, compareCharByte((char)0, Byte.MAX_VALUE));
+
+    expectEquals(0, compareCharByte((char)0, (byte)0));
+    expectEquals(0, compareCharByte((char)1, (byte)1));
+
+    expectEquals(1, compareCharByte((char)0, Byte.MIN_VALUE));
+    expectEquals(1, compareCharByte((char)0, (byte)(Byte.MIN_VALUE + 1)));
+    expectEquals(1, compareCharByte((char)0, (byte)-1));
+    expectEquals(1, compareCharByte((char)1, (byte)-1));
+    expectEquals(1, compareCharByte((char)1, (byte)0));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, Byte.MIN_VALUE));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, (byte)-1));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, (byte)0));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, (byte)1));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, (byte)(Byte.MAX_VALUE - 1)));
+    expectEquals(1, compareCharByte(Character.MAX_VALUE, Byte.MAX_VALUE));
+
+    for (char i = 0; i <= 11; i++) {
+      for (byte j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareCharByte(i, j));
+      }
+    }
+  }
+
+  public static void testCompareCharShort() {
+    expectEquals(-1, compareCharShort((char)0, (short)1));
+    expectEquals(-1, compareCharShort((char)0, Short.MAX_VALUE));
+
+    expectEquals(0, compareCharShort((char)0, (short)0));
+    expectEquals(0, compareCharShort((char)1, (short)1));
+
+    expectEquals(1, compareCharShort((char)0, Short.MIN_VALUE));
+    expectEquals(1, compareCharShort((char)0, (short)(Short.MIN_VALUE + 1)));
+    expectEquals(1, compareCharShort((char)0, (short)-1));
+    expectEquals(1, compareCharShort((char)1, (short)-1));
+    expectEquals(1, compareCharShort((char)1, (short)0));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, Short.MIN_VALUE));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, (short)-1));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, (short)0));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, (short)1));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, (short)(Short.MAX_VALUE - 1)));
+    expectEquals(1, compareCharShort(Character.MAX_VALUE, Short.MAX_VALUE));
+
+    for (char i = 0; i <= 11; i++) {
+      for (short j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareCharShort(i, j));
+      }
+    }
+  }
+
+  public static void testCompareCharInt() {
+    expectEquals(-1, compareCharInt((char)0, 1));
+    expectEquals(-1, compareCharInt((char)0, Integer.MAX_VALUE));
+    expectEquals(-1, compareCharInt(Character.MAX_VALUE, Integer.MAX_VALUE - 1));
+    expectEquals(-1, compareCharInt(Character.MAX_VALUE, Integer.MAX_VALUE));
+
+    expectEquals(0, compareCharInt((char)0, 0));
+    expectEquals(0, compareCharInt((char)1, 1));
+
+    expectEquals(1, compareCharInt((char)0, Integer.MIN_VALUE));
+    expectEquals(1, compareCharInt((char)0, Integer.MIN_VALUE + 1));
+    expectEquals(1, compareCharInt((char)0, -1));
+    expectEquals(1, compareCharInt((char)1, -1));
+    expectEquals(1, compareCharInt((char)1, 0));
+    expectEquals(1, compareCharInt(Character.MAX_VALUE, Integer.MIN_VALUE));
+    expectEquals(1, compareCharInt(Character.MAX_VALUE, -1));
+    expectEquals(1, compareCharInt(Character.MAX_VALUE, 0));
+    expectEquals(1, compareCharInt(Character.MAX_VALUE, 1));
+
+    for (char i = 0; i <= 11; i++) {
+      for (int j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareCharInt(i, j));
+      }
+    }
+  }
+
+
+  public static void testCompareIntByte() {
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, Byte.MIN_VALUE));
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, (byte)(Byte.MIN_VALUE + 1)));
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, (byte)-1));
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, (byte)0));
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, (byte)1));
+    expectEquals(-1, compareIntByte(Integer.MIN_VALUE, Byte.MAX_VALUE));
+    expectEquals(-1, compareIntByte(-1, (byte)0));
+    expectEquals(-1, compareIntByte(-1, (byte)1));
+    expectEquals(-1, compareIntByte(0, (byte)1));
+
+    expectEquals(0, compareIntByte(-1, (byte)-1));
+    expectEquals(0, compareIntByte(0, (byte)0));
+    expectEquals(0, compareIntByte(1, (byte)1));
+
+    expectEquals(1, compareIntByte(0, (byte)-1));
+    expectEquals(1, compareIntByte(1, (byte)-1));
+    expectEquals(1, compareIntByte(1, (byte)0));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, Byte.MIN_VALUE));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, (byte)-1));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, (byte)0));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, (byte)1));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, (byte)(Byte.MAX_VALUE - 1)));
+    expectEquals(1, compareIntByte(Integer.MAX_VALUE, Byte.MAX_VALUE));
+
+    for (int i = -11; i <= 11; i++) {
+      for (byte j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareIntByte(i, j));
+      }
+    }
+  }
+
+  public static void testCompareIntShort() {
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, Short.MIN_VALUE));
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, (short)(Short.MIN_VALUE + 1)));
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, (short)-1));
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, (short)0));
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, (short)1));
+    expectEquals(-1, compareIntShort(Integer.MIN_VALUE, Short.MAX_VALUE));
+    expectEquals(-1, compareIntShort(-1, (short)0));
+    expectEquals(-1, compareIntShort(-1, (short)1));
+    expectEquals(-1, compareIntShort(0, (short)1));
+
+    expectEquals(0, compareIntShort(-1, (short)-1));
+    expectEquals(0, compareIntShort(0, (short)0));
+    expectEquals(0, compareIntShort(1, (short)1));
+
+    expectEquals(1, compareIntShort(0, (short)-1));
+    expectEquals(1, compareIntShort(1, (short)-1));
+    expectEquals(1, compareIntShort(1, (short)0));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, Short.MIN_VALUE));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, (short)-1));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, (short)0));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, (short)1));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, (short)(Short.MAX_VALUE - 1)));
+    expectEquals(1, compareIntShort(Integer.MAX_VALUE, Short.MAX_VALUE));
+
+    for (int i = -11; i <= 11; i++) {
+      for (short j = -11; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareIntShort(i, j));
+      }
+    }
+  }
+
+  public static void testCompareIntChar() {
+    expectEquals(-1, compareIntChar(Integer.MIN_VALUE, (char)0));
+    expectEquals(-1, compareIntChar(Integer.MIN_VALUE, (char)1));
+    expectEquals(-1, compareIntChar(Integer.MIN_VALUE, Character.MAX_VALUE));
+    expectEquals(-1, compareIntChar(-1, (char)0));
+    expectEquals(-1, compareIntChar(-1, (char)1));
+    expectEquals(-1, compareIntChar(0, (char)1));
+
+    expectEquals(0, compareIntChar(0, (char)0));
+    expectEquals(0, compareIntChar(1, (char)1));
+
+    expectEquals(1, compareIntChar(1, (char)0));
+    expectEquals(1, compareIntChar(Integer.MAX_VALUE, (char)0));
+    expectEquals(1, compareIntChar(Integer.MAX_VALUE, (char)1));
+    expectEquals(1, compareIntChar(Integer.MAX_VALUE, (char)(Character.MAX_VALUE - 1)));
+    expectEquals(1, compareIntChar(Integer.MAX_VALUE, Character.MAX_VALUE));
+
+    for (int i = -11; i <= 11; i++) {
+      for (char j = 0; j <= 11; j++) {
+        int expected = 0;
+        if (i < j) expected = -1;
+        else if (i > j) expected = 1;
+        expectEquals(expected, compareIntChar(i, j));
+      }
+    }
+  }
+
+
+  public static void main(String args[]) {
+    testCompareBooleans();
+    testCompareBytes();
+    testCompareShorts();
+    testCompareChars();
+    testCompareInts();
+    testCompareLongs();
+
+    testCompareByteShort();
+    testCompareByteChar();
+    testCompareByteInt();
+
+    testCompareShortByte();
+    testCompareShortChar();
+    testCompareShortInt();
+
+    testCompareCharByte();
+    testCompareCharShort();
+    testCompareCharInt();
+
+    testCompareIntByte();
+    testCompareIntShort();
+    testCompareIntChar();
 
     System.out.println("passed");
   }
diff --git a/test/583-checker-zero/expected.txt b/test/583-checker-zero/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/583-checker-zero/expected.txt
diff --git a/test/583-checker-zero/info.txt b/test/583-checker-zero/info.txt
new file mode 100644
index 0000000..8ec5d48
--- /dev/null
+++ b/test/583-checker-zero/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to think 0.0 has the same bits
+as -0.0.
diff --git a/test/583-checker-zero/src/Main.java b/test/583-checker-zero/src/Main.java
new file mode 100644
index 0000000..f1f7f05
--- /dev/null
+++ b/test/583-checker-zero/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Main {
+  // Test that by inlining new Float(-0f), we still keep the store of
+  // -0f to the instance field. We used to remove it due to wrong assumptions
+  // around HConstant.IsZero.
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+  /// CHECK: InstanceFieldSet
+  public static void main(String[] args) {
+    if (new Float(0f).equals(new Float(-0f))) {
+      throw new Error("Expected not equal");
+    }
+  }
+}
diff --git a/test/584-checker-div-bool/expected.txt b/test/584-checker-div-bool/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/584-checker-div-bool/expected.txt
diff --git a/test/584-checker-div-bool/info.txt b/test/584-checker-div-bool/info.txt
new file mode 100644
index 0000000..59650d5
--- /dev/null
+++ b/test/584-checker-div-bool/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to not accept
+HDivZeroCheck taking a boolean.
diff --git a/test/584-checker-div-bool/src/Main.java b/test/584-checker-div-bool/src/Main.java
new file mode 100644
index 0000000..fadc995
--- /dev/null
+++ b/test/584-checker-div-bool/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Main {
+
+  public static void main(String[] args) {
+    try {
+      foo(intField);
+      throw new Error("Expected ArithmeticException");
+    } catch (ArithmeticException e) {
+      // expected
+    }
+  }
+
+  /// CHECK-START: int Main.foo(int) register (after)
+  /// CHECK: <<BoolField:z\d+>> StaticFieldGet
+  /// CHECK:                    DivZeroCheck [<<BoolField>>]
+  public static int foo(int a) {
+    return a / bar();
+  }
+
+  public static int bar() {
+    return booleanField ? 1 : 0;
+  }
+
+  public static boolean booleanField;
+  public static int intField;
+}
diff --git a/test/585-inline-unresolved/expected.txt b/test/585-inline-unresolved/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/585-inline-unresolved/expected.txt
diff --git a/test/585-inline-unresolved/info.txt b/test/585-inline-unresolved/info.txt
new file mode 100644
index 0000000..414f638
--- /dev/null
+++ b/test/585-inline-unresolved/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to crash when inlining
+a method whose return type is unresolved.
diff --git a/test/585-inline-unresolved/smali/TestCase.smali b/test/585-inline-unresolved/smali/TestCase.smali
new file mode 100644
index 0000000..f260092
--- /dev/null
+++ b/test/585-inline-unresolved/smali/TestCase.smali
@@ -0,0 +1,48 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LTestCase;
+
+.super Ljava/lang/Object;
+
+.field static private test1:Z
+
+.method public static topLevel()V
+   .registers 1
+   invoke-static {}, LTestCase;->$inline$foo()LUnresolved;
+   return-void
+.end method
+
+# We need multiple returns to trigger the crash.
+.method public static $inline$foo()LUnresolved;
+  .registers 2
+  const v1, 0x0
+  sget-boolean v0, LTestCase;->test1:Z
+  if-eqz v0, :other_return
+  return-object v1
+  :other_return
+  invoke-static {}, LTestCase;->$noinline$bar()LUnresolved;
+  move-result-object v0
+  return-object v0
+.end method
+
+.method public static $noinline$bar()LUnresolved;
+  .registers 2
+  const v1, 0x0
+  sget-boolean v0, LTestCase;->test1:Z
+  if-eqz v0, :return
+  throw v1
+  :return
+  return-object v1
+.end method
diff --git a/runtime/native/java_lang_Runtime.h b/test/585-inline-unresolved/src/Main.java
similarity index 64%
copy from runtime/native/java_lang_Runtime.h
copy to test/585-inline-unresolved/src/Main.java
index ceda06b..67ad4d2 100644
--- a/runtime/native/java_lang_Runtime.h
+++ b/test/585-inline-unresolved/src/Main.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,15 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-#define ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
-
-#include <jni.h>
-
-namespace art {
-
-void register_java_lang_Runtime(JNIEnv* env);
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
+public class Main {
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("TestCase");
+    c.getMethod("topLevel").invoke(null);
+  }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 7036bdc..bb7daf8 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -223,12 +223,9 @@
 
 # Disable 097-duplicate-method while investigation (broken by latest Jack release, b/27358065)
 # Disable 137-cfi (b/27391690).
-# Disable 536-checker-needs-access-check and 537-checker-inline-and-unverified (b/27425061)
 # Disable 577-profile-foreign-dex (b/27454772).
 TEST_ART_BROKEN_ALL_TARGET_TESTS := \
   097-duplicate-method \
-  536-checker-needs-access-check \
-  537-checker-inline-and-unverified \
   577-profile-foreign-dex \
 
 ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/etc/default-build b/test/etc/default-build
index 5f78496..d048757 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -54,6 +54,12 @@
   HAS_SRC_EX=false
 fi
 
+if [ -d src-dex2oat-unresolved ]; then
+  HAS_SRC_DEX2OAT_UNRESOLVED=true
+else
+  HAS_SRC_DEX2OAT_UNRESOLVED=false
+fi
+
 DX_FLAGS=""
 SKIP_DX_MERGER="false"
 EXPERIMENTAL=""
@@ -116,59 +122,80 @@
   SKIP_DX_MERGER="true"
 fi
 
-if [ ${USE_JACK} = "true" ]; then
-  # Jack toolchain
-  if [ "${HAS_SRC}" = "true" ]; then
-    if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
-      # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning
-      # when creating the output .dex file.
-      ${JACK} ${JACK_ARGS} --output-jack src.jack src src src-multidex
-      jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex"
-      jack_extra_args="${jack_extra_args} -D jack.preprocessor=true"
-      jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp"
-    else
-      ${JACK} ${JACK_ARGS} --output-jack src.jack src
+if [ ${HAS_SRC_DEX2OAT_UNRESOLVED} = "true" ]; then
+  mkdir classes
+  mkdir classes-ex
+  ${JAVAC} ${JAVAC_ARGS} -implicit:none -sourcepath src-dex2oat-unresolved -d classes `find src -name '*.java'`
+  ${JAVAC} ${JAVAC_ARGS} -implicit:none -sourcepath src -d classes-ex `find src-dex2oat-unresolved -name '*.java'`
+  if [ ${USE_JACK} = "true" ]; then
+    jar cf classes.jill.jar -C classes .
+    jar cf classes-ex.jill.jar -C classes-ex .
+
+    ${JACK} --import classes-ex.jill.jar --output-dex .
+    zip ${TEST_NAME}-ex.jar classes.dex
+    ${JACK} --import classes.jill.jar --output-dex .
+  else
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+      zip ${TEST_NAME}-ex.jar classes.dex
+      ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
     fi
-    jack_extra_args="${jack_extra_args} --import src.jack"
-  fi
-
-  if [ "${HAS_SRC2}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} --output-jack src2.jack src2
-    # In case of duplicate classes, we want to take into account the classes from src2. Therefore
-    # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file.
-    jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first"
-    jack_extra_args="--import src2.jack ${jack_extra_args}"
-  fi
-
-  # Compile jack files into a DEX file.
-  if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex .
   fi
 else
-  # Legacy toolchain with javac+dx
-  if [ "${HAS_SRC}" = "true" ]; then
-    mkdir classes
-    ${JAVAC} ${JAVAC_ARGS} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
-  fi
-
-  if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
-    mkdir classes2
-    ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
-    if [ ${NEED_DEX} = "true" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-        --dump-width=1000 ${DX_FLAGS} classes2
+  if [ ${USE_JACK} = "true" ]; then
+    # Jack toolchain
+    if [ "${HAS_SRC}" = "true" ]; then
+      if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
+        # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning
+        # when creating the output .dex file.
+        ${JACK} ${JACK_ARGS} --output-jack src.jack src src src-multidex
+        jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex"
+        jack_extra_args="${jack_extra_args} -D jack.preprocessor=true"
+        jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp"
+      else
+        ${JACK} ${JACK_ARGS} --output-jack src.jack src
+      fi
+      jack_extra_args="${jack_extra_args} --import src.jack"
     fi
-  fi
 
-  if [ "${HAS_SRC2}" = "true" ]; then
-    mkdir -p classes
-    ${JAVAC} ${JAVAC_ARGS} -d classes `find src2 -name '*.java'`
-  fi
+    if [ "${HAS_SRC2}" = "true" ]; then
+      ${JACK} ${JACK_ARGS} --output-jack src2.jack src2
+      # In case of duplicate classes, we want to take into account the classes from src2. Therefore
+      # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file.
+      jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first"
+      jack_extra_args="--import src2.jack ${jack_extra_args}"
+    fi
 
-  if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
-    if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-        --dump-width=1000 ${DX_FLAGS} classes
+    # Compile jack files into a DEX file.
+    if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
+      ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex .
+    fi
+  else
+    # Legacy toolchain with javac+dx
+    if [ "${HAS_SRC}" = "true" ]; then
+      mkdir classes
+      ${JAVAC} ${JAVAC_ARGS} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
+    fi
+
+    if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
+      mkdir classes2
+      ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
+      if [ ${NEED_DEX} = "true" ]; then
+        ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
+          --dump-width=1000 ${DX_FLAGS} classes2
+      fi
+    fi
+
+    if [ "${HAS_SRC2}" = "true" ]; then
+      mkdir -p classes
+      ${JAVAC} ${JAVAC_ARGS} -d classes `find src2 -name '*.java'`
+    fi
+
+    if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
+      if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
+        ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+          --dump-width=1000 ${DX_FLAGS} classes
+      fi
     fi
   fi
 fi
diff --git a/test/run-test b/test/run-test
index d0f93b9..6bb1549 100755
--- a/test/run-test
+++ b/test/run-test
@@ -45,7 +45,7 @@
 export RUN="${progdir}/etc/run-test-jar"
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
-export USE_JACK="false"
+export USE_JACK="true"
 export SMALI_ARGS="--experimental --api-level 23"
 
 # If dx was not set by the environment variable, assume it is in the path.
@@ -73,11 +73,6 @@
   export JACK="jack"
 fi
 
-# If the tree is compiled with Jack, build test with Jack by default.
-if [ "$ANDROID_COMPILE_WITH_JACK" = "true" ]; then
-  USE_JACK="true"
-fi
-
 # ANDROID_BUILD_TOP is not set in a build environment.
 if [ -z "$ANDROID_BUILD_TOP" ]; then
     export ANDROID_BUILD_TOP=$oldwd
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 46100ae..4c3aea4 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -270,5 +270,10 @@
   description: "Only work with --mode=activity",
   result: EXEC_FAILED,
   names: [ "libcore.java.io.FileTest#testJavaIoTmpdirMutable" ]
+},
+{
+  description: "Wrong junit constructor for test",
+  result: EXEC_FAILED,
+  names: [ "jsr166.CollectionTest#testEmptyMeansEmpty" ]
 }
 ]