Merge "Fix and improve reference cache mod-union table"
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 3a1bd09..7550f50 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -133,10 +133,6 @@
 ART_TARGET_CLANG_CFLAGS_x86 :=
 ART_TARGET_CLANG_CFLAGS_x86_64 :=
 
-# These are necessary for Clang ARM64 ART builds. TODO: remove.
-ART_TARGET_CLANG_CFLAGS_arm64  += \
-  -DNVALGRIND
-
 # Warn about thread safety violations with clang.
 art_clang_cflags := -Wthread-safety -Wthread-safety-negative
 
@@ -299,6 +295,22 @@
 ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
 ART_HOST_ASFLAGS += $(art_asflags)
 
+# Disable -Wpessimizing-move: triggered for art/runtime/base/variant_map.h:261
+# Adding this flag to art_clang_cflags doesn't work because -Wall gets added to
+# ART_HOST_CFLAGS (as a part of art_cflags) after
+# -Wno-pessimizing-move.  Instead, add the flag here to both
+# ART_TARGET_CLANG_CFLAGS and ART_HOST_CFLAGS
+ifeq ($(ART_HOST_CLANG),true)
+ART_HOST_CFLAGS += -Wno-pessimizing-move
+endif
+ART_TARGET_CLANG_CFLAGS += -Wno-pessimizing-move
+
+# The latest clang update trips over many of the files in art and never finishes
+# compiling for aarch64 with -O3 (or -O2). Drop back to -O1 while we investigate
+# to stop punishing the build server.
+# Bug: http://b/23256622
+ART_TARGET_CLANG_CFLAGS_arm64 += -O1
+
 ifndef LIBART_IMG_TARGET_BASE_ADDRESS
   $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
 endif
@@ -363,7 +375,7 @@
   endif
 
   LOCAL_CLANG_CFLAGS := $(ART_TARGET_CLANG_CFLAGS)
-  $(foreach arch,$(ART_SUPPORTED_ARCH),
+  $(foreach arch,$(ART_TARGET_SUPPORTED_ARCH),
     LOCAL_CLANG_CFLAGS_$(arch) += $$(ART_TARGET_CLANG_CFLAGS_$(arch)))
 
   # Clear locally used variables.
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index cf01884..db76cc6 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -593,13 +593,20 @@
     return true;
   }
 
+  // At this point lit != 1 (which is a power of two).
+  DCHECK_NE(lit, 1);
   if (IsPowerOfTwo(lit - 1)) {
     op->op = kOpAdd;
     op->shift = CTZ(lit - 1);
     return true;
   }
 
-  if (IsPowerOfTwo(lit + 1)) {
+  if (lit == -1) {
+    // Can be created as neg.
+    op->op = kOpNeg;
+    op->shift = 0;
+    return true;
+  } else if (IsPowerOfTwo(lit + 1)) {
     op->op = kOpRsub;
     op->shift = CTZ(lit + 1);
     return true;
@@ -612,21 +619,26 @@
 
 // Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms.
 bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) {
+  DCHECK_NE(lit, 1);           // A case of "1" should have been folded.
+  DCHECK_NE(lit, -1);          // A case of "-1" should have been folded.
   if (GetEasyMultiplyOp(lit, &ops[0])) {
     ops[1].op = kOpInvalid;
     ops[1].shift = 0;
     return true;
   }
 
-  int lit1 = lit;
-  uint32_t shift = CTZ(lit1);
+  DCHECK_NE(lit, 0);           // Should be handled above.
+  DCHECK(!IsPowerOfTwo(lit));  // Same.
+
+  int lit1 = lit;              // With the DCHECKs, it's clear we don't get "0", "1" or "-1" for
+  uint32_t shift = CTZ(lit1);  // lit1.
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpLsl;
     ops[1].shift = shift;
     return true;
   }
 
-  lit1 = lit - 1;
+  lit1 = lit - 1;              // With the DCHECKs, it's clear we don't get "0" or "1" for lit1.
   shift = CTZ(lit1);
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpAdd;
@@ -634,7 +646,7 @@
     return true;
   }
 
-  lit1 = lit + 1;
+  lit1 = lit + 1;              // With the DCHECKs, it's clear we don't get "0" here.
   shift = CTZ(lit1);
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpRsub;
@@ -652,7 +664,7 @@
 // Additional temporary register is required,
 // if it need to generate 2 instructions and src/dest overlap.
 void ArmMir2Lir::GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops) {
-  // tmp1 = ( src << shift1) + [ src | -src | 0 ]
+  // tmp1 = (( src << shift1) + [ src | -src | 0 ] ) | -src
   // dest = (tmp1 << shift2) + [ src | -src | 0 ]
 
   RegStorage r_tmp1;
@@ -674,6 +686,9 @@
     case kOpRsub:
       OpRegRegRegShift(kOpRsub, r_tmp1, r_src, r_src, EncodeShift(kArmLsl, ops[0].shift));
       break;
+    case kOpNeg:
+      OpRegReg(kOpNeg, r_tmp1, r_src);
+      break;
     default:
       DCHECK_EQ(ops[0].op, kOpInvalid);
       break;
@@ -691,6 +706,7 @@
     case kOpRsub:
       OpRegRegRegShift(kOpRsub, r_dest, r_src, r_tmp1, EncodeShift(kArmLsl, ops[1].shift));
       break;
+    // No negation allowed in second op.
     default:
       LOG(FATAL) << "Unexpected opcode passed to GenEasyMultiplyTwoOps";
       break;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index a03ff75..3a3410c 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -244,8 +244,8 @@
   DCHECK(object != nullptr);
   DCHECK_NE(image_objects_offset_begin_, 0u);
 
-  size_t previous_bin_sizes = bin_slot_previous_sizes_[bin_slot.GetBin()];
-  size_t new_offset = image_objects_offset_begin_ + previous_bin_sizes + bin_slot.GetIndex();
+  size_t bin_slot_offset = bin_slot_offsets_[bin_slot.GetBin()];
+  size_t new_offset = bin_slot_offset + bin_slot.GetIndex();
   DCHECK_ALIGNED(new_offset, kObjectAlignment);
 
   SetImageOffset(object, new_offset);
@@ -866,8 +866,10 @@
         }
         bool any_dirty = false;
         size_t count = 0;
-        const size_t method_size = ArtMethod::ObjectSize(target_ptr_size_);
-        auto iteration_range = MakeIterationRangeFromLengthPrefixedArray(array, method_size);
+        const size_t method_alignment = ArtMethod::Alignment(target_ptr_size_);
+        const size_t method_size = ArtMethod::Size(target_ptr_size_);
+        auto iteration_range =
+            MakeIterationRangeFromLengthPrefixedArray(array, method_size, method_alignment);
         for (auto& m : iteration_range) {
           any_dirty = any_dirty || WillMethodBeDirty(&m);
           ++count;
@@ -876,7 +878,9 @@
             kNativeObjectRelocationTypeArtMethodClean;
         Bin bin_type = BinTypeForNativeRelocationType(type);
         // Forward the entire array at once, but header first.
-        const size_t header_size = LengthPrefixedArray<ArtMethod>::ComputeSize(0, method_size);
+        const size_t header_size = LengthPrefixedArray<ArtMethod>::ComputeSize(0,
+                                                                               method_size,
+                                                                               method_alignment);
         auto it = native_object_relocations_.find(array);
         CHECK(it == native_object_relocations_.end()) << "Method array " << array
             << " already forwarded";
@@ -910,7 +914,7 @@
       << PrettyMethod(method);
   size_t& offset = bin_slot_sizes_[BinTypeForNativeRelocationType(type)];
   native_object_relocations_.emplace(method, NativeObjectRelocation { offset, type });
-  offset += ArtMethod::ObjectSize(target_ptr_size_);
+  offset += ArtMethod::Size(target_ptr_size_);
 }
 
 void ImageWriter::WalkFieldsCallback(mirror::Object* obj, void* arg) {
@@ -972,9 +976,10 @@
   size_t& offset = bin_slot_sizes_[BinTypeForNativeRelocationType(image_method_type)];
   native_object_relocations_.emplace(&image_method_array_,
                                      NativeObjectRelocation { offset, image_method_type });
+  size_t method_alignment = ArtMethod::Alignment(target_ptr_size_);
   const size_t array_size = LengthPrefixedArray<ArtMethod>::ComputeSize(
-      0, ArtMethod::ObjectSize(target_ptr_size_));
-  CHECK_ALIGNED(array_size, 8u);
+      0, ArtMethod::Size(target_ptr_size_), method_alignment);
+  CHECK_ALIGNED_PARAM(array_size, method_alignment);
   offset += array_size;
   for (auto* m : image_methods_) {
     CHECK(m != nullptr);
@@ -982,13 +987,21 @@
     AssignMethodOffset(m, kNativeObjectRelocationTypeArtMethodClean);
   }
 
-  // Calculate cumulative bin slot sizes.
-  size_t previous_sizes = 0u;
+  // Calculate bin slot offsets.
+  size_t bin_offset = image_objects_offset_begin_;
   for (size_t i = 0; i != kBinSize; ++i) {
-    bin_slot_previous_sizes_[i] = previous_sizes;
-    previous_sizes += bin_slot_sizes_[i];
+    bin_slot_offsets_[i] = bin_offset;
+    bin_offset += bin_slot_sizes_[i];
+    if (i == kBinArtField) {
+      static_assert(kBinArtField + 1 == kBinArtMethodClean, "Methods follow fields.");
+      static_assert(alignof(ArtField) == 4u, "ArtField alignment is 4.");
+      DCHECK_ALIGNED(bin_offset, 4u);
+      DCHECK(method_alignment == 4u || method_alignment == 8u);
+      bin_offset = RoundUp(bin_offset, method_alignment);
+    }
   }
-  DCHECK_EQ(previous_sizes, GetBinSizeSum());
+  // NOTE: There may be additional padding between the bin slots and the intern table.
+
   DCHECK_EQ(image_end_, GetBinSizeSum(kBinMirrorCount) + image_objects_offset_begin_);
 
   // Transform each object's bin slot into an offset which will be used to do the final copy.
@@ -1002,7 +1015,7 @@
   for (auto& pair : native_object_relocations_) {
     NativeObjectRelocation& relocation = pair.second;
     Bin bin_type = BinTypeForNativeRelocationType(relocation.type);
-    relocation.offset += image_objects_offset_begin_ + bin_slot_previous_sizes_[bin_type];
+    relocation.offset += bin_slot_offsets_[bin_type];
   }
 
   // Calculate how big the intern table will be after being serialized.
@@ -1029,15 +1042,15 @@
   // Add field section.
   auto* field_section = &sections[ImageHeader::kSectionArtFields];
   *field_section = ImageSection(cur_pos, bin_slot_sizes_[kBinArtField]);
-  CHECK_EQ(image_objects_offset_begin_ + bin_slot_previous_sizes_[kBinArtField],
-           field_section->Offset());
+  CHECK_EQ(bin_slot_offsets_[kBinArtField], field_section->Offset());
   cur_pos = field_section->End();
+  // Round up to the alignment the required by the method section.
+  cur_pos = RoundUp(cur_pos, ArtMethod::Alignment(target_ptr_size_));
   // Add method section.
   auto* methods_section = &sections[ImageHeader::kSectionArtMethods];
   *methods_section = ImageSection(cur_pos, bin_slot_sizes_[kBinArtMethodClean] +
                                   bin_slot_sizes_[kBinArtMethodDirty]);
-  CHECK_EQ(image_objects_offset_begin_ + bin_slot_previous_sizes_[kBinArtMethodClean],
-           methods_section->Offset());
+  CHECK_EQ(bin_slot_offsets_[kBinArtMethodClean], methods_section->Offset());
   cur_pos = methods_section->End();
   // Round up to the alignment the string table expects. See HashSet::WriteToMemory.
   cur_pos = RoundUp(cur_pos, sizeof(uint64_t));
@@ -1135,7 +1148,10 @@
       }
       case kNativeObjectRelocationTypeArtMethodArrayClean:
       case kNativeObjectRelocationTypeArtMethodArrayDirty: {
-        memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(0));
+        memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(
+            0,
+            ArtMethod::Size(target_ptr_size_),
+            ArtMethod::Alignment(target_ptr_size_)));
         break;
       }
     }
@@ -1444,7 +1460,7 @@
 }
 
 void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, ArtMethod* copy) {
-  memcpy(copy, orig, ArtMethod::ObjectSize(target_ptr_size_));
+  memcpy(copy, orig, ArtMethod::Size(target_ptr_size_));
 
   copy->SetDeclaringClass(GetImageAddress(orig->GetDeclaringClassUnchecked()));
   copy->SetDexCacheResolvedMethods(GetImageAddress(orig->GetDexCacheResolvedMethods()));
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index f4e10cc..c8aa82d 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -54,7 +54,7 @@
         quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0),
         quick_to_interpreter_bridge_offset_(0), compile_pic_(compile_pic),
         target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())),
