Merge remote-tracking branch 'goog/master' into nyc-dev

bug:25492619
bug:27520994
bug:27624718

Change-Id: I8dd1e90724f7b9694a1d493ce61f669123dd3ac4
diff --git a/Android.mk b/Android.mk
index e762814..a518d2f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,9 +270,17 @@
 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.
+# 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
+valgrind-test-art-host32: valgrind-test-art-host-gtest32
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: valgrind-test-art-host64
+valgrind-test-art-host64: valgrind-test-art-host-gtest64
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 ########################################################################
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index 2d4fff4..4712d47 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -96,12 +96,21 @@
   std::vector<VariableLocation> variable_locations;
 
   // Get stack maps sorted by pc (they might not be sorted internally).
+  // TODO(dsrbecky) Remove this once stackmaps get sorted by pc.
   const CodeInfo code_info(method_info->code_info);
   const StackMapEncoding encoding = code_info.ExtractEncoding();
   std::map<uint32_t, uint32_t> stack_maps;  // low_pc -> stack_map_index.
   for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
     StackMap stack_map = code_info.GetStackMapAt(s, encoding);
     DCHECK(stack_map.IsValid());
+    if (!stack_map.HasDexRegisterMap(encoding)) {
+      // The compiler creates stackmaps without register maps at the start of
+      // basic blocks in order to keep instruction-accurate line number mapping.
+      // However, we never stop at those (breakpoint locations always have map).
+      // Therefore, for the purpose of local variables, we ignore them.
+      // The main reason for this is to save space by avoiding undefined gaps.
+      continue;
+    }
     const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding);
     DCHECK_LE(pc_offset, method_info->code_size);
     DCHECK_LE(compilation_unit_code_address, method_info->code_address);
@@ -128,6 +137,8 @@
     // Check that the stack map is in the requested range.
     uint32_t dex_pc = stack_map.GetDexPc(encoding);
     if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
+      // The variable is not in scope at this PC. Therefore omit the entry.
+      // Note that this is different to None() entry which means in scope, but unknown location.
       continue;
     }
 
@@ -136,13 +147,12 @@
     DexRegisterLocation reg_hi = DexRegisterLocation::None();
     DCHECK_LT(stack_map_index, dex_register_maps.size());
     DexRegisterMap dex_register_map = dex_register_maps[stack_map_index];
-    if (dex_register_map.IsValid()) {
-      reg_lo = dex_register_map.GetDexRegisterLocation(
-          vreg, method_info->code_item->registers_size_, code_info, encoding);
-      if (is64bitValue) {
-        reg_hi = dex_register_map.GetDexRegisterLocation(
-            vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
-      }
+    DCHECK(dex_register_map.IsValid());
+    reg_lo = dex_register_map.GetDexRegisterLocation(
+        vreg, method_info->code_item->registers_size_, code_info, encoding);
+    if (is64bitValue) {
+      reg_hi = dex_register_map.GetDexRegisterLocation(
+          vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
     }
 
     // Add location entry for this address range.
@@ -152,9 +162,6 @@
         variable_locations.back().high_pc == low_pc) {
       // Merge with the previous entry (extend its range).
       variable_locations.back().high_pc = high_pc;
-    } else if (!variable_locations.empty() && reg_lo == DexRegisterLocation::None()) {
-      // Unknown location - use the last known location as best-effort guess.
-      variable_locations.back().high_pc = high_pc;
     } else {
       variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
     }
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index de000b0..ea16cb2 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);
 
@@ -2512,6 +2513,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);
@@ -2752,12 +2756,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 e40f7c0..64a06a2 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -699,6 +699,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 71eb787..b4389d3 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),
@@ -228,9 +226,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 f13c7af..59698af 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -50,7 +50,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;
@@ -185,7 +184,7 @@
   }
 
   bool GetNativeDebuggable() const {
-    return native_debuggable_;
+    return GetDebuggable() && GetGenerateDebugInfo();
   }
 
   // This flag controls whether the compiler collects debugging information.
@@ -298,7 +297,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/elf_builder.h b/compiler/elf_builder.h
index ef44a6f..26ab281 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -841,7 +841,7 @@
       load.p_type    = PT_LOAD;
       load.p_flags   = PF_R;
       load.p_offset  = load.p_vaddr = load.p_paddr = 0;
-      load.p_filesz  = load.p_memsz = sections_[0]->header_.sh_offset;
+      load.p_filesz  = load.p_memsz = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders;
       load.p_align   = kPageSize;
       phdrs.push_back(load);
     }
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/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index f2929bc..084360f 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -535,6 +535,7 @@
             graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
         dynamic_bce_standby_(
             graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
+        record_dynamic_bce_standby_(true),
         early_exit_loop_(
             std::less<uint32_t>(),
             graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
@@ -556,6 +557,7 @@
 
   void Finish() {
     // Retry dynamic bce candidates on standby that are still in the graph.
+    record_dynamic_bce_standby_ = false;
     for (HBoundsCheck* bounds_check : dynamic_bce_standby_) {
       if (bounds_check->IsInBlock()) {
         TryDynamicBCE(bounds_check);
@@ -1191,7 +1193,7 @@
       if (!array_length->IsArrayLength()) {
         continue;  // disregard phis and constants
       }
-      // Collect all bounds checks are still there and that are related as "a[base + constant]"
+      // Collect all bounds checks that are still there and that are related as "a[base + constant]"
       // for a base instruction (possibly absent) and various constants. Note that no attempt
       // is made to partition the set into matching subsets (viz. a[0], a[1] and a[base+1] and
       // a[base+2] are considered as one set).
@@ -1214,7 +1216,12 @@
           HInstruction* other_array_length = other_bounds_check->InputAt(1);
           ValueBound other_value = ValueBound::AsValueBound(other_index);
           if (array_length == other_array_length && base == other_value.GetInstruction()) {
-            int32_t other_c = other_value.GetConstant();
+            // Reject certain OOB if BoundsCheck(l, l) occurs on considered subset.
+            if (array_length == other_index) {
+              candidates.clear();
+              standby.clear();
+              break;
+            }
             // Since a subsequent dominated block could be under a conditional, only accept
             // the other bounds check if it is in same block or both blocks dominate the exit.
             // TODO: we could improve this by testing proper post-dominance, or even if this
@@ -1222,6 +1229,7 @@
             HBasicBlock* exit = GetGraph()->GetExitBlock();
             if (block == user->GetBlock() ||
                 (block->Dominates(exit) && other_block->Dominates(exit))) {
+              int32_t other_c = other_value.GetConstant();
               min_c = std::min(min_c, other_c);
               max_c = std::max(max_c, other_c);
               candidates.push_back(other_bounds_check);
@@ -1251,7 +1259,11 @@
            distance <= kMaxLengthForAddingDeoptimize) {  // reject likely/certain deopt
         AddCompareWithDeoptimization(block, array_length, base, min_c, max_c);
         for (HInstruction* other_bounds_check : candidates) {
-          ReplaceInstruction(other_bounds_check, other_bounds_check->InputAt(0));
+          // Only replace if still in the graph. This avoids visiting the same
+          // bounds check twice if it occurred multiple times in the use list.
+          if (other_bounds_check->IsInBlock()) {
+            ReplaceInstruction(other_bounds_check, other_bounds_check->InputAt(0));
+          }
         }
       }
     }
@@ -1467,7 +1479,9 @@
       }
       // If bounds check made it this far, it is worthwhile to check later if
       // the loop was forced finite by another candidate.
-      dynamic_bce_standby_.push_back(check);
+      if (record_dynamic_bce_standby_) {
+        dynamic_bce_standby_.push_back(check);
+      }
       return false;
     }
     return true;
@@ -1691,6 +1705,7 @@
 
   // Stand by list for dynamic bce.
   ArenaVector<HBoundsCheck*> dynamic_bce_standby_;
+  bool record_dynamic_bce_standby_;
 
   // Early-exit loop bookkeeping.
   ArenaSafeMap<uint32_t, bool> early_exit_loop_;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index af50363..d64a786 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -196,7 +196,7 @@
       code_start = GetAssembler()->CodeSize();
     }
     // Record the dex pc at start of slow path (required for java line number mapping).
-    MaybeRecordNativeDebugInfo(nullptr /* instruction */, slow_path->GetDexPc());
+    MaybeRecordNativeDebugInfo(slow_path->GetInstruction(), slow_path->GetDexPc(), slow_path);
     slow_path->EmitNativeCode(this);
     if (disasm_info_ != nullptr) {
       disasm_info_->AddSlowPathInterval(slow_path, code_start, GetAssembler()->CodeSize());
@@ -234,6 +234,12 @@
     MaybeRecordNativeDebugInfo(nullptr /* instruction */, block->GetDexPc());
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
+      if (current->HasEnvironment()) {
+        // Create stackmap for HNativeDebugInfo or any instruction which calls native code.
+        // Note that we need correct mapping for the native PC of the call instruction,
+        // so the runtime's stackmap is not sufficient since it is at PC after the call.
+        MaybeRecordNativeDebugInfo(current, block->GetDexPc());
+      }
       DisassemblyScope disassembly_scope(current, *this);
       DCHECK(CheckTypeConsistency(current));
       current->Accept(instruction_visitor);
@@ -706,7 +712,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 +723,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()) {
@@ -823,13 +829,15 @@
   return count > 0 && stack_map_stream_.GetStackMap(count - 1).native_pc_offset == pc;
 }
 
-void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction, uint32_t dex_pc) {
+void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction,
+                                               uint32_t dex_pc,
+                                               SlowPathCode* slow_path) {
   if (GetCompilerOptions().GetNativeDebuggable() && dex_pc != kNoDexPc) {
     if (HasStackMapAtCurrentPc()) {
       // Ensure that we do not collide with the stack map of the previous instruction.
       GenerateNop();
     }
-    RecordPcInfo(instruction, dex_pc);
+    RecordPcInfo(instruction, dex_pc, slow_path);
   }
 }
 
@@ -1110,6 +1118,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..e56323f 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -106,6 +106,10 @@
   Label* GetEntryLabel() { return &entry_label_; }
   Label* GetExitLabel() { return &exit_label_; }
 
+  HInstruction* GetInstruction() const {
+    return instruction_;
+  }
+
   uint32_t GetDexPc() const {
     return instruction_ != nullptr ? instruction_->GetDexPc() : kNoDexPc;
   }
@@ -274,10 +278,15 @@
   // Check whether we have already recorded mapping at this PC.
   bool HasStackMapAtCurrentPc();
   // Record extra stack maps if we support native debugging.
-  void MaybeRecordNativeDebugInfo(HInstruction* instruction, uint32_t dex_pc);
+  void MaybeRecordNativeDebugInfo(HInstruction* instruction,
+                                  uint32_t dex_pc,
+                                  SlowPathCode* slow_path = nullptr);
 
   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..4c9c25f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1543,8 +1543,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorARM::GenerateNop() {
@@ -3151,6 +3151,7 @@
   Location value = locations->InAt(0);
 
   switch (instruction->GetType()) {
+    case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
@@ -3272,7 +3273,8 @@
     __ Bind(&end);
   }
 }
-void LocationsBuilderARM::HandleRotate(HRor* ror) {
+
+void LocationsBuilderARM::VisitRor(HRor* ror) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
   switch (ror->GetResultType()) {
@@ -3299,7 +3301,7 @@
   }
 }
 
-void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) {
+void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
   LocationSummary* locations = ror->GetLocations();
   Primitive::Type type = ror->GetResultType();
   switch (type) {
@@ -3317,14 +3319,6 @@
   }
 }
 
-void LocationsBuilderARM::VisitRor(HRor* op) {
-  HandleRotate(op);
-}
-
-void InstructionCodeGeneratorARM::VisitRor(HRor* op) {
-  HandleRotate(op);
-}
-
 void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
 
@@ -3671,6 +3665,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 +3699,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 +4286,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 +4307,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..cc4aa14 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -174,7 +174,6 @@
   void HandleCondition(HCondition* condition);
   void HandleIntegerRotate(LocationSummary* locations);
   void HandleLongRotate(LocationSummary* locations);
-  void HandleRotate(HRor* ror);
   void HandleShift(HBinaryOperation* operation);
   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
@@ -222,7 +221,6 @@
   void HandleCondition(HCondition* condition);
   void HandleIntegerRotate(LocationSummary* locations);
   void HandleLongRotate(LocationSummary* locations);
-  void HandleRotate(HRor* ror);
   void HandleShift(HBinaryOperation* operation);
 
   void GenerateWideAtomicStore(Register addr, uint32_t offset,
@@ -274,9 +272,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 +509,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..088dbb3 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;
   }
 
@@ -3084,8 +3092,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorARM64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorARM64::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorARM64::GenerateNop() {
@@ -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..4c92063 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:
@@ -3393,8 +3402,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorMIPS::GenerateNop() {
@@ -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..955c9a4 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;
   }
 
@@ -2718,8 +2726,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorMIPS64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorMIPS64::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorMIPS64::GenerateNop() {
@@ -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..fb3216c 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1636,8 +1636,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorX86::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorX86::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorX86::GenerateNop() {
@@ -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:
@@ -3979,8 +3981,7 @@
     __ cmovl(kNotEqual, first_reg_hi, first_reg_lo);
     __ cmovl(kNotEqual, first_reg_lo, temp_reg);
   } else {
-    int32_t shift_amt =
-      CodeGenerator::GetInt64ValueOf(second.GetConstant()) & kMaxLongShiftValue;
+    int32_t shift_amt = CodeGenerator::GetInt64ValueOf(second.GetConstant()) & kMaxLongShiftValue;
     if (shift_amt == 0) {
       // Already fine.
       return;
@@ -4184,6 +4185,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 +4224,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;
@@ -4786,6 +4795,7 @@
         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
         __ movl(Address(base, offset), Immediate(v));
       } else {
+        DCHECK(value.IsRegister()) << value;
         __ movl(Address(base, offset), value.AsRegister<Register>());
       }
       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..7648f61 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1617,8 +1617,8 @@
   new (GetGraph()->GetArena()) LocationSummary(info);
 }
 
-void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
-  codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo*) {
+  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
 }
 
 void CodeGeneratorX86_64::GenerateNop() {
@@ -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/common_arm64.h b/compiler/optimizing/common_arm64.h
index 10d8343..6c55194 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -194,7 +194,8 @@
 }
 
 static bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) {
-  DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant());
+  DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant())
+      << constant->DebugName();
 
   // For single uses we let VIXL handle the constant generation since it will
   // use registers that are not managed by the register allocator (wip0, wip1).
@@ -221,7 +222,8 @@
            instr->IsBoundsCheck() ||
            instr->IsCompare() ||
            instr->IsCondition() ||
-           instr->IsSub());
+           instr->IsSub())
+        << instr->DebugName();
     // Uses aliases of ADD/SUB instructions.
     // If `value` does not fit but `-value` does, VIXL will automatically use
     // the 'opposite' instruction.
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 4a49c83..11e3689 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())));
+    // Use the first input, so that we can also make this check for shift and rotate operations.
+    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 049901b..4a8186a 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);
     }
   }
 
@@ -92,10 +96,10 @@
 
   bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
 
-  void SimplifyRotate(HInvoke* invoke, bool is_left);
+  void SimplifyRotate(HInvoke* invoke, bool is_left, Primitive::Type type);
   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
@@ -255,10 +262,8 @@
 bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op,
                                                         HUShr* ushr,
                                                         HShl* shl) {
-  DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
-  HRor* ror = new (GetGraph()->GetArena()) HRor(ushr->GetType(),
-                                                ushr->GetLeft(),
-                                                ushr->GetRight());
+  DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()) << op->DebugName();
+  HRor* ror = new (GetGraph()->GetArena()) HRor(ushr->GetType(), ushr->GetLeft(), ushr->GetRight());
   op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror);
   if (!ushr->HasUses()) {
     ushr->GetBlock()->RemoveInstruction(ushr);
@@ -463,19 +468,17 @@
 
   if (object->IsNullConstant()) {
     check_cast->GetBlock()->RemoveInstruction(check_cast);
-    if (stats_ != nullptr) {
-      stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
-    }
+    MaybeRecordStat(MethodCompilationStat::kRemovedCheckedCast);
     return;
   }
 
-  bool outcome;
+  // Note: The `outcome` is initialized to please valgrind - the compiler can reorder
+  // the return value check with the `outcome` check, b/27651442 .
+  bool outcome = false;
   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
@@ -505,14 +508,18 @@
 
   HGraph* graph = GetGraph();
   if (object->IsNullConstant()) {
+    MaybeRecordStat(kRemovedInstanceOf);
     instruction->ReplaceWith(graph->GetIntConstant(0));
     instruction->GetBlock()->RemoveInstruction(instruction);
     RecordSimplification();
     return;
   }
 
-  bool outcome;
+  // Note: The `outcome` is initialized to please valgrind - the compiler can reorder
+  // 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);
@@ -867,9 +874,7 @@
         return;
       }
     }
-  } else if (input->IsAnd() &&
-      Primitive::IsIntegralType(result_type) &&
-      input->HasOnlyOneNonEnvironmentUse()) {
+  } else if (input->IsAnd() && Primitive::IsIntegralType(result_type)) {
     DCHECK(Primitive::IsIntegralType(input_type));
     HAnd* input_and = input->AsAnd();
     HConstant* constant = input_and->GetConstantRight();
@@ -879,10 +884,18 @@
       size_t trailing_ones = CTZ(~static_cast<uint64_t>(value));
       if (trailing_ones >= kBitsPerByte * Primitive::ComponentSize(result_type)) {
         // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
-        input_and->ReplaceWith(input_and->GetLeastConstantLeft());
-        input_and->GetBlock()->RemoveInstruction(input_and);
-        RecordSimplification();
-        return;
+        HInstruction* original_input = input_and->GetLeastConstantLeft();
+        if (IsTypeConversionImplicit(original_input->GetType(), result_type)) {
+          instruction->ReplaceWith(original_input);
+          instruction->GetBlock()->RemoveInstruction(instruction);
+          RecordSimplification();
+          return;
+        } else if (input->HasOnlyOneNonEnvironmentUse()) {
+          input_and->ReplaceWith(original_input);
+          input_and->GetBlock()->RemoveInstruction(input_and);
+          RecordSimplification();
+          return;
+        }
       }
     }
   }
@@ -1217,7 +1230,7 @@
       // with
       //    SHL dst, src, log2(pow_of_2)
       HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
-      HShl* shl = new(allocator) HShl(type, input_other, shift);
+      HShl* shl = new (allocator) HShl(type, input_other, shift);
       block->ReplaceAndRemoveInstructionWith(instruction, shl);
       RecordSimplification();
     } else if (IsPowerOfTwo(factor - 1)) {
@@ -1516,7 +1529,9 @@
   }
 }
 
-void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, bool is_left) {
+void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke,
+                                                  bool is_left,
+                                                  Primitive::Type type) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
   DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic);
   HInstruction* value = invoke->InputAt(0);
@@ -1526,7 +1541,7 @@
     distance = new (GetGraph()->GetArena()) HNeg(distance->GetType(), distance);
     invoke->GetBlock()->InsertInstructionBefore(distance, invoke);
   }
-  HRor* ror = new (GetGraph()->GetArena()) HRor(value->GetType(), value, distance);
+  HRor* ror = new (GetGraph()->GetArena()) HRor(type, value, distance);
   invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, ror);
   // Remove ClinitCheck and LoadClass, if possible.
   HInstruction* clinit = invoke->InputAt(invoke->InputCount() - 1);
@@ -1604,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) {
@@ -1678,20 +1694,28 @@
       SimplifySystemArrayCopy(instruction);
       break;
     case Intrinsics::kIntegerRotateRight:
+      SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimInt);
+      break;
     case Intrinsics::kLongRotateRight:
-      SimplifyRotate(instruction, false);
+      SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimLong);
       break;
     case Intrinsics::kIntegerRotateLeft:
+      SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimInt);
+      break;
     case Intrinsics::kLongRotateLeft:
-      SimplifyRotate(instruction, true);
+      SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimLong);
       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/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8eaac0b..561dcfb 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -728,6 +728,23 @@
       // This acts like GVN but with better aliasing analysis.
       heap_values[idx] = instruction;
     } else {
+      if (Primitive::PrimitiveKind(heap_value->GetType())
+              != Primitive::PrimitiveKind(instruction->GetType())) {
+        // The only situation where the same heap location has different type is when
+        // we do an array get from a null constant. In order to stay properly typed
+        // we do not merge the array gets.
+        if (kIsDebugBuild) {
+          DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName();
+          DCHECK(instruction->IsArrayGet()) << instruction->DebugName();
+          HInstruction* array = instruction->AsArrayGet()->GetArray();
+          DCHECK(array->IsNullCheck()) << array->DebugName();
+          DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName();
+          array = heap_value->AsArrayGet()->GetArray();
+          DCHECK(array->IsNullCheck()) << array->DebugName();
+          DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName();
+        }
+        return;
+      }
       removed_loads_.push_back(instruction);
       substitute_instructions_for_loads_.push_back(heap_value);
       TryRemovingNullCheck(instruction);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 1bb5f5d..46377ee 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);
@@ -4684,7 +4689,12 @@
 class HRor : public HBinaryOperation {
  public:
   HRor(Primitive::Type result_type, HInstruction* value, HInstruction* distance)
-    : HBinaryOperation(result_type, value, distance) {}
+    : HBinaryOperation(result_type, value, distance) {
+    if (kIsDebugBuild) {
+      DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType()));
+      DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType()));
+    }
+  }
 
   template <typename T, typename U, typename V>
   T Compute(T x, U y, V max_shift_value) const {
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 ba313aa..0debd42 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -320,7 +320,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.");
@@ -328,13 +328,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.");
@@ -1046,7 +1043,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()) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 2cdd4c7..9ac18e8 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -103,9 +103,11 @@
 template <typename ElfTypes>
 class OatSymbolizer FINAL {
  public:
-  OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
-      oat_file_(oat_file), builder_(nullptr),
-      output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
+  OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
+      oat_file_(oat_file),
+      builder_(nullptr),
+      output_name_(output_name.empty() ? "symbolized.oat" : output_name),
+      no_bits_(no_bits) {
   }
 
   bool Symbolize() {
@@ -124,17 +126,25 @@
     auto* text = builder_->GetText();
     auto* bss = builder_->GetBss();
 
-    rodata->Start();
     const uint8_t* rodata_begin = oat_file_->Begin();
     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
-    rodata->WriteFully(rodata_begin, rodata_size);
-    rodata->End();
+    if (no_bits_) {
+      rodata->WriteNoBitsSection(rodata_size);
+    } else {
+      rodata->Start();
+      rodata->WriteFully(rodata_begin, rodata_size);
+      rodata->End();
+    }
 
-    text->Start();
     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
     const size_t text_size = oat_file_->End() - text_begin;
-    text->WriteFully(text_begin, text_size);
-    text->End();
+    if (no_bits_) {
+      text->WriteNoBitsSection(text_size);
+    } else {
+      text->Start();
+      text->WriteFully(text_begin, text_size);
+      text->End();
+    }
 
     if (oat_file_->BssSize() != 0) {
       bss->WriteNoBitsSection(oat_file_->BssSize());
@@ -264,6 +274,7 @@
   std::vector<debug::MethodDebugInfo> method_debug_infos_;
   std::unordered_set<uint32_t> seen_offsets_;
   const std::string output_name_;
+  bool no_bits_;
 };
 
 class OatDumperOptions {
@@ -2522,7 +2533,7 @@
   }
 }
 
-static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
+static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) {
   std::string error_msg;
   OatFile* oat_file = OatFile::Open(oat_filename,
                                     oat_filename,
@@ -2541,10 +2552,10 @@
   // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
   // files for 64-bit code in the past.
   if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
-    OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name);
+    OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name, no_bits);
     result = oat_symbolizer.Symbolize();
   } else {
-    OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name);
+    OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name, no_bits);
     result = oat_symbolizer.Symbolize();
   }
   if (!result) {
@@ -2587,6 +2598,8 @@
     } else if (option.starts_with("--symbolize=")) {
       oat_filename_ = option.substr(strlen("--symbolize=")).data();
       symbolize_ = true;
+    } else if (option.starts_with("--only-keep-debug")) {
+      only_keep_debug_ = true;
     } else if (option.starts_with("--class-filter=")) {
       class_filter_ = option.substr(strlen("--class-filter=")).data();
     } else if (option.starts_with("--method-filter=")) {
@@ -2692,6 +2705,10 @@
         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
         "      Example: --symbolize=/system/framework/boot.oat\n"
         "\n"
+        "  --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
+        "      .rodata and .text sections are omitted in the output file to save space.\n"
+        "      Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
+        "\n"
         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
         "      Example: --class-filter=com.example.foo\n"
         "\n"
@@ -2721,6 +2738,7 @@
   bool dump_code_info_stack_maps_ = false;
   bool disassemble_code_ = true;
   bool symbolize_ = false;
+  bool only_keep_debug_ = false;
   bool list_classes_ = false;
   bool list_methods_ = false;
   bool dump_header_only_ = false;
@@ -2765,7 +2783,12 @@
     MemMap::Init();
 
     if (args_->symbolize_) {
-      return SymbolizeOat(args_->oat_filename_, args_->output_name_) == EXIT_SUCCESS;
+      // ELF has special kind of section called SHT_NOBITS which allows us to create
+      // sections which exist but their data is omitted from the ELF file to save space.
+      // This is what "strip --only-keep-debug" does when it creates separate ELF file
+      // with only debug data. We use it in similar way to exclude .rodata and .text.
+      bool no_bits = args_->only_keep_debug_;
+      return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS;
     } else {
       return DumpOat(nullptr,
                      args_->oat_filename_,
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 7a3071e..63ae342 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -128,7 +128,7 @@
     if (f.get() != nullptr) {
       if (fchmod(f->Fd(), 0644) != 0) {
         PLOG(ERROR) << "Unable to make " << name << " world readable";
-        TEMP_FAILURE_RETRY(unlink(name));
+        unlink(name);
         return nullptr;
       }
     }
@@ -440,7 +440,7 @@
   }
 
   // Delete the original file, since we won't need it.
-  TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
+  unlink(output_oat_filename.c_str());
 
   // Create a symlink from the old oat to the new oat
   if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) {
@@ -1148,7 +1148,7 @@
     if (!success) {
       if (new_oat_out) {
         CHECK(!output_oat_filename.empty());
-        TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
+        unlink(output_oat_filename.c_str());
       }
     }
 
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 64135d8..82ec0b7 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1125,9 +1125,8 @@
     // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
     // r2, r3, r12: free.
 #if defined(USE_READ_BARRIER)
-    eor    r0, r0, r0                                         // Read barrier not supported here.
-    sub    r0, r0, #1                                         // Return -1.
-    bx     lr
+    mvn    r0, #0                                             // Read barrier not supported here.
+    bx     lr                                                 // Return -1.
 #endif
     ldr    r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32]    // Load dex cache resolved types array
                                                               // Load the class (r2)
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index e4c2558..65d5b46 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1638,7 +1638,79 @@
     RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 END art_quick_alloc_object_rosalloc
 
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
+ENTRY art_quick_alloc_object_tlab
+    // Fast path tlab allocation.
+    // x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
+    // x2-x7: free.
+#if defined(USE_READ_BARRIER)
+    mvn    x0, xzr                                            // Read barrier not supported here.
+    ret                                                       // Return -1.
+#endif
+    ldr    x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64]    // Load dex cache resolved types array
+                                                              // Load the class (x2)
+    ldr    w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
+    cbz    x2, .Lart_quick_alloc_object_tlab_slow_path        // Check null class
+                                                              // Check class status.
+    ldr    w3, [x2, #MIRROR_CLASS_STATUS_OFFSET]
+    cmp    x3, #MIRROR_CLASS_STATUS_INITIALIZED
+    bne    .Lart_quick_alloc_object_tlab_slow_path
+                                                              // Add a fake dependence from the
+                                                              // following access flag and size
+                                                              // loads to the status load.
+                                                              // This is to prevent those loads
+                                                              // from being reordered above the
+                                                              // status load and reading wrong
+                                                              // values (an alternative is to use
+                                                              // a load-acquire for the status).
+    eor    x3, x3, x3
+    add    x2, x2, x3
+                                                              // Check access flags has
+                                                              // kAccClassIsFinalizable.
+    ldr    w3, [x2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
+    tbnz   x3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT, .Lart_quick_alloc_object_tlab_slow_path
+                                                              // Load thread_local_pos (x4) and
+                                                              // thread_local_end (x5).
+    ldr    x4, [xSELF, #THREAD_LOCAL_POS_OFFSET]
+    ldr    x5, [xSELF, #THREAD_LOCAL_END_OFFSET]
+    sub    x6, x5, x4                                         // Compute the remaining buf size.
+    ldr    w7, [x2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET]         // Load the object size (x7).
+    cmp    x7, x6                                             // Check if it fits. OK to do this
+                                                              // before rounding up the object size
+                                                              // assuming the buf size alignment.
+    bhi    .Lart_quick_alloc_object_tlab_slow_path
+    // "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1.
+                                                              // Round up the object size by the
+                                                              // object alignment. (addr + 7) & ~7.
+    add    x7, x7, #OBJECT_ALIGNMENT_MASK
+    and    x7, x7, #OBJECT_ALIGNMENT_MASK_TOGGLED
+                                                              // Move old thread_local_pos to x0
+                                                              // for the return value.
+    mov    x0, x4
+    add    x5, x0, x7
+    str    x5, [xSELF, #THREAD_LOCAL_POS_OFFSET]              // Store new thread_local_pos.
+    ldr    x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET]          // Increment thread_local_objects.
+    add    x5, x5, #1
+    str    x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET]
+    POISON_HEAP_REF w2
+    str    w2, [x0, #MIRROR_OBJECT_CLASS_OFFSET]              // Store the class pointer.
+                                                              // Fence. This is "ish" not "ishst" so
+                                                              // that the code after this allocation
+                                                              // site will see the right values in
+                                                              // the fields of the class.
+                                                              // Alternatively we could use "ishst"
+                                                              // if we use load-acquire for the
+                                                              // class status load.)
+    dmb    ish
+    ret
+.Lart_quick_alloc_object_tlab_slow_path:
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    // Save callee saves in case of GC.
+    mov    x2, xSELF                     // Pass Thread::Current.
+    bl     artAllocObjectFromCodeTLAB    // (uint32_t type_idx, Method* method, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+END art_quick_alloc_object_tlab
+
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
 
     /*
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index d5f0dff..1f24f45 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -230,6 +230,9 @@
 #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
 ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
             static_cast<uint32_t>(art::kAccClassIsFinalizable))
+#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT 31
+ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
+            static_cast<uint32_t>(1U << ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT))
 
 // Array offsets.
 #define MIRROR_ARRAY_LENGTH_OFFSET      MIRROR_OBJECT_HEADER_SIZE
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 51766c8..ada6e5c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2555,8 +2555,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) {
@@ -2739,13 +2749,18 @@
     return true;
   }
 
-  if (runtime->UseJit() && runtime->GetJit()->JitAtFirstUse()) {
-    // The force JIT uses the interpreter entry point to execute the JIT.
-    return true;
+  if (runtime->IsNativeDebuggable()) {
+    DCHECK(runtime->UseJit() && runtime->GetJit()->JitAtFirstUse());
+    // If we are doing native debugging, ignore application's AOT code,
+    // since we want to JIT it with extra stackmaps for native debugging.
+    // On the other hand, keep all AOT code from the boot image, since the
+    // blocking JIT would results in non-negligible performance impact.
+    return !runtime->GetHeap()->IsInBootImageOatFile(quick_code);
   }
 
   if (Dbg::IsDebuggerActive()) {
-    // Boot image classes are AOT-compiled as non-debuggable.
+    // Boot image classes may be AOT-compiled as non-debuggable.
+    // This is not suitable for the Java debugger, so ignore the AOT code.
     return runtime->GetHeap()->IsInBootImageOatFile(quick_code);
   }
 
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index bc65893..c375bba 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -622,9 +622,11 @@
   }
 
   Runtime* runtime = Runtime::Current();
-  // Since boot image code is AOT compiled as not debuggable, we need to patch
+  // Since boot image code may be AOT compiled as not debuggable, we need to patch
   // entry points of methods in boot image to interpreter bridge.
-  if (!runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+  // However, the performance cost of this is non-negligible during native-debugging due to the
+  // forced JIT, so we keep the AOT code in that case in exchange for limited native debugging.
+  if (!runtime->GetInstrumentation()->IsForcedInterpretOnly() && !runtime->IsNativeDebuggable()) {
     ScopedObjectAccess soa(self);
     UpdateEntryPointsClassVisitor visitor(runtime->GetInstrumentation());
     runtime->GetClassLinker()->VisitClasses(&visitor);
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 b506a25..8ca60b2 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::DumpForSigQuit(std::ostream& os) {
@@ -100,6 +102,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) {
 }
@@ -438,5 +442,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 1e38b38..e3fa89d 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_);
 
   static void NewTypeLoadedIfUsingJit(mirror::Class* type)
       SHARED_REQUIRES(Locks::mutator_lock_);
@@ -123,6 +125,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..887eee0 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -119,7 +119,9 @@
   }
 
   if ((debug_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
-    runtime->AddCompilerOption("--native-debuggable");
+    runtime->AddCompilerOption("--debuggable");
+    runtime->AddCompilerOption("--generate-debug-info");
+    runtime->SetNativeDebuggable(true);
     debug_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
   }
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e57125b..3ec3826 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -477,4 +477,23 @@
   }
 }
 
+void OatFileManager::DumpForSigQuit(std::ostream& os) {
+  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  std::vector<const OatFile*> boot_oat_files = GetBootOatFiles();
+  for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
+    if (ContainsElement(boot_oat_files, oat_file.get())) {
+      continue;
+    }
+    // Use "platform-default" if it's neither extract nor profile guided.
+    // Saying 'full' could be misleading if for example the platform uses
+    // compiler filters.
+    const char* status = oat_file->IsExtractOnly()
+        ? OatHeader::kExtractOnlyValue
+        : oat_file->IsProfileGuideCompiled()
+            ? OatHeader::kProfileGuideCompiledValue
+            : "platform-default";
+    os << oat_file->GetLocation() << ": " << status << "\n";
+  }
+}
+
 }  // namespace art
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index c508c4b..a541d10 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -108,6 +108,8 @@
       /*out*/ std::vector<std::string>* error_msgs)
       REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_);
 
+  void DumpForSigQuit(std::ostream& os);
+
  private:
   // Check for duplicate class definitions of the given oat file against all open oat files.
   // Return true if there are any class definition collisions in the oat_file.
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 182ca36..5284c93 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"
@@ -204,6 +203,7 @@
       implicit_suspend_checks_(false),
       no_sig_chain_(false),
       is_native_bridge_loaded_(false),
+      is_native_debuggable_(false),
       zygote_max_failed_boots_(0),
       experimental_flags_(ExperimentalFlags::kNone),
       oat_file_manager_(nullptr),
@@ -1364,6 +1364,7 @@
   GetInternTable()->DumpForSigQuit(os);
   GetJavaVM()->DumpForSigQuit(os);
   GetHeap()->DumpForSigQuit(os);
+  oat_file_manager_->DumpForSigQuit(os);
   if (GetJit() != nullptr) {
     GetJit()->DumpForSigQuit(os);
   } else {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index aebfad7..36ad7f1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -583,6 +583,14 @@
 
   bool IsDebuggable() const;
 
+  bool IsNativeDebuggable() const {
+    return is_native_debuggable_;
+  }
+
+  void SetNativeDebuggable(bool value) {
+    is_native_debuggable_ = value;
+  }
+
   // Returns the build fingerprint, if set. Otherwise an empty string is returned.
   std::string GetFingerprint() {
     return fingerprint_;
@@ -804,6 +812,9 @@
   // that there's no native bridge.
   bool is_native_bridge_loaded_;
 
+  // Whether we are running under native debugger.
+  bool is_native_debuggable_;
+
   // The maximum number of failed boots we allow before pruning the dalvik cache
   // and trying again. This option is only inspected when we're running as a
   // zygote.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index afb11d3..a9ce056 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -133,22 +133,24 @@
       suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data);  // Dump time to suspend.
     }
   }
-  Dump(os, Runtime::Current()->GetDumpNativeStackOnSigQuit());
-  DumpUnattachedThreads(os);
+  bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit();
+  Dump(os, dump_native_stack);
+  DumpUnattachedThreads(os, dump_native_stack);
 }
 