-        bin_slot_sizes_(), bin_slot_previous_sizes_(), bin_slot_count_(),
+        bin_slot_sizes_(), bin_slot_offsets_(), bin_slot_count_(),
         intern_table_bytes_(0u), image_method_array_(ImageHeader::kImageMethodsCount),
         dirty_methods_(0u), clean_methods_(0u) {
     CHECK_NE(image_begin, 0U);
@@ -359,7 +359,7 @@
 
   // Bin slot tracking for dirty object packing
   size_t bin_slot_sizes_[kBinSize];  // Number of bytes in a bin
-  size_t bin_slot_previous_sizes_[kBinSize];  // Number of bytes in previous bins.
+  size_t bin_slot_offsets_[kBinSize];  // Number of bytes in previous bins.
   size_t bin_slot_count_[kBinSize];  // Number of objects in a bin
 
   // Cached size of the intern table for when we allocate memory.
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index b4926c2..9ea68ec 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -854,6 +854,97 @@
   __ Bind(slow_path->GetExitLabel());
 }
 
+void IntrinsicLocationsBuilderX86_64::VisitStringEquals(HInvoke* invoke) {
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                            LocationSummary::kNoCall,
+                                                            kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+
+  // Request temporary registers, RCX and RDI needed for repe_cmpsq instruction.
+  locations->AddTemp(Location::RegisterLocation(RCX));
+  locations->AddTemp(Location::RegisterLocation(RDI));
+
+  // Set output, RSI needed for repe_cmpsq instruction anyways.
+  locations->SetOut(Location::RegisterLocation(RSI), Location::kOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitStringEquals(HInvoke* invoke) {
+  X86_64Assembler* assembler = GetAssembler();
+  LocationSummary* locations = invoke->GetLocations();
+
+  CpuRegister str = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister arg = locations->InAt(1).AsRegister<CpuRegister>();
+  CpuRegister rcx = locations->GetTemp(0).AsRegister<CpuRegister>();
+  CpuRegister rdi = locations->GetTemp(1).AsRegister<CpuRegister>();
+  CpuRegister rsi = locations->Out().AsRegister<CpuRegister>();
+
+  Label end;
+  Label return_true;
+  Label return_false;
+
+  // Get offsets of count, value, and class fields within a string object.
+  const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+  const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
+  const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
+
+  // Note that the null check must have been done earlier.
+  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
+
+  // Check if input is null, return false if it is.
+  __ testl(arg, arg);
+  __ j(kEqual, &return_false);
+
+  // Instanceof check for the argument by comparing class fields.
+  // All string objects must have the same type since String cannot be subclassed.
+  // Receiver must be a string object, so its class field is equal to all strings' class fields.
+  // If the argument is a string object, its class field must be equal to receiver's class field.
+  __ movl(rcx, Address(str, class_offset));
+  __ cmpl(rcx, Address(arg, class_offset));
+  __ j(kNotEqual, &return_false);
+
+  // Reference equality check, return true if same reference.
+  __ cmpl(str, arg);
+  __ j(kEqual, &return_true);
+
+  // Load length of receiver string.
+  __ movl(rcx, Address(str, count_offset));
+  // Check if lengths are equal, return false if they're not.
+  __ cmpl(rcx, Address(arg, count_offset));
+  __ j(kNotEqual, &return_false);
+  // Return true if both strings are empty.
+  __ testl(rcx, rcx);
+  __ j(kEqual, &return_true);
+
+  // Load starting addresses of string values into RSI/RDI as required for repe_cmpsq instruction.
+  __ leal(rsi, Address(str, value_offset));
+  __ leal(rdi, Address(arg, value_offset));
+
+  // Divide string length by 4 and adjust for lengths not divisible by 4.
+  __ addl(rcx, Immediate(3));
+  __ shrl(rcx, Immediate(2));
+
+  // Assertions that must hold in order to compare strings 4 characters at a time.
+  DCHECK_ALIGNED(value_offset, 8);
+  static_assert(IsAligned<8>(kObjectAlignment), "String is not zero padded");
+
+  // Loop to compare strings four characters at a time starting at the beginning of the string.
+  __ repe_cmpsq();
+  // If strings are not equal, zero flag will be cleared.
+  __ j(kNotEqual, &return_false);
+
+  // Return true and exit the function.
+  // If loop does not result in returning false, we return true.
+  __ Bind(&return_true);
+  __ movl(rsi, Immediate(1));
+  __ jmp(&end);
+
+  // Return false and exit the function.
+  __ Bind(&return_false);
+  __ xorl(rsi, rsi);
+  __ Bind(&end);
+}
+
 static void CreateStringIndexOfLocations(HInvoke* invoke,
                                          ArenaAllocator* allocator,
                                          bool start_at_zero) {
@@ -1607,7 +1698,6 @@
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
 UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
-UNIMPLEMENTED_INTRINSIC(StringEquals)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 550ed70..703b6f7 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -19,6 +19,7 @@
 
 #include "base/arena_containers.h"
 #include "base/bit_vector-inl.h"
+#include "base/hash_map.h"
 #include "base/value_object.h"
 #include "memory_region.h"
 #include "nodes.h"
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 914bd56..9b3d792 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -158,6 +158,20 @@
   EmitUint8(0xC8 + dst);
 }
 
+void X86Assembler::bsrl(Register dst, Register src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitRegisterOperand(dst, src);
+}
+
+void X86Assembler::bsrl(Register dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitOperand(dst, src);
+}
+
 void X86Assembler::movzxb(Register dst, ByteRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x0F);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 850e1da..a9227f3 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -234,6 +234,8 @@
   void movntl(const Address& dst, Register src);
 
   void bswapl(Register dst);
+  void bsrl(Register dst, Register src);
+  void bsrl(Register dst, const Address& src);
 
   void movzxb(Register dst, ByteRegister src);
   void movzxb(Register dst, const Address& src);
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index c257b78..731b5f4 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -230,4 +230,17 @@
   DriverStr(expected, "rep_movsw");
 }
 
+TEST_F(AssemblerX86Test, Bsrl) {
+  DriverStr(RepeatRR(&x86::X86Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl");
+}
+
+TEST_F(AssemblerX86Test, BsrlAddress) {
+  GetAssembler()->bsrl(x86::Register(x86::EDI), x86::Address(
+      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
+  const char* expected =
+    "bsrl 0xc(%EDI,%EBX,4), %EDI\n";
+
+  DriverStr(expected, "bsrl_address");
+}
+
 }  // namespace art
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 38a9e72..dc61c99 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2092,6 +2092,37 @@
   EmitUint8(0xC8 + dst.LowBits());
 }
 
+void X86_64Assembler::bsrl(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+void X86_64Assembler::bsrl(CpuRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::bsrq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+void X86_64Assembler::bsrq(CpuRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitOperand(dst.LowBits(), src);
+}
 
 void X86_64Assembler::repne_scasw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 6780785..da42213 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -606,6 +606,11 @@
   void bswapl(CpuRegister dst);
   void bswapq(CpuRegister dst);
 
+  void bsrl(CpuRegister dst, CpuRegister src);
+  void bsrl(CpuRegister dst, const Address& src);
+  void bsrq(CpuRegister dst, CpuRegister src);
+  void bsrq(CpuRegister dst, const Address& src);
+
   void repne_scasw();
   void repe_cmpsw();
   void repe_cmpsl();
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 7e879e9..8673f03 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1141,6 +1141,44 @@
   DriverStr(RepeatR(&x86_64::X86_64Assembler::bswapq, "bswap %{reg}"), "bswapq");
 }
 
+TEST_F(AssemblerX86_64Test, Bsrl) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl");
+}
+
+TEST_F(AssemblerX86_64Test, BsrlAddress) {
+  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  const char* expected =
+    "bsrl 0xc(%RDI,%RBX,4), %R10d\n"
+    "bsrl 0xc(%R10,%RBX,4), %edi\n"
+    "bsrl 0xc(%RDI,%R9,4), %edi\n";
+
+  DriverStr(expected, "bsrl_address");
+}
+
+TEST_F(AssemblerX86_64Test, Bsrq) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::bsrq, "bsrq %{reg2}, %{reg1}"), "bsrq");
+}
+
+TEST_F(AssemblerX86_64Test, BsrqAddress) {
+  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::R10), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  const char* expected =
+    "bsrq 0xc(%RDI,%RBX,4), %R10\n"
+    "bsrq 0xc(%R10,%RBX,4), %RDI\n"
+    "bsrq 0xc(%RDI,%R9,4), %RDI\n";
+
+  DriverStr(expected, "bsrq_address");
+}
+
 std::string setcc_test_fn(AssemblerX86_64Test::Base* assembler_test,
                           x86_64::X86_64Assembler* assembler) {
   // From Condition
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 976c002..5653612 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -539,26 +539,11 @@
     }
   }
 
-  // Parse the arguments from the command line. In case of an unrecognized option or impossible
-  // values/combinations, a usage error will be displayed and exit() is called. Thus, if the method
-  // returns, arguments have been successfully parsed.
-  void ParseArgs(int argc, char** argv) {
-    original_argc = argc;
-    original_argv = argv;
-
-    InitLogging(argv);
-
-    // Skip over argv[0].
-    argv++;
-    argc--;
-
-    if (argc == 0) {
-      Usage("No arguments specified");
-    }
-
+  struct ParserOptions {
     std::string oat_symbols;
     std::string boot_image_filename;
     const char* compiler_filter_string = nullptr;
+    CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
     bool compile_pic = false;
     int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
     int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
@@ -580,277 +565,192 @@
     bool abort_on_hard_verifier_error = false;
     bool requested_specific_compiler = false;
 
+    bool implicit_null_checks = false;
+    bool implicit_so_checks = false;
+    bool implicit_suspend_checks = false;
+
     PassManagerOptions pass_manager_options;
 
     std::string error_msg;
+  };
 
-    for (int i = 0; i < argc; i++) {
-      const StringPiece option(argv[i]);
-      const bool log_options = false;
-      if (log_options) {
-        LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
-      }
-      if (option.starts_with("--dex-file=")) {
-        dex_filenames_.push_back(option.substr(strlen("--dex-file=")).data());
-      } else if (option.starts_with("--dex-location=")) {
-        dex_locations_.push_back(option.substr(strlen("--dex-location=")).data());
-      } else if (option.starts_with("--zip-fd=")) {
-        const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data();
-        if (!ParseInt(zip_fd_str, &zip_fd_)) {
-          Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
-        }
-        if (zip_fd_ < 0) {
-          Usage("--zip-fd passed a negative value %d", zip_fd_);
-        }
-      } else if (option.starts_with("--zip-location=")) {
-        zip_location_ = option.substr(strlen("--zip-location=")).data();
-      } else if (option.starts_with("--oat-file=")) {
-        oat_filename_ = option.substr(strlen("--oat-file=")).data();
-      } else if (option.starts_with("--oat-symbols=")) {
-        oat_symbols = option.substr(strlen("--oat-symbols=")).data();
-      } else if (option.starts_with("--oat-fd=")) {
-        const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
-        if (!ParseInt(oat_fd_str, &oat_fd_)) {
-          Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
-        }
-        if (oat_fd_ < 0) {
-          Usage("--oat-fd passed a negative value %d", oat_fd_);
-        }
-      } else if (option == "--watch-dog") {
-        watch_dog_enabled = true;
-      } else if (option == "--no-watch-dog") {
-        watch_dog_enabled = false;
-      } else if (option.starts_with("-j")) {
-        const char* thread_count_str = option.substr(strlen("-j")).data();
-        if (!ParseUint(thread_count_str, &thread_count_)) {
-          Usage("Failed to parse -j argument '%s' as an integer", thread_count_str);
-        }
-      } else if (option.starts_with("--oat-location=")) {
-        oat_location_ = option.substr(strlen("--oat-location=")).data();
-      } else if (option.starts_with("--image=")) {
-        image_filename_ = option.substr(strlen("--image=")).data();
-      } else if (option.starts_with("--image-classes=")) {
-        image_classes_filename_ = option.substr(strlen("--image-classes=")).data();
-      } else if (option.starts_with("--image-classes-zip=")) {
-        image_classes_zip_filename_ = option.substr(strlen("--image-classes-zip=")).data();
-      } else if (option.starts_with("--compiled-classes=")) {
-        compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data();
-      } else if (option.starts_with("--compiled-classes-zip=")) {
-        compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data();
-      } else if (option.starts_with("--compiled-methods=")) {
-        compiled_methods_filename_ = option.substr(strlen("--compiled-methods=")).data();
-      } else if (option.starts_with("--compiled-methods-zip=")) {
-        compiled_methods_zip_filename_ = option.substr(strlen("--compiled-methods-zip=")).data();
-      } else if (option.starts_with("--base=")) {
-        const char* image_base_str = option.substr(strlen("--base=")).data();
-        char* end;
-        image_base_ = strtoul(image_base_str, &end, 16);
-        if (end == image_base_str || *end != '\0') {
-          Usage("Failed to parse hexadecimal value for option %s", option.data());
-        }
-      } else if (option.starts_with("--boot-image=")) {
-        boot_image_filename = option.substr(strlen("--boot-image=")).data();
-      } else if (option.starts_with("--android-root=")) {
-        android_root_ = option.substr(strlen("--android-root=")).data();
-      } else if (option.starts_with("--instruction-set=")) {
-        StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
-        // StringPiece is not necessarily zero-terminated, so need to make a copy and ensure it.
-        std::unique_ptr<char[]> buf(new char[instruction_set_str.length() + 1]);
-        strncpy(buf.get(), instruction_set_str.data(), instruction_set_str.length());
-        buf.get()[instruction_set_str.length()] = 0;
-        instruction_set_ = GetInstructionSetFromString(buf.get());
-        // arm actually means thumb2.
-        if (instruction_set_ == InstructionSet::kArm) {
-          instruction_set_ = InstructionSet::kThumb2;
-        }
-      } else if (option.starts_with("--instruction-set-variant=")) {
-        StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
-        instruction_set_features_.reset(
-            InstructionSetFeatures::FromVariant(instruction_set_, str.as_string(), &error_msg));
-        if (instruction_set_features_.get() == nullptr) {
-          Usage("%s", error_msg.c_str());
-        }
-      } else if (option.starts_with("--instruction-set-features=")) {
-        StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
-        if (instruction_set_features_.get() == nullptr) {
-          instruction_set_features_.reset(
-              InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
-          if (instruction_set_features_.get() == nullptr) {
-            Usage("Problem initializing default instruction set features variant: %s",
-                  error_msg.c_str());
-          }
-        }
-        instruction_set_features_.reset(
-            instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
-        if (instruction_set_features_.get() == nullptr) {
-          Usage("Error parsing '%s': %s", option.data(), error_msg.c_str());
-        }
-      } else if (option.starts_with("--compiler-backend=")) {
-        requested_specific_compiler = true;
-        StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
-        if (backend_str == "Quick") {
-          compiler_kind_ = Compiler::kQuick;
-        } else if (backend_str == "Optimizing") {
-          compiler_kind_ = Compiler::kOptimizing;
-        } else {
-          Usage("Unknown compiler backend: %s", backend_str.data());
-        }
-      } else if (option.starts_with("--compiler-filter=")) {
-        compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
-      } else if (option == "--compile-pic") {
-        compile_pic = true;
-      } else if (option.starts_with("--huge-method-max=")) {
-        const char* threshold = option.substr(strlen("--huge-method-max=")).data();
-        if (!ParseInt(threshold, &huge_method_threshold)) {
-          Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
-        }
-        if (huge_method_threshold < 0) {
-          Usage("--huge-method-max passed a negative value %s", huge_method_threshold);
-        }
-      } else if (option.starts_with("--large-method-max=")) {
-        const char* threshold = option.substr(strlen("--large-method-max=")).data();
-        if (!ParseInt(threshold, &large_method_threshold)) {
-          Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
-        }
-        if (large_method_threshold < 0) {
-          Usage("--large-method-max passed a negative value %s", large_method_threshold);
-        }
-      } else if (option.starts_with("--small-method-max=")) {
-        const char* threshold = option.substr(strlen("--small-method-max=")).data();
-        if (!ParseInt(threshold, &small_method_threshold)) {
-          Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
-        }
-        if (small_method_threshold < 0) {
-          Usage("--small-method-max passed a negative value %s", small_method_threshold);
-        }
-      } else if (option.starts_with("--tiny-method-max=")) {
-        const char* threshold = option.substr(strlen("--tiny-method-max=")).data();
-        if (!ParseInt(threshold, &tiny_method_threshold)) {
-          Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
-        }
-        if (tiny_method_threshold < 0) {
-          Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold);
-        }
-      } else if (option.starts_with("--num-dex-methods=")) {
-        const char* threshold = option.substr(strlen("--num-dex-methods=")).data();
-        if (!ParseInt(threshold, &num_dex_methods_threshold)) {
-          Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
-        }
-        if (num_dex_methods_threshold < 0) {
-          Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold);
-        }
-      } else if (option.starts_with("--inline-depth-limit=")) {
-        const char* limit = option.substr(strlen("--inline-depth-limit=")).data();
-        if (!ParseInt(limit, &inline_depth_limit)) {
-          Usage("Failed to parse --inline-depth-limit '%s' as an integer", limit);
-        }
-        if (inline_depth_limit < 0) {
-          Usage("--inline-depth-limit passed a negative value %s", inline_depth_limit);
-        }
-      } else if (option.starts_with("--inline-max-code-units=")) {
-        const char* code_units = option.substr(strlen("--inline-max-code-units=")).data();
-        if (!ParseInt(code_units, &inline_max_code_units)) {
-          Usage("Failed to parse --inline-max-code-units '%s' as an integer", code_units);
-        }
-        if (inline_max_code_units < 0) {
-          Usage("--inline-max-code-units passed a negative value %s", inline_max_code_units);
-        }
-      } else if (option == "--host") {
-        is_host_ = true;
-      } else if (option == "--runtime-arg") {
-        if (++i >= argc) {
-          Usage("Missing required argument for --runtime-arg");
-        }
-        if (log_options) {
-          LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
-        }
-        runtime_args_.push_back(argv[i]);
-      } else if (option == "--dump-timing") {
-        dump_timing_ = true;
-      } else if (option == "--dump-passes") {
-        dump_passes_ = true;
-      } else if (option.starts_with("--dump-cfg=")) {
-        dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data();
-      } else if (option == "--dump-stats") {
-        dump_stats_ = true;
-      } else if (option == "--generate-debug-info" || option == "-g") {
-        generate_debug_info = true;
-      } else if (option == "--no-generate-debug-info") {
-        generate_debug_info = false;
-      } else if (option == "--debuggable") {
-        debuggable = true;
-        generate_debug_info = true;
-      } else if (option.starts_with("--profile-file=")) {
-        profile_file_ = option.substr(strlen("--profile-file=")).data();
-        VLOG(compiler) << "dex2oat: profile file is " << profile_file_;
-      } else if (option == "--no-profile-file") {
-        // No profile
-      } else if (option.starts_with("--top-k-profile-threshold=")) {
-        ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold);
-      } else if (option == "--print-pass-names") {
-        pass_manager_options.SetPrintPassNames(true);
-      } else if (option.starts_with("--disable-passes=")) {
-        const std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
-        pass_manager_options.SetDisablePassList(disable_passes);
-      } else if (option.starts_with("--print-passes=")) {
-        const std::string print_passes = option.substr(strlen("--print-passes=")).data();
-        pass_manager_options.SetPrintPassList(print_passes);
-      } else if (option == "--print-all-passes") {
-        pass_manager_options.SetPrintAllPasses();
-      } else if (option.starts_with("--dump-cfg-passes=")) {
-        const std::string dump_passes_string = option.substr(strlen("--dump-cfg-passes=")).data();
-        pass_manager_options.SetDumpPassList(dump_passes_string);
-      } else if (option == "--print-pass-options") {
-        pass_manager_options.SetPrintPassOptions(true);
-      } else if (option.starts_with("--pass-options=")) {
-        const std::string options = option.substr(strlen("--pass-options=")).data();
-        pass_manager_options.SetOverriddenPassOptions(options);
-      } else if (option == "--include-patch-information") {
-        include_patch_information = true;
-      } else if (option == "--no-include-patch-information") {
-        include_patch_information = false;
-      } else if (option.starts_with("--verbose-methods=")) {
-        // TODO: rather than switch off compiler logging, make all VLOG(compiler) messages
-        //       conditional on having verbost methods.
-        gLogVerbosity.compiler = false;
-        Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods_);
-      } else if (option.starts_with("--dump-init-failures=")) {
-        std::string file_name = option.substr(strlen("--dump-init-failures=")).data();
-        init_failure_output_.reset(new std::ofstream(file_name));
-        if (init_failure_output_.get() == nullptr) {
-          LOG(ERROR) << "Failed to allocate ofstream";
-        } else if (init_failure_output_->fail()) {
-          LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization "
-                     << "failures.";
-          init_failure_output_.reset();
-        }
-      } else if (option.starts_with("--swap-file=")) {
-        swap_file_name_ = option.substr(strlen("--swap-file=")).data();
-      } else if (option.starts_with("--swap-fd=")) {
-        const char* swap_fd_str = option.substr(strlen("--swap-fd=")).data();
-        if (!ParseInt(swap_fd_str, &swap_fd_)) {
-          Usage("Failed to parse --swap-fd argument '%s' as an integer", swap_fd_str);
-        }
-        if (swap_fd_ < 0) {
-          Usage("--swap-fd passed a negative value %d", swap_fd_);
-        }
-      } else if (option == "--abort-on-hard-verifier-error") {
-        abort_on_hard_verifier_error = true;
-      } else {
-        Usage("Unknown argument %s", option.data());
+  template <typename T>
+  static void ParseUintOption(const StringPiece& option,
+                              const std::string& option_name,
+                              T* out,
+                              bool is_long_option = true) {
+    std::string option_prefix = option_name + (is_long_option ? "=" : "");
+    DCHECK(option.starts_with(option_prefix));
+    const char* value_string = option.substr(option_prefix.size()).data();
+    int64_t parsed_integer_value;
+    if (!ParseInt(value_string, &parsed_integer_value)) {
+      Usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
+    }
+    if (parsed_integer_value < 0) {
+      Usage("%s passed a negative value %d", option_name.c_str(), parsed_integer_value);
+    }
+    *out = dchecked_integral_cast<T>(parsed_integer_value);
+  }
+
+  void ParseZipFd(const StringPiece& option) {
+    ParseUintOption(option, "--zip-fd", &zip_fd_);
+  }
+
+  void ParseOatFd(const StringPiece& option) {
+    ParseUintOption(option, "--oat-fd", &oat_fd_);
+  }
+
+  void ParseJ(const StringPiece& option) {
+    ParseUintOption(option, "-j", &thread_count_, /* is_long_option */ false);
+  }
+
+  void ParseBase(const StringPiece& option) {
+    DCHECK(option.starts_with("--base="));
+    const char* image_base_str = option.substr(strlen("--base=")).data();
+    char* end;
+    image_base_ = strtoul(image_base_str, &end, 16);
+    if (end == image_base_str || *end != '\0') {
+      Usage("Failed to parse hexadecimal value for option %s", option.data());
+    }
+  }
+
+  void ParseInstructionSet(const StringPiece& option) {
+    DCHECK(option.starts_with("--instruction-set="));
+    StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
+    // StringPiece is not necessarily zero-terminated, so need to make a copy and ensure it.
+    std::unique_ptr<char[]> buf(new char[instruction_set_str.length() + 1]);
+    strncpy(buf.get(), instruction_set_str.data(), instruction_set_str.length());
+    buf.get()[instruction_set_str.length()] = 0;
+    instruction_set_ = GetInstructionSetFromString(buf.get());
+    // arm actually means thumb2.
+    if (instruction_set_ == InstructionSet::kArm) {
+      instruction_set_ = InstructionSet::kThumb2;
+    }
+  }
+
+  void ParseInstructionSetVariant(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--instruction-set-variant="));
+    StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
+    instruction_set_features_.reset(
+        InstructionSetFeatures::FromVariant(
+            instruction_set_, str.as_string(), &parser_options->error_msg));
+    if (instruction_set_features_.get() == nullptr) {
+      Usage("%s", parser_options->error_msg.c_str());
+    }
+  }
+
+  void ParseInstructionSetFeatures(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--instruction-set-features="));
+    StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
+    if (instruction_set_features_.get() == nullptr) {
+      instruction_set_features_.reset(
+          InstructionSetFeatures::FromVariant(
+              instruction_set_, "default", &parser_options->error_msg));
+      if (instruction_set_features_.get() == nullptr) {
+        Usage("Problem initializing default instruction set features variant: %s",
+              parser_options->error_msg.c_str());
       }
     }
+    instruction_set_features_.reset(
+        instruction_set_features_->AddFeaturesFromString(str.as_string(),
+                                                         &parser_options->error_msg));
+    if (instruction_set_features_.get() == nullptr) {
+      Usage("Error parsing '%s': %s", option.data(), parser_options->error_msg.c_str());
+    }
+  }
 
+  void ParseCompilerBackend(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--compiler-backend="));
+    parser_options->requested_specific_compiler = true;
+    StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
+    if (backend_str == "Quick") {
+      compiler_kind_ = Compiler::kQuick;
+    } else if (backend_str == "Optimizing") {
+      compiler_kind_ = Compiler::kOptimizing;
+    } else {
+      Usage("Unknown compiler backend: %s", backend_str.data());
+    }
+  }
+
+  void ParseHugeMethodMax(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--huge-method-max", &parser_options->huge_method_threshold);
+  }
+
+  void ParseLargeMethodMax(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--large-method-max", &parser_options->large_method_threshold);
+  }
+
+  void ParseSmallMethodMax(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--small-method-max", &parser_options->small_method_threshold);
+  }
+
+  void ParseTinyMethodMax(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--tiny-method-max", &parser_options->tiny_method_threshold);
+  }
+
+  void ParseNumDexMethods(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--num-dex-methods", &parser_options->num_dex_methods_threshold);
+  }
+
+  void ParseInlineDepthLimit(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--inline-depth-limit", &parser_options->inline_depth_limit);
+  }
+
+  void ParseInlineMaxCodeUnits(const StringPiece& option, ParserOptions* parser_options) {
+    ParseUintOption(option, "--inline-max-code-units=", &parser_options->inline_max_code_units);
+  }
+
+  void ParseDisablePasses(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--disable-passes="));
+    const std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
+    parser_options->pass_manager_options.SetDisablePassList(disable_passes);
+  }
+
+  void ParsePrintPasses(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--print-passes="));
+    const std::string print_passes = option.substr(strlen("--print-passes=")).data();
+    parser_options->pass_manager_options.SetPrintPassList(print_passes);
+  }
+
+  void ParseDumpCfgPasses(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--dump-cfg-passes="));
+    const std::string dump_passes_string = option.substr(strlen("--dump-cfg-passes=")).data();
+    parser_options->pass_manager_options.SetDumpPassList(dump_passes_string);
+  }
+
+  void ParsePassOptions(const StringPiece& option, ParserOptions* parser_options) {
+    DCHECK(option.starts_with("--pass-options="));
+    const std::string pass_options = option.substr(strlen("--pass-options=")).data();
+    parser_options->pass_manager_options.SetOverriddenPassOptions(pass_options);
+  }
+
+  void ParseDumpInitFailures(const StringPiece& option) {
+    DCHECK(option.starts_with("--dump-init-failures="));
+    std::string file_name = option.substr(strlen("--dump-init-failures=")).data();
+    init_failure_output_.reset(new std::ofstream(file_name));
+    if (init_failure_output_.get() == nullptr) {
+      LOG(ERROR) << "Failed to allocate ofstream";
+    } else if (init_failure_output_->fail()) {
+      LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization "
+                 << "failures.";
+      init_failure_output_.reset();
+    }
+  }
+
+  void ParseSwapFd(const StringPiece& option) {
+    ParseUintOption(option, "--swap-fd", &swap_fd_);
+  }
+
+  void ProcessOptions(ParserOptions* parser_options) {
     image_ = (!image_filename_.empty());
-    if (!requested_specific_compiler && !kUseOptimizingCompiler) {
+    if (!parser_options->requested_specific_compiler && !kUseOptimizingCompiler) {
       // If no specific compiler is requested, the current behavior is
       // to compile the boot image with Quick, and the rest with Optimizing.
       compiler_kind_ = image_ ? Compiler::kQuick : Compiler::kOptimizing;
     }
-
     if (compiler_kind_ == Compiler::kOptimizing) {
       // Optimizing only supports PIC mode.
-      compile_pic = true;
+      parser_options->compile_pic = true;
     }
 
     if (oat_filename_.empty() && oat_fd_ == -1) {
@@ -861,11 +761,11 @@
       Usage("--oat-file should not be used with --oat-fd");
     }
 
-    if (!oat_symbols.empty() && oat_fd_ != -1) {
+    if (!parser_options->oat_symbols.empty() && oat_fd_ != -1) {
       Usage("--oat-symbols should not be used with --oat-fd");
     }
 
-    if (!oat_symbols.empty() && is_host_) {
+    if (!parser_options->oat_symbols.empty() && is_host_) {
       Usage("--oat-symbols should not be used with --host");
     }
 
@@ -881,13 +781,13 @@
       android_root_ += android_root_env_var;
     }
 
-    if (!image_ && boot_image_filename.empty()) {
-      boot_image_filename += android_root_;
-      boot_image_filename += "/framework/boot.art";
+    if (!image_ && parser_options->boot_image_filename.empty()) {
+      parser_options->boot_image_filename += android_root_;
+      parser_options->boot_image_filename += "/framework/boot.art";
     }
-    if (!boot_image_filename.empty()) {
+    if (!parser_options->boot_image_filename.empty()) {
       boot_image_option_ += "-Ximage:";
-      boot_image_option_ += boot_image_filename;
+      boot_image_option_ += parser_options->boot_image_filename;
     }
 
     if (image_classes_filename_ != nullptr && !image_) {
@@ -945,8 +845,8 @@
     }
 
     oat_stripped_ = oat_filename_;
-    if (!oat_symbols.empty()) {
-      oat_unstripped_ = oat_symbols;
+    if (!parser_options->oat_symbols.empty()) {
+      oat_unstripped_ = parser_options->oat_symbols;
     } else {
       oat_unstripped_ = oat_filename_;
     }
@@ -955,10 +855,11 @@
     // instruction set.
     if (instruction_set_features_.get() == nullptr) {
       instruction_set_features_.reset(
-          InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+          InstructionSetFeatures::FromVariant(
+              instruction_set_, "default", &parser_options->error_msg));
       if (instruction_set_features_.get() == nullptr) {
         Usage("Problem initializing default instruction set features variant: %s",
-              error_msg.c_str());
+              parser_options->error_msg.c_str());
       }
     }
 
@@ -973,52 +874,50 @@
       }
     }
 
-    if (compiler_filter_string == nullptr) {
-      compiler_filter_string = "speed";
+    if (parser_options->compiler_filter_string == nullptr) {
+      parser_options->compiler_filter_string = "speed";
     }
 
-    CHECK(compiler_filter_string != nullptr);
-    CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
-    if (strcmp(compiler_filter_string, "verify-none") == 0) {
-      compiler_filter = CompilerOptions::kVerifyNone;
-    } else if (strcmp(compiler_filter_string, "interpret-only") == 0) {
-      compiler_filter = CompilerOptions::kInterpretOnly;
-    } else if (strcmp(compiler_filter_string, "verify-at-runtime") == 0) {
-      compiler_filter = CompilerOptions::kVerifyAtRuntime;
-    } else if (strcmp(compiler_filter_string, "space") == 0) {
-      compiler_filter = CompilerOptions::kSpace;
-    } else if (strcmp(compiler_filter_string, "balanced") == 0) {
-      compiler_filter = CompilerOptions::kBalanced;
-    } else if (strcmp(compiler_filter_string, "speed") == 0) {
-      compiler_filter = CompilerOptions::kSpeed;
-    } else if (strcmp(compiler_filter_string, "everything") == 0) {
-      compiler_filter = CompilerOptions::kEverything;
-    } else if (strcmp(compiler_filter_string, "time") == 0) {
-      compiler_filter = CompilerOptions::kTime;
+    CHECK(parser_options->compiler_filter_string != nullptr);
+    if (strcmp(parser_options->compiler_filter_string, "verify-none") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kVerifyNone;
+    } else if (strcmp(parser_options->compiler_filter_string, "interpret-only") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kInterpretOnly;
+    } else if (strcmp(parser_options->compiler_filter_string, "verify-at-runtime") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kVerifyAtRuntime;
+    } else if (strcmp(parser_options->compiler_filter_string, "space") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kSpace;
+    } else if (strcmp(parser_options->compiler_filter_string, "balanced") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kBalanced;
+    } else if (strcmp(parser_options->compiler_filter_string, "speed") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kSpeed;
+    } else if (strcmp(parser_options->compiler_filter_string, "everything") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kEverything;
+    } else if (strcmp(parser_options->compiler_filter_string, "time") == 0) {
+      parser_options->compiler_filter = CompilerOptions::kTime;
     } else {
-      Usage("Unknown --compiler-filter value %s", compiler_filter_string);
+      Usage("Unknown --compiler-filter value %s", parser_options->compiler_filter_string);
     }
 
     // It they are not set, use default values for inlining settings.
     // TODO: We should rethink the compiler filter. We mostly save
     // time here, which is orthogonal to space.
-    if (inline_depth_limit == kUnsetInlineDepthLimit) {
-      inline_depth_limit = (compiler_filter == CompilerOptions::kSpace)
+    if (parser_options->inline_depth_limit == ParserOptions::kUnsetInlineDepthLimit) {
+      parser_options->inline_depth_limit =
+          (parser_options->compiler_filter == CompilerOptions::kSpace)
           // Implementation of the space filter: limit inlining depth.
           ? CompilerOptions::kSpaceFilterInlineDepthLimit
           : CompilerOptions::kDefaultInlineDepthLimit;
     }
-    if (inline_max_code_units == kUnsetInlineMaxCodeUnits) {
-      inline_max_code_units = (compiler_filter == CompilerOptions::kSpace)
+    if (parser_options->inline_max_code_units == ParserOptions::kUnsetInlineMaxCodeUnits) {
+      parser_options->inline_max_code_units =
+          (parser_options->compiler_filter == CompilerOptions::kSpace)
           // Implementation of the space filter: limit inlining max code units.
           ? CompilerOptions::kSpaceFilterInlineMaxCodeUnits
           : CompilerOptions::kDefaultInlineMaxCodeUnits;
     }
 
     // Checks are all explicit until we know the architecture.
-    bool implicit_null_checks = false;
-    bool implicit_so_checks = false;
-    bool implicit_suspend_checks = false;
     // Set the compilation target's implicit checks options.
     switch (instruction_set_) {
       case kArm:
@@ -1028,8 +927,8 @@
       case kX86_64:
       case kMips:
       case kMips64:
-        implicit_null_checks = true;
-        implicit_so_checks = true;
+        parser_options->implicit_null_checks = true;
+        parser_options->implicit_so_checks = true;
         break;
 
       default:
@@ -1037,55 +936,224 @@
         break;
     }
 
-    compiler_options_.reset(new CompilerOptions(compiler_filter,
-                                                huge_method_threshold,
-                                                large_method_threshold,
-                                                small_method_threshold,
-                                                tiny_method_threshold,
-                                                num_dex_methods_threshold,
-                                                inline_depth_limit,
-                                                inline_max_code_units,
-                                                include_patch_information,
-                                                top_k_profile_threshold,
-                                                debuggable,
-                                                generate_debug_info,
-                                                implicit_null_checks,
-                                                implicit_so_checks,
-                                                implicit_suspend_checks,
-                                                compile_pic,
+    compiler_options_.reset(new CompilerOptions(parser_options->compiler_filter,
+                                                parser_options->huge_method_threshold,
+                                                parser_options->large_method_threshold,
+                                                parser_options->small_method_threshold,
+                                                parser_options->tiny_method_threshold,
+                                                parser_options->num_dex_methods_threshold,
+                                                parser_options->inline_depth_limit,
+                                                parser_options->inline_max_code_units,
+                                                parser_options->include_patch_information,
+                                                parser_options->top_k_profile_threshold,
+                                                parser_options->debuggable,
+                                                parser_options->generate_debug_info,
+                                                parser_options->implicit_null_checks,
+                                                parser_options->implicit_so_checks,
+                                                parser_options->implicit_suspend_checks,
+                                                parser_options->compile_pic,
                                                 verbose_methods_.empty() ?
                                                     nullptr :
                                                     &verbose_methods_,
-                                                new PassManagerOptions(pass_manager_options),
+                                                new PassManagerOptions(
+                                                    parser_options->pass_manager_options),
                                                 init_failure_output_.get(),
-                                                abort_on_hard_verifier_error));
+                                                parser_options->abort_on_hard_verifier_error));
 
     // Done with usage checks, enable watchdog if requested
-    if (watch_dog_enabled) {
+    if (parser_options->watch_dog_enabled) {
       watchdog_.reset(new WatchDog(true));
     }
 
     // Fill some values into the key-value store for the oat header.
     key_value_store_.reset(new SafeMap<std::string, std::string>());
+  }
+
+  void InsertCompileOptions(int argc, char** argv, ParserOptions* parser_options) {
+    std::ostringstream oss;
+    for (int i = 0; i < argc; ++i) {
+      if (i > 0) {
+        oss << ' ';
+      }
+      oss << argv[i];
+    }
+    key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
+    oss.str("");  // Reset.
+    oss << kRuntimeISA;
+    key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
+    key_value_store_->Put(
+        OatHeader::kPicKey,
+        parser_options->compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+    key_value_store_->Put(
+        OatHeader::kDebuggableKey,
+        parser_options->debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+  }
+
+  // Parse the arguments from the command line. In case of an unrecognized option or impossible
+  // values/combinations, a usage error will be displayed and exit() is called. Thus, if the method
+  // returns, arguments have been successfully parsed.
+  void ParseArgs(int argc, char** argv) {
+    original_argc = argc;
+    original_argv = argv;
+
+    InitLogging(argv);
+
+    // Skip over argv[0].
+    argv++;
+    argc--;
+
+    if (argc == 0) {
+      Usage("No arguments specified");
+    }
+
+    std::unique_ptr<ParserOptions> parser_options(new ParserOptions());
+
+    for (int i = 0; i < argc; i++) {
+      const StringPiece option(argv[i]);
+      const bool log_options = false;
+      if (log_options) {
+        LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+      }
+      if (option.starts_with("--dex-file=")) {
+        dex_filenames_.push_back(option.substr(strlen("--dex-file=")).data());
+      } else if (option.starts_with("--dex-location=")) {
+        dex_locations_.push_back(option.substr(strlen("--dex-location=")).data());
+      } else if (option.starts_with("--zip-fd=")) {
+        ParseZipFd(option);
+      } else if (option.starts_with("--zip-location=")) {
+        zip_location_ = option.substr(strlen("--zip-location=")).data();
+      } else if (option.starts_with("--oat-file=")) {
+        oat_filename_ = option.substr(strlen("--oat-file=")).data();
+      } else if (option.starts_with("--oat-symbols=")) {
+        parser_options->oat_symbols = option.substr(strlen("--oat-symbols=")).data();
+      } else if (option.starts_with("--oat-fd=")) {
+        ParseOatFd(option);
+      } else if (option == "--watch-dog") {
+        parser_options->watch_dog_enabled = true;
+      } else if (option == "--no-watch-dog") {
+        parser_options->watch_dog_enabled = false;
+      } else if (option.starts_with("-j")) {
+        ParseJ(option);
+      } else if (option.starts_with("--oat-location=")) {
+        oat_location_ = option.substr(strlen("--oat-location=")).data();
+      } else if (option.starts_with("--image=")) {
+        image_filename_ = option.substr(strlen("--image=")).data();
+      } else if (option.starts_with("--image-classes=")) {
+        image_classes_filename_ = option.substr(strlen("--image-classes=")).data();
+      } else if (option.starts_with("--image-classes-zip=")) {
+        image_classes_zip_filename_ = option.substr(strlen("--image-classes-zip=")).data();
+      } else if (option.starts_with("--compiled-classes=")) {
+        compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data();
+      } else if (option.starts_with("--compiled-classes-zip=")) {
+        compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data();
+      } else if (option.starts_with("--compiled-methods=")) {
+        compiled_methods_filename_ = option.substr(strlen("--compiled-methods=")).data();
+      } else if (option.starts_with("--compiled-methods-zip=")) {
+        compiled_methods_zip_filename_ = option.substr(strlen("--compiled-methods-zip=")).data();
+      } else if (option.starts_with("--base=")) {
+        ParseBase(option);
+      } else if (option.starts_with("--boot-image=")) {
+        parser_options->boot_image_filename = option.substr(strlen("--boot-image=")).data();
+      } else if (option.starts_with("--android-root=")) {
+        android_root_ = option.substr(strlen("--android-root=")).data();
+      } else if (option.starts_with("--instruction-set=")) {
+        ParseInstructionSet(option);
+      } else if (option.starts_with("--instruction-set-variant=")) {
+        ParseInstructionSetVariant(option, parser_options.get());
+      } else if (option.starts_with("--instruction-set-features=")) {
+        ParseInstructionSetFeatures(option, parser_options.get());
+      } else if (option.starts_with("--compiler-backend=")) {
+        ParseCompilerBackend(option, parser_options.get());
+      } else if (option.starts_with("--compiler-filter=")) {
+        parser_options->compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
+      } else if (option == "--compile-pic") {
+        parser_options->compile_pic = true;
+      } else if (option.starts_with("--huge-method-max=")) {
+        ParseHugeMethodMax(option, parser_options.get());
+      } else if (option.starts_with("--large-method-max=")) {
+        ParseLargeMethodMax(option, parser_options.get());
+      } else if (option.starts_with("--small-method-max=")) {
+        ParseSmallMethodMax(option, parser_options.get());
+      } else if (option.starts_with("--tiny-method-max=")) {
+        ParseTinyMethodMax(option, parser_options.get());
+      } else if (option.starts_with("--num-dex-methods=")) {
+        ParseNumDexMethods(option, parser_options.get());
+      } else if (option.starts_with("--inline-depth-limit=")) {
+        ParseInlineDepthLimit(option, parser_options.get());
+      } else if (option.starts_with("--inline-max-code-units=")) {
+        ParseInlineMaxCodeUnits(option, parser_options.get());
+      } else if (option == "--host") {
+        is_host_ = true;
+      } else if (option == "--runtime-arg") {
+        if (++i >= argc) {
+          Usage("Missing required argument for --runtime-arg");
+        }
+        if (log_options) {
+          LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+        }
+        runtime_args_.push_back(argv[i]);
+      } else if (option == "--dump-timing") {
+        dump_timing_ = true;
+      } else if (option == "--dump-passes") {
+        dump_passes_ = true;
+      } else if (option.starts_with("--dump-cfg=")) {
+        dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data();
+      } else if (option == "--dump-stats") {
+        dump_stats_ = true;
+      } else if (option == "--generate-debug-info" || option == "-g") {
+        parser_options->generate_debug_info = true;
+      } else if (option == "--no-generate-debug-info") {
+        parser_options->generate_debug_info = false;
+      } else if (option == "--debuggable") {
+        parser_options->debuggable = true;
+        parser_options->generate_debug_info = true;
+      } else if (option.starts_with("--profile-file=")) {
+        profile_file_ = option.substr(strlen("--profile-file=")).data();
+        VLOG(compiler) << "dex2oat: profile file is " << profile_file_;
+      } else if (option == "--no-profile-file") {
+        // No profile
+      } else if (option.starts_with("--top-k-profile-threshold=")) {
+        ParseDouble(option.data(), '=', 0.0, 100.0, &parser_options->top_k_profile_threshold);
+      } else if (option == "--print-pass-names") {
+        parser_options->pass_manager_options.SetPrintPassNames(true);
+      } else if (option.starts_with("--disable-passes=")) {
+        ParseDisablePasses(option, parser_options.get());
+      } else if (option.starts_with("--print-passes=")) {
+        ParsePrintPasses(option, parser_options.get());
+      } else if (option == "--print-all-passes") {
+        parser_options->pass_manager_options.SetPrintAllPasses();
+      } else if (option.starts_with("--dump-cfg-passes=")) {
+        ParseDumpCfgPasses(option, parser_options.get());
+      } else if (option == "--print-pass-options") {
+        parser_options->pass_manager_options.SetPrintPassOptions(true);
+      } else if (option.starts_with("--pass-options=")) {
+        ParsePassOptions(option, parser_options.get());
+      } else if (option == "--include-patch-information") {
+        parser_options->include_patch_information = true;
+      } else if (option == "--no-include-patch-information") {
+        parser_options->include_patch_information = false;
+      } else if (option.starts_with("--verbose-methods=")) {
+        // TODO: rather than switch off compiler logging, make all VLOG(compiler) messages
+        //       conditional on having verbost methods.
+        gLogVerbosity.compiler = false;
+        Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods_);
+      } else if (option.starts_with("--dump-init-failures=")) {
+        ParseDumpInitFailures(option);
+      } else if (option.starts_with("--swap-file=")) {
+        swap_file_name_ = option.substr(strlen("--swap-file=")).data();
+      } else if (option.starts_with("--swap-fd=")) {
+        ParseSwapFd(option);
+      } else if (option == "--abort-on-hard-verifier-error") {
+        parser_options->abort_on_hard_verifier_error = true;
+      } else {
+        Usage("Unknown argument %s", option.data());
+      }
+    }
+
+    ProcessOptions(parser_options.get());
 
     // Insert some compiler things.
-    {
-      std::ostringstream oss;
-      for (int i = 0; i < argc; ++i) {
-        if (i > 0) {
-          oss << ' ';
-        }
-        oss << argv[i];
-      }
-      key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
-      oss.str("");  // Reset.
-      oss << kRuntimeISA;
-      key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
-      key_value_store_->Put(OatHeader::kPicKey,
-                            compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue);
-      key_value_store_->Put(OatHeader::kDebuggableKey,
-                            debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue);
-    }
+    InsertCompileOptions(argc, argv, parser_options.get());
   }
 
   // Check whether the oat output file is writable, and open it for later. Also open a swap file,
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 03fac18..5e2cf6b 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -22,6 +22,7 @@
 #include <sstream>
 
 #include "arch/arm/registers_arm.h"
+#include "base/bit_utils.h"
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "thread.h"
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 9bee104..d4574f4 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -928,6 +928,11 @@
         has_modrm = true;
         load = true;
         break;
+      case 0xBD:
+        opcode1 = "bsr";
+        has_modrm = true;
+        load = true;
+        break;
       case 0xBE:
         opcode1 = "movsxb";
         has_modrm = true;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 5e29ca7..44b78ff 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1618,9 +1618,7 @@
           const size_t pointer_size =
               InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet());
           DumpArtMethodVisitor visitor(this);
-          methods_section.VisitPackedArtMethods(&visitor,
-                                                image_space->Begin(),
-                                                ArtMethod::ObjectSize(pointer_size));
+          methods_section.VisitPackedArtMethods(&visitor, image_space->Begin(), pointer_size);
         }
       }
       // Dump the large objects separately.
@@ -1642,13 +1640,19 @@
     const auto& intern_section = image_header_.GetImageSection(
         ImageHeader::kSectionInternedStrings);
     stats_.header_bytes = header_bytes;
-    size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
-    stats_.alignment_bytes += alignment_bytes;
+    stats_.alignment_bytes += RoundUp(header_bytes, kObjectAlignment) - header_bytes;
+    // Add padding between the field and method section.
+    // (Field section is 4-byte aligned, method section is 8-byte aligned on 64-bit targets.)
+    stats_.alignment_bytes +=
+        method_section.Offset() - (field_section.Offset() + field_section.Size());
+    // Add padding between the method section and the intern table.
+    // (Method section is 4-byte aligned on 32-bit targets, intern table is 8-byte aligned.)
+    stats_.alignment_bytes +=
+        intern_section.Offset() - (method_section.Offset() + method_section.Size());
     stats_.alignment_bytes += bitmap_section.Offset() - image_header_.GetImageSize();
     stats_.bitmap_bytes += bitmap_section.Size();
     stats_.art_field_bytes += field_section.Size();
-    // RoundUp to 8 bytes to match the intern table alignment expectation.
-    stats_.art_method_bytes += RoundUp(method_section.Size(), sizeof(uint64_t));
+    stats_.art_method_bytes += method_section.Size();
     stats_.interned_strings_bytes += intern_section.Size();
     stats_.Dump(os, indent_os);
     os << "\n";
@@ -1966,7 +1970,7 @@
                                 method_access_flags);
 
       size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
-          vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
+          vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_pointer_size);
 
       double expansion =
       static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 283eea9..d601035 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -92,6 +92,32 @@
   }
 }
 
+static const OatHeader* GetOatHeader(const ElfFile* elf_file) {
+  uint64_t off = 0;
+  if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) {
+    return nullptr;
+  }
+
+  OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + off);
+  return oat_header;
+}
+
+// This function takes an elf file and reads the current patch delta value
+// encoded in its oat header value
+static bool ReadOatPatchDelta(const ElfFile* elf_file, off_t* delta, std::string* error_msg) {
+  const OatHeader* oat_header = GetOatHeader(elf_file);
+  if (oat_header == nullptr) {
+    *error_msg = "Unable to get oat header from elf file.";
+    return false;
+  }
+  if (!oat_header->IsValid()) {
+    *error_msg = "Elf file has an invalid oat header";
+    return false;
+  }
+  *delta = oat_header->GetImagePatchDelta();
+  return true;
+}
+
 bool PatchOat::Patch(const std::string& image_location, off_t delta,
                      File* output_image, InstructionSet isa,
                      TimingLogger* timings) {
@@ -454,9 +480,8 @@
 void PatchOat::PatchArtMethods(const ImageHeader* image_header) {
   const auto& section = image_header->GetMethodsSection();
   const size_t pointer_size = InstructionSetPointerSize(isa_);
-  const size_t method_size = ArtMethod::ObjectSize(pointer_size);
   PatchOatArtMethodVisitor visitor(this);
-  section.VisitPackedArtMethods(&visitor, heap_->Begin(), method_size);
+  section.VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size);
 }
 
 class FixupRootVisitor : public RootVisitor {
@@ -585,25 +610,6 @@
   copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object);
 }
 