-static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_ANALYSIS {
+static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack)
+    NO_THREAD_SAFETY_ANALYSIS {
   // TODO: No thread safety analysis as DumpState with a null thread won't access fields, should
   // refactor DumpState to avoid skipping analysis.
   Thread::DumpState(os, nullptr, tid);
   DumpKernelStack(os, tid, "  kernel: ", false);
-  if (kDumpUnattachedThreadNativeStack) {
+  if (dump_native_stack && kDumpUnattachedThreadNativeStack) {
     DumpNativeStack(os, tid, nullptr, "  native: ");
   }
   os << "\n";
 }
 
-void ThreadList::DumpUnattachedThreads(std::ostream& os) {
+void ThreadList::DumpUnattachedThreads(std::ostream& os, bool dump_native_stack) {
   DIR* d = opendir("/proc/self/task");
   if (!d) {
     return;
@@ -166,7 +168,7 @@
         contains = Contains(tid);
       }
       if (!contains) {
-        DumpUnattachedThread(os, tid);
+        DumpUnattachedThread(os, tid, dump_native_stack);
       }
     }
   }
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 363cab8..f97ecd3 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -161,7 +161,7 @@
   size_t RunCheckpoint(Closure* checkpoint_function, bool includeSuspended)
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_);
 
-  void DumpUnattachedThreads(std::ostream& os)
+  void DumpUnattachedThreads(std::ostream& os, bool dump_native_stack)
       REQUIRES(!Locks::thread_list_lock_);
 
   void SuspendAllDaemonThreadsForShutdown()
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4019656..537d9c9 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3992,13 +3992,17 @@
       // TODO Can we verify anything else.
       if (class_idx == class_def_->class_idx_) {
         Fail(VERIFY_ERROR_CLASS_CHANGE) << "Cannot invoke-super on self as interface";
+        return nullptr;
       }
       // TODO Revisit whether we want to allow invoke-super on direct interfaces only like the JLS
       // does.
-      mirror::Class* this_class = GetDeclaringClass().GetClass();
-      if (!reference_class->IsAssignableFrom(this_class)) {
+      if (!GetDeclaringClass().HasClass()) {
+        Fail(VERIFY_ERROR_NO_CLASS) << "Unable to resolve the full class of 'this' used in an"
+                                    << "interface invoke-super";
+        return nullptr;
+      } else if (!reference_class->IsAssignableFrom(GetDeclaringClass().GetClass())) {
         Fail(VERIFY_ERROR_CLASS_CHANGE)
-            << "invoke-super in " << PrettyClass(this_class) << " in method "
+            << "invoke-super in " << PrettyClass(GetDeclaringClass().GetClass()) << " in method "
             << PrettyMethod(dex_method_idx_, *dex_file_) << " to method "
             << PrettyMethod(method_idx, *dex_file_) << " references "
             << "non-super-interface type " << PrettyClass(reference_class);
diff --git a/test/004-checker-UnsafeTest18/src/Main.java b/test/004-checker-UnsafeTest18/src/Main.java
index bb020b9..c50613d 100644
--- a/test/004-checker-UnsafeTest18/src/Main.java
+++ b/test/004-checker-UnsafeTest18/src/Main.java
@@ -15,6 +15,7 @@
  */
 
 import java.lang.reflect.Field;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import sun.misc.Unsafe;
 
@@ -31,13 +32,17 @@
   private static Thread[] sThreads = new Thread[10];
 
   //
-  // Fields accessed by setters and adders.
+  // Fields accessed by setters and adders, and by memory fence tests.
   //
 
   public int i = 0;
   public long l = 0;
   public Object o = null;
 
+  public int x_value;
+  public int y_value;
+  public volatile boolean running;
+
   //
   // Setters.
   //
@@ -167,22 +172,22 @@
       throw new Error("No offset: " + e);
     }
 
-    // Some sanity within same thread.
+    // Some sanity on setters and adders within same thread.
 
     set32(m, intOffset, 3);
-    expectEquals32(3, m.i);
+    expectEqual32(3, m.i);
 
     set64(m, longOffset, 7L);
-    expectEquals64(7L, m.l);
+    expectEqual64(7L, m.l);
 
     setObj(m, objOffset, m);
-    expectEqualsObj(m, m.o);
+    expectEqualObj(m, m.o);
 
     add32(m, intOffset, 11);
-    expectEquals32(14, m.i);
+    expectEqual32(14, m.i);
 
     add64(m, longOffset, 13L);
-    expectEquals64(20L, m.l);
+    expectEqual64(20L, m.l);
 
     // Some sanity on setters within different threads.
 
@@ -193,7 +198,7 @@
       }
     });
     join();