-const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) {
-  if (elf_file->Is64Bit()) {
-    return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64());
-  } else {
-    return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32());
-  }
-}
-
-template <typename ElfFileImpl>
-const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) {
-  auto rodata_sec = elf_file->FindSectionByName(".rodata");
-  if (rodata_sec == nullptr) {
-    return nullptr;
-  }
-
-  OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset);
-  return oat_header;
-}
-
 // Called by BitmapCallback
 void PatchOat::VisitObject(mirror::Object* object) {
   mirror::Object* copy = RelocatedCopyOf(object);
@@ -871,11 +877,11 @@
   UsageError("  --base-offset-delta=<delta>: Specify the amount to change the old base-offset by.");
   UsageError("      This value may be negative.");
   UsageError("");
-  UsageError("  --patched-image-file=<file.art>: Use the same patch delta as was used to patch");
-  UsageError("      the given image file.");
+  UsageError("  --patched-image-file=<file.art>: Relocate the oat file to be the same as the");
+  UsageError("      given image file.");
   UsageError("");
-  UsageError("  --patched-image-location=<file.art>: Use the same patch delta as was used to");
-  UsageError("      patch the given image location. If used one must also specify the");
+  UsageError("  --patched-image-location=<file.art>: Relocate the oat file to be the same as the");
+  UsageError("      image at the given location. If used one must also specify the");
   UsageError("      --instruction-set flag. It will search for this image in the same way that");
   UsageError("      is done when loading one.");
   UsageError("");
@@ -991,6 +997,7 @@
   bool orig_base_offset_set = false;
   off_t base_delta = 0;
   bool base_delta_set = false;
+  bool match_delta = false;
   std::string patched_image_filename;
   std::string patched_image_location;
   bool dump_timings = kIsDebugBuild;
@@ -1189,7 +1196,11 @@
       base_delta_set = true;
       base_delta = base_offset - orig_base_offset;
     } else if (!patched_image_filename.empty()) {
+      if (have_image_files) {
+        Usage("--patched-image-location should not be used when patching other images");
+      }
       base_delta_set = true;
+      match_delta = true;
       std::string error_msg;
       if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) {
         Usage(error_msg.c_str(), patched_image_filename.c_str());
@@ -1307,6 +1318,32 @@
     return EXIT_FAILURE;
   }
 
+  if (match_delta) {
+    CHECK(!have_image_files);  // We will not do this with images.
+    std::string error_msg;
+    // Figure out what the current delta is so we can match it to the desired delta.
+    std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat.get(), PROT_READ, MAP_PRIVATE,
+                                               &error_msg));
+    off_t current_delta = 0;
+    if (elf.get() == nullptr) {
+      LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    } else if (!ReadOatPatchDelta(elf.get(), &current_delta, &error_msg)) {
+      LOG(ERROR) << "Unable to get current delta: " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    }
+    // Before this line base_delta is the desired final delta. We need it to be the actual amount to
+    // change everything by. We subtract the current delta from it to make it this.
+    base_delta -= current_delta;
+    if (!IsAligned<kPageSize>(base_delta)) {
+      LOG(ERROR) << "Given image file was relocated by an illegal delta";
+      cleanup(false);
+      return false;
+    }
+  }
+
   if (debug) {
     LOG(INFO) << "moving offset by " << base_delta
               << " (0x" << std::hex << base_delta << ") bytes or "
@@ -1333,18 +1370,18 @@
                           new_oat_out);
     // The order here doesn't matter. If the first one is successfully saved and the second one
     // erased, ImageSpace will still detect a problem and not use the files.
-    ret = ret && FinishFile(output_image.get(), ret);
-    ret = ret && FinishFile(output_oat.get(), ret);
+    ret = FinishFile(output_image.get(), ret);
+    ret = FinishFile(output_oat.get(), ret);
   } else if (have_oat_files) {
     TimingLogger::ScopedTiming pt("patch oat", &timings);
     ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
                           output_oat_fd >= 0,  // was it opened from FD?
                           new_oat_out);