-    expectEquals32(9, m.i);  // one thread's last value wins
+    expectEqual32(9, m.i);  // one thread's last value wins
 
     fork(new Runnable() {
       public void run() {
@@ -202,7 +207,7 @@
       }
     });
     join();
-    expectEquals64(109L, m.l);  // one thread's last value wins
+    expectEqual64(109L, m.l);  // one thread's last value wins
 
     fork(new Runnable() {
       public void run() {
@@ -211,7 +216,7 @@
       }
     });
     join();
-    expectEqualsObj(sThreads[9], m.o);  // one thread's last value wins
+    expectEqualObj(sThreads[9], m.o);  // one thread's last value wins
 
     // Some sanity on adders within different threads.
 
@@ -222,7 +227,7 @@
       }
     });
     join();
-    expectEquals32(559, m.i);  // all values accounted for
+    expectEqual32(559, m.i);  // all values accounted for
 
     fork(new Runnable() {
       public void run() {
@@ -231,9 +236,101 @@
       }
     });
     join();
-    expectEquals64(659L, m.l);  // all values accounted for
+    expectEqual64(659L, m.l);  // all values accounted for
 
-    // TODO: the fences
+    // Some sanity on fences within same thread. Note that memory fences within one
+    // thread make little sense, but the sanity check ensures nothing bad happens.
+
+    m.i = -1;
+    m.l = -2L;
+    m.o = null;
+
+    load();
+    store();
+    full();
+
+    expectEqual32(-1, m.i);
+    expectEqual64(-2L, m.l);
+    expectEqualObj(null, m.o);
+
+    // Some sanity on full fence within different threads. We write the non-volatile m.l after
+    // the fork(), which means there is no happens-before relation in the Java memory model
+    // with respect to the read in the threads. This relation is enforced by the memory fences
+    // and the weak-set() -> get() guard. Note that the guard semantics used here are actually
+    // too strong and already enforce total memory visibility, but this test illustrates what
+    // should still happen if Java had a true relaxed memory guard.
+
+    final AtomicBoolean guard1 = new AtomicBoolean();
+    m.l = 0L;
+
+    fork(new Runnable() {
+      public void run() {
+        while (!guard1.get());  // busy-waiting
+        full();
+        expectEqual64(-123456789L, m.l);
+      }
+    });
+
+    m.l = -123456789L;
+    full();
+    while (!guard1.weakCompareAndSet(false, true));  // relaxed memory order
+    join();
+
+    // Some sanity on release/acquire fences within different threads. We write the non-volatile
+    // m.l after the fork(), which means there is no happens-before relation in the Java memory
+    // model with respect to the read in the threads. This relation is enforced by the memory fences
+    // and the weak-set() -> get() guard. Note that the guard semantics used here are actually
+    // too strong and already enforce total memory visibility, but this test illustrates what
+    // should still happen if Java had a true relaxed memory guard.
+
+    final AtomicBoolean guard2 = new AtomicBoolean();
+    m.l = 0L;
+
+    fork(new Runnable() {
+      public void run() {
+        while (!guard2.get());  // busy-waiting
+        load();
+        expectEqual64(-987654321L, m.l);
+      }
+    });
+
+    m.l = -987654321L;
+    store();
+    while (!guard2.weakCompareAndSet(false, true));  // relaxed memory order
+    join();
+
+    // Some sanity on release/acquire fences within different threads using a test suggested by
+    // Hans Boehm. Even this test remains with the realm of sanity only, since having the threads
+    // read the same value consistently would be a valid outcome.
+
+    m.x_value = -1;
+    m.y_value = -1;
+    m.running = true;
+
+    fork(new Runnable() {
+      public void run() {
+        while (m.running) {
+          for (int few_times = 0; few_times < 1000; few_times++) {
+            // Read y first, then load fence, then read x.
+            // They should appear in order, if seen at all.
+            int local_y = m.y_value;
+            load();
+            int local_x = m.x_value;
+            expectLessThanOrEqual32(local_y, local_x);
+          }
+        }
+      }
+    });
+
+    for (int many_times = 0; many_times < 100000; many_times++) {
+      m.x_value = many_times;
+      store();
+      m.y_value = many_times;
+    }
+    m.running = false;
+    join();
+
+    // All done!
 
     System.out.println("passed");
   }
@@ -250,19 +347,25 @@
     }
   }
 
-  private static void expectEquals32(int expected, int result) {
+  private static void expectEqual32(int expected, int result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
 
-  private static void expectEquals64(long expected, long result) {
+  private static void expectLessThanOrEqual32(int val1, int val2) {
+    if (val1 > val2) {
+      throw new Error("Expected: " + val1 + " <= " + val2);
+    }
+  }
+
+  private static void expectEqual64(long expected, long result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
 
-  private static void expectEqualsObj(Object expected, Object result) {
+  private static void expectEqualObj(Object expected, Object result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
diff --git a/test/145-alloc-tracking-stress/src/Main.java b/test/145-alloc-tracking-stress/src/Main.java
index 418690a..752fdd9 100644
--- a/test/145-alloc-tracking-stress/src/Main.java
+++ b/test/145-alloc-tracking-stress/src/Main.java
@@ -1,4 +1,5 @@
 /*
+
  * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index dd4ffe4..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
@@ -1601,6 +1618,24 @@
     return (short) (value & 0x17fff);
   }
 
+  /// CHECK-START: double Main.shortAnd0xffffToShortToDouble(short) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Mask:i\d+>>     IntConstant 65535
+  /// CHECK-DAG:      <<And:i\d+>>      And [<<Mask>>,<<Arg>>]
+  /// CHECK-DAG:      <<Same:s\d+>>     TypeConversion [<<And>>]
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Same>>]
+  /// CHECK-DAG:                        Return [<<Double>>]
+
+  /// CHECK-START: double Main.shortAnd0xffffToShortToDouble(short) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Double>>]
+
+  public static double shortAnd0xffffToShortToDouble(short value) {
+    short same = (short) (value & 0xffff);
+    return (double) same;
+  }
+
   /// CHECK-START: int Main.intReverseCondition(int) instruction_simplifier (before)
   /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
   /// CHECK-DAG:      <<Const42:i\d+>>  IntConstant 42
@@ -1653,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);
@@ -1717,56 +1753,63 @@
     assertIntEquals(doubleConditionEqualZero(6.0), 54);
     assertIntEquals(doubleConditionEqualZero(43.0), 13);
 
-    assertIntEquals(intToDoubleToInt(1234567), 1234567);
-    assertIntEquals(intToDoubleToInt(Integer.MIN_VALUE), Integer.MIN_VALUE);
-    assertIntEquals(intToDoubleToInt(Integer.MAX_VALUE), Integer.MAX_VALUE);
-    assertStringEquals(intToDoubleToIntPrint(7654321), "d=7654321.0, i=7654321");
-    assertIntEquals(byteToDoubleToInt((byte) 12), 12);
-    assertIntEquals(byteToDoubleToInt(Byte.MIN_VALUE), Byte.MIN_VALUE);
-    assertIntEquals(byteToDoubleToInt(Byte.MAX_VALUE), Byte.MAX_VALUE);
-    assertIntEquals(floatToDoubleToInt(11.3f), 11);
-    assertStringEquals(floatToDoubleToIntPrint(12.25f), "d=12.25, i=12");
-    assertIntEquals(byteToDoubleToShort((byte) 123), 123);
-    assertIntEquals(byteToDoubleToShort(Byte.MIN_VALUE), Byte.MIN_VALUE);
-    assertIntEquals(byteToDoubleToShort(Byte.MAX_VALUE), Byte.MAX_VALUE);
-    assertIntEquals(charToDoubleToShort((char) 1234), 1234);
-    assertIntEquals(charToDoubleToShort(Character.MIN_VALUE), Character.MIN_VALUE);
-    assertIntEquals(charToDoubleToShort(Character.MAX_VALUE), /* sign-extended */ -1);
-    assertIntEquals(floatToIntToShort(12345.75f), 12345);
-    assertIntEquals(floatToIntToShort((float)(Short.MIN_VALUE - 1)), Short.MAX_VALUE);
-    assertIntEquals(floatToIntToShort((float)(Short.MAX_VALUE + 1)), Short.MIN_VALUE);
-    assertIntEquals(intToFloatToInt(-54321), -54321);
-    assertDoubleEquals(longToIntToDouble(0x1234567812345678L), (double) 0x12345678);
-    assertDoubleEquals(longToIntToDouble(Long.MIN_VALUE), 0.0);
-    assertDoubleEquals(longToIntToDouble(Long.MAX_VALUE), -1.0);
-    assertLongEquals(longToIntToLong(0x1234567812345678L), 0x0000000012345678L);
-    assertLongEquals(longToIntToLong(0x1234567887654321L), 0xffffffff87654321L);
-    assertLongEquals(longToIntToLong(Long.MIN_VALUE), 0L);
-    assertLongEquals(longToIntToLong(Long.MAX_VALUE), -1L);
-    assertIntEquals(shortToCharToShort((short) -5678), (short) -5678);
-    assertIntEquals(shortToCharToShort(Short.MIN_VALUE), Short.MIN_VALUE);
-    assertIntEquals(shortToCharToShort(Short.MAX_VALUE), Short.MAX_VALUE);
-    assertIntEquals(shortToLongToInt((short) 5678), 5678);
-    assertIntEquals(shortToLongToInt(Short.MIN_VALUE), Short.MIN_VALUE);
-    assertIntEquals(shortToLongToInt(Short.MAX_VALUE), Short.MAX_VALUE);
-    assertIntEquals(shortToCharToByte((short) 0x1234), 0x34);
-    assertIntEquals(shortToCharToByte((short) 0x12f0), -0x10);
-    assertIntEquals(shortToCharToByte(Short.MIN_VALUE), 0);
-    assertIntEquals(shortToCharToByte(Short.MAX_VALUE), -1);
-    assertStringEquals(shortToCharToBytePrint((short) 1025), "c=1025, b=1");
-    assertStringEquals(shortToCharToBytePrint((short) 1023), "c=1023, b=-1");
-    assertStringEquals(shortToCharToBytePrint((short) -1), "c=65535, b=-1");
+    assertIntEquals(1234567, intToDoubleToInt(1234567));
+    assertIntEquals(Integer.MIN_VALUE, intToDoubleToInt(Integer.MIN_VALUE));
+    assertIntEquals(Integer.MAX_VALUE, intToDoubleToInt(Integer.MAX_VALUE));
+    assertStringEquals("d=7654321.0, i=7654321", intToDoubleToIntPrint(7654321));
+    assertIntEquals(12, byteToDoubleToInt((byte) 12));
+    assertIntEquals(Byte.MIN_VALUE, byteToDoubleToInt(Byte.MIN_VALUE));
+    assertIntEquals(Byte.MAX_VALUE, byteToDoubleToInt(Byte.MAX_VALUE));
+    assertIntEquals(11, floatToDoubleToInt(11.3f));
+    assertStringEquals("d=12.25, i=12", floatToDoubleToIntPrint(12.25f));
+    assertIntEquals(123, byteToDoubleToShort((byte) 123));
+    assertIntEquals(Byte.MIN_VALUE, byteToDoubleToShort(Byte.MIN_VALUE));
+    assertIntEquals(Byte.MAX_VALUE, byteToDoubleToShort(Byte.MAX_VALUE));
+    assertIntEquals(1234, charToDoubleToShort((char) 1234));
+    assertIntEquals(Character.MIN_VALUE, charToDoubleToShort(Character.MIN_VALUE));
+    assertIntEquals(/* sign-extended */ -1, charToDoubleToShort(Character.MAX_VALUE));
+    assertIntEquals(12345, floatToIntToShort(12345.75f));
+    assertIntEquals(Short.MAX_VALUE, floatToIntToShort((float)(Short.MIN_VALUE - 1)));
+    assertIntEquals(Short.MIN_VALUE, floatToIntToShort((float)(Short.MAX_VALUE + 1)));
+    assertIntEquals(-54321, intToFloatToInt(-54321));
+    assertDoubleEquals((double) 0x12345678, longToIntToDouble(0x1234567812345678L));
+    assertDoubleEquals(0.0, longToIntToDouble(Long.MIN_VALUE));
+    assertDoubleEquals(-1.0, longToIntToDouble(Long.MAX_VALUE));
+    assertLongEquals(0x0000000012345678L, longToIntToLong(0x1234567812345678L));
+    assertLongEquals(0xffffffff87654321L, longToIntToLong(0x1234567887654321L));
+    assertLongEquals(0L, longToIntToLong(Long.MIN_VALUE));
+    assertLongEquals(-1L, longToIntToLong(Long.MAX_VALUE));
+    assertIntEquals((short) -5678, shortToCharToShort((short) -5678));
+    assertIntEquals(Short.MIN_VALUE, shortToCharToShort(Short.MIN_VALUE));
+    assertIntEquals(Short.MAX_VALUE, shortToCharToShort(Short.MAX_VALUE));
+    assertIntEquals(5678, shortToLongToInt((short) 5678));
+    assertIntEquals(Short.MIN_VALUE, shortToLongToInt(Short.MIN_VALUE));
+    assertIntEquals(Short.MAX_VALUE, shortToLongToInt(Short.MAX_VALUE));
+    assertIntEquals(0x34, shortToCharToByte((short) 0x1234));
+    assertIntEquals(-0x10, shortToCharToByte((short) 0x12f0));
+    assertIntEquals(0, shortToCharToByte(Short.MIN_VALUE));
+    assertIntEquals(-1, shortToCharToByte(Short.MAX_VALUE));
+    assertStringEquals("c=1025, b=1", shortToCharToBytePrint((short) 1025));
+    assertStringEquals("c=1023, b=-1", shortToCharToBytePrint((short) 1023));
+    assertStringEquals("c=65535, b=-1", shortToCharToBytePrint((short) -1));
 
-    assertIntEquals(longAnd0xffToByte(0x1234432112344321L), 0x21);
-    assertIntEquals(longAnd0xffToByte(Long.MIN_VALUE), 0);
-    assertIntEquals(longAnd0xffToByte(Long.MAX_VALUE), -1);
-    assertIntEquals(intAnd0x1ffffToChar(0x43211234), 0x1234);
-    assertIntEquals(intAnd0x1ffffToChar(Integer.MIN_VALUE), 0);
-    assertIntEquals(intAnd0x1ffffToChar(Integer.MAX_VALUE), Character.MAX_VALUE);
-    assertIntEquals(intAnd0x17fffToShort(0x87654321), 0x4321);
-    assertIntEquals(intAnd0x17fffToShort(0x88888888), 0x0888);
-    assertIntEquals(intAnd0x17fffToShort(Integer.MIN_VALUE), 0);
-    assertIntEquals(intAnd0x17fffToShort(Integer.MAX_VALUE), Short.MAX_VALUE);
+    assertIntEquals(0x21, longAnd0xffToByte(0x1234432112344321L));
+    assertIntEquals(0, longAnd0xffToByte(Long.MIN_VALUE));
+    assertIntEquals(-1, longAnd0xffToByte(Long.MAX_VALUE));
+    assertIntEquals(0x1234, intAnd0x1ffffToChar(0x43211234));
+    assertIntEquals(0, intAnd0x1ffffToChar(Integer.MIN_VALUE));
+    assertIntEquals(Character.MAX_VALUE, intAnd0x1ffffToChar(Integer.MAX_VALUE));
+    assertIntEquals(0x4321, intAnd0x17fffToShort(0x87654321));
+    assertIntEquals(0x0888, intAnd0x17fffToShort(0x88888888));
+    assertIntEquals(0, intAnd0x17fffToShort(Integer.MIN_VALUE));
+    assertIntEquals(Short.MAX_VALUE, intAnd0x17fffToShort(Integer.MAX_VALUE));
+
+    assertDoubleEquals(0.0, shortAnd0xffffToShortToDouble((short) 0));
+    assertDoubleEquals(1.0, shortAnd0xffffToShortToDouble((short) 1));
+    assertDoubleEquals(-2.0, shortAnd0xffffToShortToDouble((short) -2));
+    assertDoubleEquals(12345.0, shortAnd0xffffToShortToDouble((short) 12345));
+    assertDoubleEquals((double)Short.MAX_VALUE, shortAnd0xffffToShortToDouble(Short.MAX_VALUE));
+    assertDoubleEquals((double)Short.MIN_VALUE, shortAnd0xffffToShortToDouble(Short.MIN_VALUE));
 
     assertIntEquals(intReverseCondition(41), 13);
     assertIntEquals(intReverseConditionNaN(-5), 13);
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%
copy from runtime/native/java_lang_Runtime.h
copy 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..dd3be006 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/565-checker-rotate/src/Main.java b/test/565-checker-rotate/src/Main.java
index 33bbe02..d7f57d8 100644
--- a/test/565-checker-rotate/src/Main.java
+++ b/test/565-checker-rotate/src/Main.java
@@ -16,112 +16,534 @@
 
 public class Main {
 
-  /// CHECK-START: int Main.rotateLeft32(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerRotateLeft
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int rotateLeft32(int x, int y) {
-    return Integer.rotateLeft(x, y);
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
+  /// CHECK-NOT:                      Phi
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier_after_bce (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                      Select
+
+  private static int rotateLeftBoolean(boolean value, int distance) {
+    return Integer.rotateLeft(value ? 1 : 0, distance);
   }
 
-  /// CHECK-START: long Main.rotateLeft64(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect intrinsic:LongRotateLeft
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static long rotateLeft64(long x, int y) {
-    return Long.rotateLeft(x, y);
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftByte(byte value, int distance) {
+    return Integer.rotateLeft(value, distance);
   }
 
-  /// CHECK-START: int Main.rotateRight32(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerRotateRight
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int rotateRight32(int x, int y) {
-    return Integer.rotateRight(x, y);
+  /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftShort(short value, int distance) {
+    return Integer.rotateLeft(value, distance);
   }
 
-  /// CHECK-START: long Main.rotateRight64(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect intrinsic:LongRotateRight
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static long rotateRight64(long x, int y) {
-    return Long.rotateRight(x, y);
+  /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftChar(char value, int distance) {
+    return Integer.rotateLeft(value, distance);
   }
 
+  /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateLeftInt(int value, int distance) {
+    return Integer.rotateLeft(value, distance);
+  }
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<NegDist:i\d+>> Neg [<<ArgDist>>]
+  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<NegDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static long rotateLeftLong(long value, int distance) {
+    return Long.rotateLeft(value, distance);
+  }
+
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                     Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<Val>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
+  /// CHECK-DAG:     <<One:i\d+>>     IntConstant 1
+  /// CHECK-DAG:     <<SelVal:i\d+>>  Select [<<Zero>>,<<One>>,<<ArgVal>>]
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<SelVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
+  /// CHECK-NOT:                     Phi
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier_after_bce (after)
+  /// CHECK:         <<ArgVal:z\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                     Select
+
+  private static int rotateRightBoolean(boolean value, int distance) {
+    return Integer.rotateRight(value ? 1 : 0, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightByte(byte value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightShort(short value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightChar(char value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static int rotateRightInt(int value, int distance) {
+    return Integer.rotateRight(value, distance);
+  }
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+  /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
+  /// CHECK:         <<ArgDist:i\d+>> ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>>  Ror [<<ArgVal>>,<<ArgDist>>]
+  /// CHECK-DAG:                      Return [<<Result>>]
+
+  /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  private static long rotateRightLong(long value, int distance) {
+    return Long.rotateRight(value, distance);
+  }
+
+
+  public static void testRotateLeftBoolean() {
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0, rotateLeftBoolean(false, i));
+      expectEqualsInt(1 << i, rotateLeftBoolean(true, i));
+    }
+  }
+
+  public static void testRotateLeftByte() {
+    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0));
+    expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1));
+    expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31));
+    expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32));  // overshoot
+    expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1));
+    expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2));
+    expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4));
+    expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i));
+      expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i));
+      expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i));
+    }
+  }
+
+  public static void testRotateLeftShort() {
+    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0));
+    expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1));
+    expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31));
+    expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32));  // overshoot
+    expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1));
+    expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2));
+    expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4));
+    expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i));
+      expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i));
+      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i));
+    }
+  }
+
+  public static void testRotateLeftChar() {
+    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0));
+    expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1));
+    expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31));
+    expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32));  // overshoot
+    expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1));
+    expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2));
+    expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4));
+    expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8));
+    expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i));
+      expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i));
+      expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i));
+    }
+  }
+
+  public static void testRotateLeftInt() {
+    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0));
+    expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1));
+    expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31));
+    expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32));  // overshoot
+    expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1));
+    expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2));
+    expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4));
+    expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i));
+      expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i));
+      expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i));
+    }
+  }
+
+  public static void testRotateLeftLong() {
+    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0));
+    expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1));
+    expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63));
+    expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64));  // overshoot
+    expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1));
+    expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2));
+    expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4));
+    expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8));
+    for (int i = 0; i < 70; i++) {  // overshoot a bit
+      int j = i & 63;
+      expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i));
+      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i));
+      expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i));
+      expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
+                       rotateLeftLong(0x123456789ABCDEF0L, i));
+    }
+  }
+
+  public static void testRotateRightBoolean() {
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0, rotateRightBoolean(false, i));
+      expectEqualsInt(1 << (32 - i), rotateRightBoolean(true, i));
+    }
+  }
+
+  public static void testRotateRightByte() {
+    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0));
+    expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1));
+    expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31));
+    expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32));  // overshoot
+    expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1));
+    expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2));
+    expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4));
+    expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i));
+      expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i));
+      expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i));
+    }
+  }
+
+  public static void testRotateRightShort() {
+    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0));
+    expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1));
+    expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31));
+    expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32));  // overshoot
+    expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1));
+    expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2));
+    expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4));
+    expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i));
+      expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i));
+      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i));
+    }
+  }
+
+  public static void testRotateRightChar() {
+    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0));
+    expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1));
+    expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31));
+    expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32));  // overshoot
+    expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1));
+    expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2));
+    expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4));
+    expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i));
+      expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i));
+      expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i));
+    }
+  }
+
+  public static void testRotateRightInt() {
+    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0));
+    expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1));
+    expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31));
+    expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32));  // overshoot
+    expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1));
+    expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2));
+    expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4));
+    expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8));
+    for (int i = 0; i < 40; i++) {  // overshoot a bit
+      int j = i & 31;
+      expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i));
+      expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i));
+      expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i));
+      expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i));
+    }
+  }
+
+  public static void testRotateRightLong() {
+    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0));
+    expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1));
+    expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63));
+    expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64));  // overshoot
+    expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1));
+    expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2));
+    expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4));
+    expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8));
+    for (int i = 0; i < 70; i++) {  // overshoot a bit
+      int j = i & 63;
+      expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i));
+      expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i));
+      expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i));
+      expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
+                       rotateRightLong(0x123456789ABCDEF0L, i));
+    }
+  }
+
+
   public static void main(String args[]) {
-    expectEquals32(0x00000001, rotateLeft32(0x00000001, 0));
-    expectEquals32(0x00000002, rotateLeft32(0x00000001, 1));
-    expectEquals32(0x80000000, rotateLeft32(0x00000001, 31));
-    expectEquals32(0x00000001, rotateLeft32(0x00000001, 32));  // overshoot
-    expectEquals32(0x00000003, rotateLeft32(0x80000001, 1));
-    expectEquals32(0x00000006, rotateLeft32(0x80000001, 2));
-    expectEquals32(0x23456781, rotateLeft32(0x12345678, 4));
-    expectEquals32(0xBCDEF09A, rotateLeft32(0x9ABCDEF0, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEquals32(0x00000000, rotateLeft32(0x00000000, i));
-      expectEquals32(0xFFFFFFFF, rotateLeft32(0xFFFFFFFF, i));
-      expectEquals32(1 << j, rotateLeft32(0x00000001, i));
-      expectEquals32((0x12345678 << j) | (0x12345678 >>> -j),
-                     rotateLeft32(0x12345678, i));
-    }
+    testRotateLeftBoolean();
+    testRotateLeftByte();
+    testRotateLeftShort();
+    testRotateLeftChar();
+    testRotateLeftInt();
+    testRotateLeftLong();
 
-    expectEquals64(0x0000000000000001L, rotateLeft64(0x0000000000000001L, 0));
-    expectEquals64(0x0000000000000002L, rotateLeft64(0x0000000000000001L, 1));
-    expectEquals64(0x8000000000000000L, rotateLeft64(0x0000000000000001L, 63));
-    expectEquals64(0x0000000000000001L, rotateLeft64(0x0000000000000001L, 64));  // overshoot
-    expectEquals64(0x0000000000000003L, rotateLeft64(0x8000000000000001L, 1));
-    expectEquals64(0x0000000000000006L, rotateLeft64(0x8000000000000001L, 2));
-    expectEquals64(0x23456789ABCDEF01L, rotateLeft64(0x123456789ABCDEF0L, 4));
-    expectEquals64(0x3456789ABCDEF012L, rotateLeft64(0x123456789ABCDEF0L, 8));
-    for (int i = 0; i < 70; i++) {  // overshoot a bit
-      int j = i & 63;
-      expectEquals64(0x0000000000000000L, rotateLeft64(0x0000000000000000L, i));
-      expectEquals64(0xFFFFFFFFFFFFFFFFL, rotateLeft64(0xFFFFFFFFFFFFFFFFL, i));
-      expectEquals64(1L << j, rotateLeft64(0x0000000000000001, i));
-      expectEquals64((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
-                     rotateLeft64(0x123456789ABCDEF0L, i));
-    }
-
-    expectEquals32(0x80000000, rotateRight32(0x80000000, 0));
-    expectEquals32(0x40000000, rotateRight32(0x80000000, 1));
-    expectEquals32(0x00000001, rotateRight32(0x80000000, 31));
-    expectEquals32(0x80000000, rotateRight32(0x80000000, 32));  // overshoot
-    expectEquals32(0xC0000000, rotateRight32(0x80000001, 1));
-    expectEquals32(0x60000000, rotateRight32(0x80000001, 2));
-    expectEquals32(0x81234567, rotateRight32(0x12345678, 4));
-    expectEquals32(0xF09ABCDE, rotateRight32(0x9ABCDEF0, 8));
-    for (int i = 0; i < 40; i++) {  // overshoot a bit
-      int j = i & 31;
-      expectEquals32(0x00000000, rotateRight32(0x00000000, i));
-      expectEquals32(0xFFFFFFFF, rotateRight32(0xFFFFFFFF, i));
-      expectEquals32(0x80000000 >>> j, rotateRight32(0x80000000, i));
-      expectEquals32((0x12345678 >>> j) | (0x12345678 << -j),
-                     rotateRight32(0x12345678, i));
-    }
-
-    expectEquals64(0x8000000000000000L, rotateRight64(0x8000000000000000L, 0));
-    expectEquals64(0x4000000000000000L, rotateRight64(0x8000000000000000L, 1));
-    expectEquals64(0x0000000000000001L, rotateRight64(0x8000000000000000L, 63));
-    expectEquals64(0x8000000000000000L, rotateRight64(0x8000000000000000L, 64));  // overshoot
-    expectEquals64(0xC000000000000000L, rotateRight64(0x8000000000000001L, 1));
-    expectEquals64(0x6000000000000000L, rotateRight64(0x8000000000000001L, 2));
-    expectEquals64(0x0123456789ABCDEFL, rotateRight64(0x123456789ABCDEF0L, 4));
-    expectEquals64(0xF0123456789ABCDEL, rotateRight64(0x123456789ABCDEF0L, 8));
-    for (int i = 0; i < 70; i++) {  // overshoot a bit
-      int j = i & 63;
-      expectEquals64(0x0000000000000000L, rotateRight64(0x0000000000000000L, i));
-      expectEquals64(0xFFFFFFFFFFFFFFFFL, rotateRight64(0xFFFFFFFFFFFFFFFFL, i));
-      expectEquals64(0x8000000000000000L >>> j, rotateRight64(0x8000000000000000L, i));
-      expectEquals64((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
-                     rotateRight64(0x123456789ABCDEF0L, i));
-    }
+    testRotateRightBoolean();
+    testRotateRightByte();
+    testRotateRightShort();
+    testRotateRightChar();
+    testRotateRightInt();
+    testRotateRightLong();
 
     System.out.println("passed");
   }
 
-  private static void expectEquals32(int expected, int result) {
+
+  private static void expectEqualsInt(int expected, int result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
-  private static void expectEquals64(long expected, long result) {
+
+  private static void expectEqualsLong(long expected, long result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
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/582-checker-bce-length/expected.txt b/test/582-checker-bce-length/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/582-checker-bce-length/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/582-checker-bce-length/info.txt b/test/582-checker-bce-length/info.txt
new file mode 100644
index 0000000..cb826cd
--- /dev/null
+++ b/test/582-checker-bce-length/info.txt
@@ -0,0 +1 @@
+Regression test on deopt bounds check elimination.
diff --git a/test/582-checker-bce-length/src/Main.java b/test/582-checker-bce-length/src/Main.java
new file mode 100644
index 0000000..3565b6b
--- /dev/null
+++ b/test/582-checker-bce-length/src/Main.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test on duplicate removal of same bounds check.
+ */
+public class Main {
+
+  /// CHECK-START: void Main.doit1(int[]) BCE (before)
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.doit1(int[]) BCE (after)
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.doit1(int[]) BCE (after)
+  /// CHECK-NOT: Deoptimize
+  public static void doit1(int[] a) {
+    a[a.length-3] = 1;
+    a[a.length-2] = 2;
+    a[a.length-1] = 3;
+    // This introduces a problematic BoundsCheck(x,x) node
+    // (1) certain OOB, so should be rejected
+    // (2) exposed bug in removing same BC twice if (1) would not be done.
+    a[a.length-0] = 4;
+  }
+
+  /// CHECK-START: void Main.doit2(int[]) BCE (before)
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.doit2(int[]) BCE (after)
+  /// CHECK-DAG: Deoptimize
+  /// CHECK-DAG: Deoptimize
+  //
+  /// CHECK-START: void Main.doit2(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  public static void doit2(int[] a) {
+    a[a.length-4] = -101;
+    a[a.length-3] = -102;
+    a[a.length-2] = -103;
+    a[a.length-1] = -104;
+  }
+
+  public static void main(String[] args) {
+    int[] a = new int[4];
+
+    int fail = 0;
+    try {
+      doit1(a);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      fail++;
+    }
+    expectEquals(1, fail);
+    expectEquals(0, a[0]);
+    expectEquals(1, a[1]);
+    expectEquals(2, a[2]);
+    expectEquals(3, a[3]);
+
+    try {
+      doit2(a);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      fail++;
+    }
+    expectEquals(1, fail);
+    expectEquals(-101, a[0]);
+    expectEquals(-102, a[1]);
+    expectEquals(-103, a[2]);
+    expectEquals(-104, a[3]);
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
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%
rename from runtime/native/java_lang_Runtime.h
rename 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/586-checker-null-array-get/expected.txt b/test/586-checker-null-array-get/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/586-checker-null-array-get/expected.txt
diff --git a/test/586-checker-null-array-get/info.txt b/test/586-checker-null-array-get/info.txt
new file mode 100644
index 0000000..81b42e9
--- /dev/null
+++ b/test/586-checker-null-array-get/info.txt
@@ -0,0 +1,3 @@
+Regression test for the load store elimination of optimizing
+that used to merge two array gets that have the same inputs but
+not the same type. Note that this only happens if the array is null.
diff --git a/test/586-checker-null-array-get/src/Main.java b/test/586-checker-null-array-get/src/Main.java
new file mode 100644
index 0000000..4b03ff2
--- /dev/null
+++ b/test/586-checker-null-array-get/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * 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 Object[] getObjectArray() { return null; }
+  public static long[] getLongArray() { return null; }
+
+  public static void main(String[] args) {
+    try {
+      foo();
+      throw new Error("Expected NullPointerException");
+    } catch (NullPointerException e) {
+      // Expected.
+    }
+  }
+
+  /// CHECK-START: void Main.foo() load_store_elimination (after)
+  /// CHECK-DAG: <<Null:l\d+>>  NullConstant
+  /// CHECK-DAG: <<Check:l\d+>> NullCheck [<<Null>>]
+  /// CHECK-DAG: <<Get1:j\d+>>  ArrayGet [<<Check>>,{{i\d+}}]
+  /// CHECK-DAG: <<Get2:l\d+>>  ArrayGet [<<Check>>,{{i\d+}}]
+  public static void foo() {
+    longField = getLongArray()[0];
+    objectField = getObjectArray()[0];
+  }
+
+  public static long longField;
+  public static Object objectField;
+}
diff --git a/test/974-verify-interface-super/expected.txt b/test/974-verify-interface-super/expected.txt
new file mode 100644
index 0000000..7ba7491
--- /dev/null
+++ b/test/974-verify-interface-super/expected.txt
@@ -0,0 +1 @@
+OK. No exception before invoke!
diff --git a/test/974-verify-interface-super/info.txt b/test/974-verify-interface-super/info.txt
new file mode 100644
index 0000000..c5ff1f6
--- /dev/null
+++ b/test/974-verify-interface-super/info.txt
@@ -0,0 +1,3 @@
+Test that we do the right thing with invoke-super on interfaces when there are
+verifier errors.
+
diff --git a/test/974-verify-interface-super/smali/base.smali b/test/974-verify-interface-super/smali/base.smali
new file mode 100644
index 0000000..c7875de
--- /dev/null
+++ b/test/974-verify-interface-super/smali/base.smali
@@ -0,0 +1,31 @@
+# Copyright 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 LBase;
+
+.super La/klass/that/does/not/Exist;
+
+.method public static run()V
+    .locals 4
+    new-instance v0, LBase;
+    invoke-direct {v0}, LBase;-><init>()V
+    invoke-virtual {v0}, LBase;->SayHi()V
+    return-void
+.end method
+
+.method public SayHi()V
+.locals 2
+  invoke-super {p0}, LIface;->SayHi()V
+  return-void
+.end method
diff --git a/test/974-verify-interface-super/smali/iface.smali b/test/974-verify-interface-super/smali/iface.smali
new file mode 100644
index 0000000..89f9c0b
--- /dev/null
+++ b/test/974-verify-interface-super/smali/iface.smali
@@ -0,0 +1,22 @@
+# Copyright 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 abstract interface LIface;
+
+.super Ljava/lang/Object;
+
+.method public SayHi()V
+.locals 0
+    return-void
+.end method
diff --git a/test/974-verify-interface-super/smali/main.smali b/test/974-verify-interface-super/smali/main.smali
new file mode 100644
index 0000000..be4016c
--- /dev/null
+++ b/test/974-verify-interface-super/smali/main.smali
@@ -0,0 +1,40 @@
+# Copyright 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 LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+    .locals 4
+    const-string v0, "OK. No exception before invoke!"
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+    :try_start
+        invoke-static {}, LBase;->run()V
+        const-string v0, "FAIL: no exception!"
+        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+        invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+        goto :end
+    :try_end
+    .catch Ljava/lang/LinkageError; {:try_start .. :try_end} :end
+    .catch Ljava/lang/Throwable; {:try_start .. :try_end} :error
+    :error
+        move-exception v0
+        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+        invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+        invoke-virtual {v0}, Ljava/lang/Throwable;->printStackTrace()V
+    :end
+    return-void
+.end method
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index bb7daf8..30f1d78 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -538,9 +538,7 @@
 TEST_ART_BROKEN_OPTIMIZING_DEBUGGABLE_RUN_TESTS :=
 
 # Tests that should fail in the read barrier configuration with the interpreter.
-# 145: Test sometimes times out in read barrier configuration (b/27467554).
-TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS := \
-  145-alloc-tracking-stress
+TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS :=
 
 # Tests that should fail in the read barrier configuration with the default (Quick) compiler (AOT).
 # Quick has no support for read barriers and punts to the interpreter, so this list is composed of
@@ -550,7 +548,6 @@
   $(TEST_ART_BROKEN_INTERPRETER_RUN_TESTS)
 
 # Tests that should fail in the read barrier configuration with the Optimizing compiler (AOT).
-# 145: Test sometimes times out in read barrier configuration (b/27467554).
 # 484: Baker's fast path based read barrier compiler instrumentation generates code containing
 #      more parallel moves on x86, thus some Checker assertions may fail.
 # 527: On ARM64, the read barrier instrumentation does not support the HArm64IntermediateAddress
@@ -558,15 +555,12 @@
 # 537: Expects an array copy to be intrinsified on x86-64, but calling-on-slowpath intrinsics are
 #      not yet handled in the read barrier configuration.
 TEST_ART_BROKEN_OPTIMIZING_READ_BARRIER_RUN_TESTS := \
-  145-alloc-tracking-stress \
   484-checker-register-hints \
   527-checker-array-access-split \
   537-checker-arraycopy
 
 # Tests that should fail in the read barrier configuration with JIT (Optimizing compiler).
-# 145: Test sometimes times out in read barrier configuration (b/27467554).
-TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS := \
-  145-alloc-tracking-stress
+TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS :=
 
 ifeq ($(ART_USE_READ_BARRIER),true)
   ifneq (,$(filter interpreter,$(COMPILER_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/etc/run-test-jar b/test/etc/run-test-jar
index 2db1e6c..b360f67 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -66,6 +66,10 @@
         fi
         LIB="$1"
         shift
+    elif [ "x$1" = "x--gc-stress" ]; then
+        # Give an extra 5 mins if we are gc-stress.
+        TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300))
+        shift
     elif [ "x$1" = "x--testlib" ]; then
         shift
         if [ "x$1" = "x" ]; then
diff --git a/test/run-test b/test/run-test
index d0f93b9..3350b35 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
@@ -394,7 +389,7 @@
   run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc"
 fi
 if [ "$gc_stress" = "true" ]; then
-  run_args="${run_args} --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
+  run_args="${run_args} --gc-stress --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
 fi
 if [ "$trace" = "true" ]; then
     run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 46100ae..2533ce2 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -270,5 +270,12 @@
   description: "Only work with --mode=activity",
   result: EXEC_FAILED,
   names: [ "libcore.java.io.FileTest#testJavaIoTmpdirMutable" ]
+},
+{
+  description: "Made for extending, shouldn't be run",
+  result: EXEC_FAILED,
+  names: ["jsr166.CollectionTest#testEmptyMeansEmpty",
+          "jsr166.Collection8Test#testForEach",
+          "jsr166.Collection8Test#testForEachConcurrentStressTest"]
 }
 ]
diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt
index 95f0c2d..75d1eff 100644
--- a/tools/libcore_failures_concurrent_collector.txt
+++ b/tools/libcore_failures_concurrent_collector.txt
@@ -16,5 +16,11 @@
   names: ["jsr166.LinkedTransferQueueTest#testTransfer2",
           "jsr166.LinkedTransferQueueTest#testWaitingConsumer"],
   bug: 25883050
+},
+{
+  description: "libcore.java.lang.OldSystemTest#test_gc failure on armv8-concurrent-collector.",
+  result: EXEC_FAILED,
+  names: ["libcore.java.lang.OldSystemTest#test_gc"],
+  bug: 26155567
 }
 ]