-    ret = ret && FinishFile(output_oat.get(), ret);
+    ret = FinishFile(output_oat.get(), ret);
   } else if (have_image_files) {
     TimingLogger::ScopedTiming pt("patch image", &timings);
     ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings);
-    ret = ret && FinishFile(output_image.get(), ret);
+    ret = FinishFile(output_image.get(), ret);
   } else {
     CHECK(false);
     ret = true;
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 43cdaea..87ecc61 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -163,13 +163,6 @@
     return ret;
   }
 
-  // Look up the oat header from any elf file.
-  static const OatHeader* GetOatHeader(const ElfFile* elf_file);
-
-  // Templatized version to actually look up the oat header
-  template <typename ElfFileImpl>
-  static const OatHeader* GetOatHeader(const ElfFileImpl* elf_file);
-
   // Walks through the old image and patches the mmap'd copy of it to the new offset. It does not
   // change the heap.
   class PatchVisitor {
diff --git a/runtime/art_field.h b/runtime/art_field.h
index fa0694b..a943a34 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -21,7 +21,6 @@
 
 #include "gc_root.h"
 #include "modifiers.h"
-#include "object_callbacks.h"
 #include "offsets.h"
 #include "primitive.h"
 #include "read_barrier_option.h"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 51398ca..40bb9e1 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -506,7 +506,7 @@
 
 inline void ArtMethod::CopyFrom(const ArtMethod* src, size_t image_pointer_size) {
   memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
-         ObjectSize(image_pointer_size));
+         Size(image_pointer_size));
   declaring_class_ = GcRoot<mirror::Class>(const_cast<ArtMethod*>(src)->GetDeclaringClass());
   dex_cache_resolved_methods_ = GcRoot<mirror::PointerArray>(
       const_cast<ArtMethod*>(src)->GetDexCacheResolvedMethods());
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 17c9fe4..b9e13a4 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -20,6 +20,7 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/stringpiece.h"
+#include "debugger.h"
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
 #include "entrypoints/entrypoint_utils.h"
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 85c03ed..cec1837 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -23,7 +23,6 @@
 #include "method_reference.h"
 #include "modifiers.h"
 #include "mirror/object.h"
-#include "object_callbacks.h"
 #include "quick/quick_method_frame_info.h"
 #include "read_barrier_option.h"
 #include "stack.h"
@@ -507,12 +506,19 @@
   bool EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  // Size of an instance of this object.
-  static size_t ObjectSize(size_t pointer_size) {
+  // Size of an instance of this native class.
+  static size_t Size(size_t pointer_size) {
     return RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size) +
         (sizeof(PtrSizedFields) / sizeof(void*)) * pointer_size;
   }
 
+  // Alignment of an instance of this native class.
+  static size_t Alignment(size_t pointer_size) {
+    // The ArtMethod alignment is the same as image pointer size. This differs from
+    // alignof(ArtMethod) if cross-compiling with pointer_size != sizeof(void*).
+    return pointer_size;
+  }
+
   void CopyFrom(const ArtMethod* src, size_t image_pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 6f45dc8..1b0d774 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -29,21 +29,28 @@
 template<typename T>
 static constexpr int CLZ(T x) {
   static_assert(std::is_integral<T>::value, "T must be integral");
-  // TODO: assert unsigned. There is currently many uses with signed values.
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
   static_assert(sizeof(T) <= sizeof(long long),  // NOLINT [runtime/int] [4]
                 "T too large, must be smaller than long long");
-  return (sizeof(T) == sizeof(uint32_t))
-      ? __builtin_clz(x)  // TODO: __builtin_clz[ll] has undefined behavior for x=0
-      : __builtin_clzll(x);
+  return
+      DCHECK_CONSTEXPR(x != 0, "x must not be zero", T(0))
+      (sizeof(T) == sizeof(uint32_t))
+          ? __builtin_clz(x)
+          : __builtin_clzll(x);
 }
 
 template<typename T>
 static constexpr int CTZ(T x) {
   static_assert(std::is_integral<T>::value, "T must be integral");
-  // TODO: assert unsigned. There is currently many uses with signed values.
-  return (sizeof(T) == sizeof(uint32_t))
-      ? __builtin_ctz(x)
-      : __builtin_ctzll(x);
+  // It is not unreasonable to ask for trailing zeros in a negative number. As such, do not check
+  // that T is an unsigned type.
+  static_assert(sizeof(T) <= sizeof(long long),  // NOLINT [runtime/int] [4]
+                "T too large, must be smaller than long long");
+  return
+      DCHECK_CONSTEXPR(x != 0, "x must not be zero", T(0))
+      (sizeof(T) == sizeof(uint32_t))
+          ? __builtin_ctz(x)
+          : __builtin_ctzll(x);
 }
 
 template<typename T>
@@ -158,6 +165,9 @@
 #define DCHECK_ALIGNED(value, alignment) \
   DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value)
 
+#define CHECK_ALIGNED_PARAM(value, alignment) \
+  CHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
+
 #define DCHECK_ALIGNED_PARAM(value, alignment) \
   DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f19263d..c179c64 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1213,9 +1213,8 @@
   if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) {
     const ImageHeader& header = space->GetImageHeader();
     const ImageSection& methods = header.GetMethodsSection();
-    const size_t art_method_size = ArtMethod::ObjectSize(image_pointer_size_);
     SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_);
-    methods.VisitPackedArtMethods(&visitor, space->Begin(), art_method_size);
+    methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_);
   }
 
   // reinit class_roots_
@@ -2294,9 +2293,11 @@
   if (length == 0) {
     return nullptr;
   }
-  auto* ret = new(Runtime::Current()->GetLinearAlloc()->Alloc(
-      self, LengthPrefixedArray<ArtField>::ComputeSize(length))) LengthPrefixedArray<ArtField>(
-          length);
+  // If the ArtField alignment changes, review all uses of LengthPrefixedArray<ArtField>.
+  static_assert(alignof(ArtField) == 4, "ArtField alignment is expected to be 4.");
+  size_t storage_size = LengthPrefixedArray<ArtField>::ComputeSize(length);
+  void* array_storage = Runtime::Current()->GetLinearAlloc()->Alloc(self, storage_size);
+  auto* ret = new(array_storage) LengthPrefixedArray<ArtField>(length);
   CHECK(ret != nullptr);
   std::uninitialized_fill_n(&ret->At(0), length, ArtField());
   return ret;
@@ -2306,13 +2307,15 @@
   if (length == 0) {
     return nullptr;
   }
-  const size_t method_size = ArtMethod::ObjectSize(image_pointer_size_);
-  auto* ret = new (Runtime::Current()->GetLinearAlloc()->Alloc(
-      self, LengthPrefixedArray<ArtMethod>::ComputeSize(length, method_size)))
-          LengthPrefixedArray<ArtMethod>(length);
+  const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_);
+  const size_t method_size = ArtMethod::Size(image_pointer_size_);
+  const size_t storage_size =
+      LengthPrefixedArray<ArtMethod>::ComputeSize(length, method_size, method_alignment);
+  void* array_storage = Runtime::Current()->GetLinearAlloc()->Alloc(self, storage_size);
+  auto* ret = new (array_storage) LengthPrefixedArray<ArtMethod>(length);
   CHECK(ret != nullptr);
   for (size_t i = 0; i < length; ++i) {
-    new(reinterpret_cast<void*>(&ret->At(i, method_size))) ArtMethod;
+    new(reinterpret_cast<void*>(&ret->At(i, method_size, method_alignment))) ArtMethod;
   }
   return ret;
 }
@@ -4689,7 +4692,8 @@
   const bool have_interfaces = interfaces.Get() != nullptr;
   const size_t num_interfaces =
       have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces();
-  const size_t method_size = ArtMethod::ObjectSize(image_pointer_size_);
+  const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_);
+  const size_t method_size = ArtMethod::Size(image_pointer_size_);
   if (num_interfaces == 0) {
     if (super_ifcount == 0) {
       // Class implements no interfaces.
@@ -4914,7 +4918,7 @@
         // matter which direction we go.  We walk it backward anyway.)
         for (k = input_array_length - 1; k >= 0; --k) {
           ArtMethod* vtable_method = input_virtual_methods != nullptr ?
-              &input_virtual_methods->At(k, method_size) :
+              &input_virtual_methods->At(k, method_size, method_alignment) :
               input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size_);
           ArtMethod* vtable_method_for_name_comparison =
               vtable_method->GetInterfaceMethodIfProxy(image_pointer_size_);
@@ -4975,10 +4979,14 @@
     // where GCs could attempt to mark stale pointers due to memcpy. And since we overwrite the
     // realloced memory with out->CopyFrom, we are guaranteed to have objects in the to space since
     // CopyFrom has internal read barriers.
-    const size_t old_size = old_virtuals != nullptr ?
-        LengthPrefixedArray<ArtMethod>::ComputeSize(old_method_count, method_size) : 0u;
+    const size_t old_size = old_virtuals != nullptr
+        ? LengthPrefixedArray<ArtMethod>::ComputeSize(old_method_count,
+                                                      method_size,
+                                                      method_alignment)
+        : 0u;
     const size_t new_size = LengthPrefixedArray<ArtMethod>::ComputeSize(new_method_count,
-                                                                        method_size);
+                                                                        method_size,
+                                                                        method_alignment);
     auto* virtuals = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
         runtime->GetLinearAlloc()->Realloc(self, old_virtuals, old_size, new_size));
     if (UNLIKELY(virtuals == nullptr)) {
@@ -4989,7 +4997,7 @@
     ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter());
     if (virtuals != old_virtuals) {
       // Maps from heap allocated miranda method to linear alloc miranda method.
-      StrideIterator<ArtMethod> out = virtuals->Begin(method_size);
+      StrideIterator<ArtMethod> out = virtuals->Begin(method_size, method_alignment);
       // Copy over the old methods + miranda methods.
       for (auto& m : klass->GetVirtualMethods(image_pointer_size_)) {
         move_table.emplace(&m, &*out);
@@ -4999,7 +5007,7 @@
         ++out;
       }
     }
-    StrideIterator<ArtMethod> out(virtuals->Begin(method_size) + old_method_count);
+    StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment) + old_method_count);
     // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and
     // we want the roots of the miranda methods to get visited.
     for (ArtMethod* mir_method : miranda_methods) {
@@ -5022,7 +5030,7 @@
       self->AssertPendingOOMException();
       return false;
     }
-    out = StrideIterator<ArtMethod>(virtuals->Begin(method_size) + old_method_count);
+    out = virtuals->Begin(method_size, method_alignment) + old_method_count;
     size_t vtable_pos = old_vtable_count;
     for (size_t i = old_method_count; i < new_method_count; ++i) {
       // Leave the declaring class alone as type indices are relative to it
@@ -5893,8 +5901,10 @@
 }
 
 ArtMethod* ClassLinker::CreateRuntimeMethod() {
-  const size_t method_size = ArtMethod::ObjectSize(image_pointer_size_);
-  ArtMethod* method = &AllocArtMethodArray(Thread::Current(), 1)->At(0, method_size);
+  const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_);
+  const size_t method_size = ArtMethod::Size(image_pointer_size_);
+  LengthPrefixedArray<ArtMethod>* method_array = AllocArtMethodArray(Thread::Current(), 1);
+  ArtMethod* method = &method_array->At(0, method_size, method_alignment);
   CHECK(method != nullptr);
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   CHECK(method->IsRuntimeMethod());
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index d30fac4..52590a5 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -29,6 +29,7 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/hash_map.h"
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "class_linker.h"
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index ceefdec..a1ddbc7 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -22,7 +22,6 @@
 #include <unordered_map>
 #include <vector>
 
-#include "base/hash_map.h"
 #include "base/logging.h"
 #include "base/mutex.h"  // For Locks::mutator_lock_.
 #include "base/value_object.h"
@@ -43,6 +42,8 @@
 class ArtField;
 class ArtMethod;
 class ClassLinker;
+template <class Key, class Value, class EmptyFn, class HashFn, class Pred, class Alloc>
+class HashMap;
 class MemMap;
 class OatDexFile;
 class Signature;
@@ -1051,7 +1052,12 @@
       return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(a, b) == 0;
     }
   };
-  typedef HashMap<const char*, const ClassDef*, UTF16EmptyFn, UTF16HashCmp, UTF16HashCmp> Index;
+  using Index = HashMap<const char*,
+                        const ClassDef*,
+                        UTF16EmptyFn,
+                        UTF16HashCmp,
+                        UTF16HashCmp,
+                        std::allocator<std::pair<const char*, const ClassDef*>>>;
   mutable Atomic<Index*> class_def_index_;
 
   // If this dex file was loaded from an oat file, oat_dex_file_ contains a
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 9fd8c87..723ee74 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1868,7 +1868,8 @@
   DELEGATE_TO_IMPL(GetFile);
 }
 
-bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) {
+bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset,
+                                      uint64_t* size) const {
   if (elf32_.get() == nullptr) {
     CHECK(elf64_.get() != nullptr);
 
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 48cb4b8..1188c97 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -60,7 +60,7 @@
 
   const File& GetFile() const;
 
-  bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size);
+  bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) const;
 
   uint64_t FindSymbolAddress(unsigned section_type,
                              const std::string& symbol_name,
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index eaf26bc..eaf33f6 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -298,7 +298,7 @@
           interface_method->GetArtMethod(), sizeof(void*));
       auto* virtual_methods = proxy_class->GetVirtualMethodsPtr();
       size_t num_virtuals = proxy_class->NumVirtualMethods();
-      size_t method_size = ArtMethod::ObjectSize(sizeof(void*));
+      size_t method_size = ArtMethod::Size(sizeof(void*));
       int throws_index = (reinterpret_cast<uintptr_t>(proxy_method) -
           reinterpret_cast<uintptr_t>(virtual_methods)) / method_size;
       CHECK_LT(throws_index, static_cast<int>(num_virtuals));
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 47f9b1b..c3a9627 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -331,7 +331,7 @@
   // If we don't have a potential method, we're outta here.
   VLOG(signals) << "potential method: " << method_obj;
   // TODO: Check linear alloc and image.
-  DCHECK_ALIGNED(ArtMethod::ObjectSize(sizeof(void*)), sizeof(void*))
+  DCHECK_ALIGNED(ArtMethod::Size(sizeof(void*)), sizeof(void*))
       << "ArtMethod is not pointer aligned";
   if (method_obj == nullptr || !IsAligned<sizeof(void*)>(method_obj)) {
     VLOG(signals) << "no method";
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 55b1772..45db500 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -22,7 +22,6 @@
 #include <string>
 
 #include "atomic.h"
-#include "base/bit_utils.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "mem_map.h"
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index efa065b..d1ab587 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -20,7 +20,6 @@
 #include "heap.h"
 
 #include "base/time_utils.h"
-#include "debugger.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/allocation_record.h"
 #include "gc/collector/semi_space.h"
diff --git a/runtime/image.cc b/runtime/image.cc
index ba1e58b..2586959 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '8', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '9', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
@@ -153,19 +153,21 @@
     for (size_t i = 0; i < array->Length(); ++i) {
       visitor->Visit(&array->At(i, sizeof(ArtField)));
     }
-    pos += array->ComputeSize(array->Length(), sizeof(ArtField));
+    pos += array->ComputeSize(array->Length());
   }
 }
 
 void ImageSection::VisitPackedArtMethods(ArtMethodVisitor* visitor,
                                          uint8_t* base,
-                                         size_t method_size) const {
+                                         size_t pointer_size) const {
+  const size_t method_alignment = ArtMethod::Alignment(pointer_size);
+  const size_t method_size = ArtMethod::Size(pointer_size);
   for (size_t pos = 0; pos < Size(); ) {
     auto* array = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(base + Offset() + pos);
     for (size_t i = 0; i < array->Length(); ++i) {
-      visitor->Visit(&array->At(i, method_size));
+      visitor->Visit(&array->At(i, method_size, method_alignment));
     }
-    pos += array->ComputeSize(array->Length(), method_size);
+    pos += array->ComputeSize(array->Length(), method_size, method_alignment);
   }
 }
 
diff --git a/runtime/image.h b/runtime/image.h
index eb26f7f..1a0d8fd 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -65,7 +65,7 @@
   }
 
   // Visit ArtMethods in the section starting at base.
-  void VisitPackedArtMethods(ArtMethodVisitor* visitor, uint8_t* base, size_t method_size) const;
+  void VisitPackedArtMethods(ArtMethodVisitor* visitor, uint8_t* base, size_t pointer_size) const;
 
   // Visit ArtMethods in the section starting at base.
   void VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const;
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index fda97db..26a4fe4 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -19,6 +19,7 @@
 #include <dlfcn.h>
 
 #include "art_method-inl.h"
+#include "debugger.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "interpreter/interpreter.h"
 #include "jit_code_cache.h"
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 14683d4..976936d 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -101,7 +101,7 @@
 static inline uint32_t UnsignedLeb128Size(uint32_t data) {
   // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1  // 32 - CLZ(data | 1)
   // bytes = ceil(bits_to_encode / 7.0);             // (6 + bits_to_encode) / 7
-  uint32_t x = 6 + 32 - CLZ(data | 1);
+  uint32_t x = 6 + 32 - CLZ(data | 1U);
   // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7).
   // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
   return (x * 37) >> 8;
@@ -111,7 +111,7 @@
 static inline uint32_t SignedLeb128Size(int32_t data) {
   // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign.
   data = data ^ (data >> 31);
-  uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1);
+  uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1U);
   return (x * 37) >> 8;
 }
 
diff --git a/runtime/length_prefixed_array.h b/runtime/length_prefixed_array.h
index 2b2e8d3..d9bc656 100644
--- a/runtime/length_prefixed_array.h
+++ b/runtime/length_prefixed_array.h
@@ -21,6 +21,8 @@
 
 #include "linear_alloc.h"
 #include "stride_iterator.h"
+#include "base/bit_utils.h"
+#include "base/casts.h"
 #include "base/iteration_range.h"
 
 namespace art {
@@ -28,29 +30,35 @@
 template<typename T>
 class LengthPrefixedArray {
  public:
-  explicit LengthPrefixedArray(uint64_t length) : length_(length) {}
+  explicit LengthPrefixedArray(size_t length)
+      : length_(dchecked_integral_cast<uint32_t>(length)) {}
 
-  T& At(size_t index, size_t element_size = sizeof(T)) {
+  T& At(size_t index, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
     DCHECK_LT(index, length_);
-    return *reinterpret_cast<T*>(&data_[0] + index * element_size);
+    return AtUnchecked(index, element_size, alignment);
   }
 
-  StrideIterator<T> Begin(size_t element_size = sizeof(T)) {
-    return StrideIterator<T>(reinterpret_cast<T*>(&data_[0]), element_size);
+  StrideIterator<T> Begin(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
+    return StrideIterator<T>(&AtUnchecked(0, element_size, alignment), element_size);
   }
 
-  StrideIterator<T> End(size_t element_size = sizeof(T)) {
-    return StrideIterator<T>(reinterpret_cast<T*>(&data_[0] + element_size * length_),
-                             element_size);
+  StrideIterator<T> End(size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
+    return StrideIterator<T>(&AtUnchecked(length_, element_size, alignment), element_size);
   }
 
-  static size_t OffsetOfElement(size_t index, size_t element_size = sizeof(T)) {
-    return offsetof(LengthPrefixedArray<T>, data_) + index * element_size;
+  static size_t OffsetOfElement(size_t index,
+                                size_t element_size = sizeof(T),
+                                size_t alignment = alignof(T)) {
+    DCHECK_ALIGNED_PARAM(element_size, alignment);
+    return RoundUp(offsetof(LengthPrefixedArray<T>, data), alignment) + index * element_size;
   }
 
-  // Alignment is the caller's responsibility.
-  static size_t ComputeSize(size_t num_elements, size_t element_size = sizeof(T)) {
-    return OffsetOfElement(num_elements, element_size);
+  static size_t ComputeSize(size_t num_elements,
+                            size_t element_size = sizeof(T),
+                            size_t alignment = alignof(T)) {
+    size_t result = OffsetOfElement(num_elements, element_size, alignment);
+    DCHECK_ALIGNED_PARAM(result, alignment);
+    return result;
   }
 
   uint64_t Length() const {
@@ -58,21 +66,26 @@
   }
 
   // Update the length but does not reallocate storage.
-  void SetLength(uint64_t length) {
-    length_ = length;
+  void SetLength(size_t length) {
+    length_ = dchecked_integral_cast<uint32_t>(length);
   }
 
  private:
-  uint64_t length_;  // 64 bits for 8 byte alignment of data_.
-  uint8_t data_[0];
+  T& AtUnchecked(size_t index, size_t element_size, size_t alignment) {
+    return *reinterpret_cast<T*>(
+        reinterpret_cast<uintptr_t>(this) + OffsetOfElement(index, element_size, alignment));
+  }
+
+  uint32_t length_;
+  uint8_t data[0];
 };
 
 // Returns empty iteration range if the array is null.
 template<typename T>
 IterationRange<StrideIterator<T>> MakeIterationRangeFromLengthPrefixedArray(
-    LengthPrefixedArray<T>* arr, size_t element_size) {
+    LengthPrefixedArray<T>* arr, size_t element_size = sizeof(T), size_t alignment = alignof(T)) {
   return arr != nullptr ?
-      MakeIterationRange(arr->Begin(element_size), arr->End(element_size)) :
+      MakeIterationRange(arr->Begin(element_size, alignment), arr->End(element_size, alignment)) :
       MakeEmptyIterationRange(StrideIterator<T>(nullptr, 0));
 }
 
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 887e204..ac9cb09 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -92,14 +92,18 @@
   CheckPointerSize(pointer_size);
   auto* methods = GetDirectMethodsPtrUnchecked();
   DCHECK(methods != nullptr);
-  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
+  return &methods->At(i,
+                      ArtMethod::Size(pointer_size),
+                      ArtMethod::Alignment(pointer_size));
 }
 
 inline ArtMethod* Class::GetDirectMethod(size_t i, size_t pointer_size) {
   CheckPointerSize(pointer_size);
   auto* methods = GetDirectMethodsPtr();
   DCHECK(methods != nullptr);
-  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
+  return &methods->At(i,
+                      ArtMethod::Size(pointer_size),
+                      ArtMethod::Alignment(pointer_size));
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -133,7 +137,9 @@
   CheckPointerSize(pointer_size);
   LengthPrefixedArray<ArtMethod>* methods = GetVirtualMethodsPtrUnchecked();
   DCHECK(methods != nullptr);
-  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
+  return &methods->At(i,
+                      ArtMethod::Size(pointer_size),
+                      ArtMethod::Alignment(pointer_size));
 }
 
 inline PointerArray* Class::GetVTable() {
@@ -837,29 +843,31 @@
 inline IterationRange<StrideIterator<ArtMethod>> Class::GetDirectMethods(size_t pointer_size) {
   CheckPointerSize(pointer_size);
   return MakeIterationRangeFromLengthPrefixedArray(GetDirectMethodsPtrUnchecked(),
-                                                   ArtMethod::ObjectSize(pointer_size));
+                                                   ArtMethod::Size(pointer_size),
+                                                   ArtMethod::Alignment(pointer_size));
 }
 
 inline IterationRange<StrideIterator<ArtMethod>> Class::GetVirtualMethods(size_t pointer_size) {
   CheckPointerSize(pointer_size);
   return MakeIterationRangeFromLengthPrefixedArray(GetVirtualMethodsPtrUnchecked(),
-                                                   ArtMethod::ObjectSize(pointer_size));
+                                                   ArtMethod::Size(pointer_size),
+                                                   ArtMethod::Alignment(pointer_size));
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetIFields() {
-  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtr(), sizeof(ArtField));
+  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtr());
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetSFields() {
-  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtr(), sizeof(ArtField));
+  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtr());
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetIFieldsUnchecked() {
-  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtrUnchecked(), sizeof(ArtField));
+  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtrUnchecked());
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetSFieldsUnchecked() {
-  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtrUnchecked(), sizeof(ArtField));
+  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtrUnchecked());
 }
 
 inline MemberOffset Class::EmbeddedImTableOffset(size_t pointer_size) {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 1ca98e5..c337e91 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -208,7 +208,7 @@
     }
   }
   if (kIsDebugBuild) {
-    for (ArtField& field : MakeIterationRangeFromLengthPrefixedArray(fields, sizeof(ArtField))) {
+    for (ArtField& field : MakeIterationRangeFromLengthPrefixedArray(fields)) {
       CHECK_NE(field.GetName(), name->ToModifiedUtf8());
     }
   }
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 7118f36..c76f6ee 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -17,7 +17,6 @@
 #include "java_lang_Thread.h"
 
 #include "common_throws.h"
-#include "debugger.h"
 #include "jni_internal.h"
 #include "monitor.h"
 #include "mirror/object.h"
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index 3db3265..33cfe08 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -28,7 +28,6 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "common_throws.h"
-#include "debugger.h"
 #include "dex_file-inl.h"
 #include "instrumentation.h"
 #include "mirror/class-inl.h"
diff --git a/runtime/stack.h b/runtime/stack.h
index 8023de1..2562738 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -21,7 +21,6 @@
 #include <string>
 
 #include "arch/instruction_set.h"
-#include "base/bit_utils.h"
 #include "dex_file.h"
 #include "gc_root.h"
 #include "mirror/object_reference.h"
diff --git a/runtime/utils.cc b/runtime/utils.cc
index db3f2fe..8aa1189 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1471,7 +1471,7 @@
         dex_pc_is_branch_target.insert(dex_pc + inst->GetTargetOffset());
       } else if (inst->IsSwitch()) {
         const uint16_t* insns = code_item->insns_ + dex_pc;
-        int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
+        int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
         const uint16_t* switch_insns = insns + switch_offset;
         uint32_t switch_count = switch_insns[1];
         int32_t targets_offset;
@@ -1483,8 +1483,9 @@
           targets_offset = 2 + 2 * switch_count;
         }
         for (uint32_t targ = 0; targ < switch_count; targ++) {
-          int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] |
-              (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
+          int32_t offset =
+              static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
+              static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
           dex_pc_is_branch_target.insert(dex_pc + offset);
         }
       }
@@ -1499,8 +1500,9 @@
     const Instruction* inst = Instruction::At(code_item->insns_);
     bool first_in_block = true;
     bool force_new_block = false;
-    for (uint32_t dex_pc = 0; dex_pc < code_item->insns_size_in_code_units_;
-        dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+    for (uint32_t dex_pc = 0;
+         dex_pc < code_item->insns_size_in_code_units_;
+         dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
       if (dex_pc == 0 ||
           (dex_pc_is_branch_target.find(dex_pc) != dex_pc_is_branch_target.end()) ||
           force_new_block) {
@@ -1531,7 +1533,7 @@
       os << " 0x" << std::hex << dex_pc << std::dec << ": ";
       std::string inst_str = inst->DumpString(dex_file);
       size_t cur_start = 0;  // It's OK to start at zero, instruction dumps don't start with chars
-      // we need to escape.
+                             // we need to escape.
       while (cur_start != std::string::npos) {
         size_t next_escape = inst_str.find_first_of("\"{}<>", cur_start + 1);
         if (next_escape == std::string::npos) {
@@ -1645,7 +1647,7 @@
           // TODO: Iterate through all switch targets.
           const uint16_t* insns = code_item->insns_ + dex_pc;
           /* make sure the start of the switch is in range */
-          int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
+          int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
           /* offset to switch table is a relative branch-style offset */
           const uint16_t* switch_insns = insns + switch_offset;
           uint32_t switch_count = switch_insns[1];
@@ -1660,8 +1662,9 @@
           /* make sure the end of the switch is in range */
           /* verify each switch target */
           for (uint32_t targ = 0; targ < switch_count; targ++) {
-            int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] |
-                (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
+            int32_t offset =
+                static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
+                static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
             int32_t abs_offset = dex_pc + offset;
             auto target_it = dex_pc_to_node_id.find(abs_offset);
             if (target_it != dex_pc_to_node_id.end()) {
@@ -1715,7 +1718,7 @@
     for (uint32_t dex_pc : blocks_with_detailed_exceptions) {
       const Instruction* inst = Instruction::At(&code_item->insns_[dex_pc]);
       uint32_t this_node_id = dex_pc_to_incl_id.find(dex_pc)->second;
-      for (;;) {
+      while (true) {
         CatchHandlerIterator catch_it(*code_item, dex_pc);
         if (catch_it.HasNext()) {
           std::set<uint32_t> handled_targets;
@@ -1739,8 +1742,8 @@
           break;
         }
 
-        // Loop update. In the body to have a late break-out if the next instruction is a branch
-        // target and thus in another block.
+        // Loop update. Have a break-out if the next instruction is a branch target and thus in
+        // another block.
         dex_pc += inst->SizeInCodeUnits();
         if (dex_pc >= code_item->insns_size_in_code_units_) {
           break;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1661534..1828b91 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -53,6 +53,9 @@
 static constexpr bool gDebugVerify = false;
 // TODO: Add a constant to method_verifier to turn on verbose logging?
 
+// On VLOG(verifier), should we dump the whole state when we run into a hard failure?
+static constexpr bool kDumpRegLinesOnHardFailureIfVLOG = true;
+
 void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* flags,
                                  uint32_t insns_size, uint16_t registers_size,
                                  MethodVerifier* verifier) {
@@ -638,6 +641,12 @@
         Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref);
       }
       have_pending_hard_failure_ = true;
+      if (VLOG_IS_ON(verifier) && kDumpRegLinesOnHardFailureIfVLOG) {
+        ScopedObjectAccess soa(Thread::Current());
+        std::ostringstream oss;
+        Dump(oss);
+        LOG(ERROR) << oss.str();
+      }
       break;
     }
   }
@@ -1034,8 +1043,8 @@
 
   DCHECK_LT(cur_offset, insn_count);
   /* make sure the start of the array data table is in range */
-  array_data_offset = insns[1] | (((int32_t) insns[2]) << 16);
-  if ((int32_t) cur_offset + array_data_offset < 0 ||
+  array_data_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
+  if (static_cast<int32_t>(cur_offset) + array_data_offset < 0 ||
       cur_offset + array_data_offset + 2 >= insn_count) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid array data start: at " << cur_offset
                                       << ", data offset " << array_data_offset
@@ -1147,8 +1156,9 @@
   DCHECK_LT(cur_offset, insn_count);
   const uint16_t* insns = code_item_->insns_ + cur_offset;
   /* make sure the start of the switch is in range */
-  int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
-  if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 > insn_count) {
+  int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
+  if (static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
+      cur_offset + switch_offset + 2 > insn_count) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch start: at " << cur_offset
                                       << ", switch offset " << switch_offset
                                       << ", count " << insn_count;
@@ -1204,8 +1214,9 @@
   if (keys_offset > 0 && switch_count > 1) {
     int32_t last_key = switch_insns[keys_offset] | (switch_insns[keys_offset + 1] << 16);
     for (uint32_t targ = 1; targ < switch_count; targ++) {
-      int32_t key = (int32_t) switch_insns[keys_offset + targ * 2] |
-                    (int32_t) (switch_insns[keys_offset + targ * 2 + 1] << 16);
+      int32_t key =
+          static_cast<int32_t>(switch_insns[keys_offset + targ * 2]) |
+          static_cast<int32_t>(switch_insns[keys_offset + targ * 2 + 1] << 16);
       if (key <= last_key) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid packed switch: last key=" << last_key
                                           << ", this=" << key;
@@ -1216,11 +1227,11 @@
   }
   /* verify each switch target */
   for (uint32_t targ = 0; targ < switch_count; targ++) {
-    int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] |
-                     (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
+    int32_t offset = static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
+                     static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
     int32_t abs_offset = cur_offset + offset;
     if (abs_offset < 0 ||
-        abs_offset >= (int32_t) insn_count ||
+        abs_offset >= static_cast<int32_t>(insn_count) ||
         !insn_flags_[abs_offset].IsOpcode()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset
                                         << " (-> " << reinterpret_cast<void*>(abs_offset) << ") at "
@@ -1319,7 +1330,7 @@
   ScopedIndentation indent1(vios);
   const Instruction* inst = Instruction::At(code_item_->insns_);
   for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
-      dex_pc += inst->SizeInCodeUnits()) {
+      dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != nullptr) {
       vios->Stream() << reg_line->Dump(this) << "\n";
@@ -1331,7 +1342,6 @@
       vios->Stream() << inst->DumpHex(5) << " ";
     }
     vios->Stream() << inst->DumpString(dex_file_) << "\n";
-    inst = inst->Next();
   }
 }
 
@@ -2139,7 +2149,8 @@
           } else {
             // Now verify if the element width in the table matches the element width declared in
             // the array
-            const uint16_t* array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
+            const uint16_t* array_data =
+                insns + (insns[1] | (static_cast<int32_t>(insns[2]) << 16));
             if (array_data[0] != Instruction::kArrayDataSignature) {
               Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid magic for array-data";
             } else {
@@ -3077,7 +3088,7 @@
    * just need to walk through and tag the targets.
    */
   if ((opcode_flags & Instruction::kSwitch) != 0) {
-    int offset_to_switch = insns[1] | (((int32_t) insns[2]) << 16);
+    int offset_to_switch = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
     const uint16_t* switch_insns = insns + offset_to_switch;
     int switch_count = switch_insns[1];
     int offset_to_targets, targ;
@@ -3098,7 +3109,7 @@
 
       /* offsets are 32-bit, and only partly endian-swapped */
       offset = switch_insns[offset_to_targets + targ * 2] |
-         (((int32_t) switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
+         (static_cast<int32_t>(switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
       abs_offset = work_insn_idx_ + offset;
       DCHECK_LT(abs_offset, code_item_->insns_size_in_code_units_);
       if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, abs_offset)) {
@@ -3938,7 +3949,24 @@
     if (array_type.IsZero()) {
       // Null array type; this code path will fail at runtime.
       // Still check that the given value matches the instruction's type.
-      work_line_->VerifyRegisterType(this, inst->VRegA_23x(), insn_type);
+      // Note: this is, as usual, complicated by the fact the the instruction isn't fully typed
+      //       and fits multiple register types.
+      const RegType* modified_reg_type = &insn_type;
+      if ((modified_reg_type == &reg_types_.Integer()) ||
+          (modified_reg_type == &reg_types_.LongLo())) {
+        // May be integer or float | long or double. Overwrite insn_type accordingly.
+        const RegType& value_type = work_line_->GetRegisterType(this, inst->VRegA_23x());
+        if (modified_reg_type == &reg_types_.Integer()) {
+          if (&value_type == &reg_types_.Float()) {
+            modified_reg_type = &value_type;
+          }
+        } else {
+          if (&value_type == &reg_types_.DoubleLo()) {
+            modified_reg_type = &value_type;
+          }
+        }
+      }
+      work_line_->VerifyRegisterType(this, inst->VRegA_23x(), *modified_reg_type);
     } else if (!array_type.IsArrayTypes()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aput";
     } else {
diff --git a/test/107-int-math2/src/Main.java b/test/107-int-math2/src/Main.java
index 6a6227c..0c91d44 100644
--- a/test/107-int-math2/src/Main.java
+++ b/test/107-int-math2/src/Main.java
@@ -412,7 +412,7 @@
      */
     static int lit8Test(int x) {
 
-        int[] results = new int[8];
+        int[] results = new int[9];
 
         /* try to generate op-int/lit8" instructions */
         results[0] = x + 10;
@@ -423,6 +423,7 @@
         results[5] = x & 10;
         results[6] = x | -10;
         results[7] = x ^ -10;
+        results[8] = x * -256;
         int minInt = -2147483648;
         int result = minInt / -1;
         if (result != minInt) {return 1; }
@@ -434,6 +435,7 @@
         if (results[5] != 8) {return 7; }
         if (results[6] != -1) {return 8; }
         if (results[7] != 55563) {return 9; }
+        if (results[8] != 14222080) {return 10; }
         return 0;
     }
 
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index a6a6e08..04326b3 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -203,9 +203,11 @@
 
   // Test segv
   sigaction(SIGSEGV, &tmp, nullptr);
-#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
-  // On supported architectures we cause a real SEGV.
+#if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
   *go_away_compiler = 'a';
+#elif defined(__x86_64__)
+  // Cause a SEGV using an instruction known to be 3 bytes long
+  asm volatile("movl $0, %%eax;" "movb $1, (%%eax);" : : : "%eax");
 #else
   // On other architectures we simulate SEGV.
   kill(getpid(), SIGSEGV);
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index e2101a6..dd37cdb 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -39,4 +39,6 @@
 b/22777307
 b/22881413
 b/20843113
+b/23201502 (float)
+b/23201502 (double)
 Done!
diff --git a/test/800-smali/smali/b_23201502.smali b/test/800-smali/smali/b_23201502.smali
new file mode 100644
index 0000000..d958938
--- /dev/null
+++ b/test/800-smali/smali/b_23201502.smali
@@ -0,0 +1,23 @@
+.class public LB23201502;
+
+.super Ljava/lang/Object;
+
+.method public static runFloat()V
+   .registers 3
+   const v0, 0             # Null array.
+   const v1, 0             # 0 index into array.
+   const v2, 0             # 0 value, will be turned into float.
+   int-to-float v2, v2     # Definitely make v2 float.
+   aput v2 , v0, v1        # Put into null array.
+   return-void
+.end method
+
+.method public static runDouble()V
+   .registers 4
+   const v0, 0             # Null array.
+   const v1, 0             # 0 index into array.
+   const v2, 0             # 0 value, will be turned into double.
+   int-to-double v2, v2    # Definitely make v2+v3 double.
+   aput-wide v2 , v0, v1   # Put into null array.
+   return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 3c88040..b481a1d 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -123,6 +123,10 @@
                 null));
         testCases.add(new TestCase("b/22881413", "B22881413", "run", null, null, null));
         testCases.add(new TestCase("b/20843113", "B20843113", "run", null, null, null));
+        testCases.add(new TestCase("b/23201502 (float)", "B23201502", "runFloat", null,
+                new NullPointerException(), null));
+        testCases.add(new TestCase("b/23201502 (double)", "B23201502", "runDouble", null,
+                new NullPointerException(), null));
     }
 
     public void runTests() {