Merge "vixl32: do not use D14 as a temporary."
diff --git a/Android.mk b/Android.mk
index 0e86188..f8c5378 100644
--- a/Android.mk
+++ b/Android.mk
@@ -388,6 +388,7 @@
 # libstdc++ is needed when building for ART_TARGET_LINUX.
 ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so
 build-art-target-golem: dex2oat dalvikvm patchoat linker libstdc++ \
+                        $(TARGET_OUT_EXECUTABLES)/art \
                         $(TARGET_OUT)/etc/public.libraries.txt \
                         $(ART_TARGET_DEX_DEPENDENCIES) \
                         $(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 1591e34..27ec8b3 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -54,11 +54,11 @@
 ART_TEST_QUIET ?= true
 
 # Do you want interpreter tests run?
-ART_TEST_INTERPRETER ?= $(ART_TEST_FULL)
-ART_TEST_INTERPRETER_ACCESS_CHECKS ?= $(ART_TEST_FULL)
+ART_TEST_INTERPRETER ?= true
+ART_TEST_INTERPRETER_ACCESS_CHECKS ?= true
 
 # Do you want JIT tests run?
-ART_TEST_JIT ?= $(ART_TEST_FULL)
+ART_TEST_JIT ?= true
 
 # Do you want optimizing compiler tests run?
 ART_TEST_OPTIMIZING ?= true
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 4814b22..5246dbc 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -5110,12 +5110,34 @@
   }
 }
 
-void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet*) {
-  UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64";
+void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
 }
 
-void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet*) {
-  UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64";
+void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
+    uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+        instruction->GetIndex(), kMips64PointerSize).SizeValue();
+    __ LoadFromOffset(kLoadDoubleword,
+                      locations->Out().AsRegister<GpuRegister>(),
+                      locations->InAt(0).AsRegister<GpuRegister>(),
+                      method_offset);
+  } else {
+    uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+        instruction->GetIndex(), kMips64PointerSize));
+    __ LoadFromOffset(kLoadDoubleword,
+                      locations->Out().AsRegister<GpuRegister>(),
+                      locations->InAt(0).AsRegister<GpuRegister>(),
+                      mirror::Class::ImtPtrOffset(kMips64PointerSize).Uint32Value());
+    __ LoadFromOffset(kLoadDoubleword,
+                      locations->Out().AsRegister<GpuRegister>(),
+                      locations->Out().AsRegister<GpuRegister>(),
+                      method_offset);
+  }
 }
 
 }  // namespace mips64
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 583008b..8a813bd 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -892,10 +892,6 @@
     return false;
   }
 
-  if (graph_->GetInstructionSet() == kMips64) {
-    // TODO: Support HClassTableGet for mips64.
-    return false;
-  }
   ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
   PointerSize pointer_size = class_linker->GetImagePointerSize();
 
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 6a57f45..5307dc0 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1169,6 +1169,32 @@
 }
 
 
+void X86Assembler::andnpd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x55);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::andnps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x55);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pandn(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0xDF);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
 void X86Assembler::orpd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
@@ -1195,6 +1221,43 @@
 }
 
 
+void X86Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x74);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x75);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x76);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x38);
+  EmitUint8(0x29);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
 void X86Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index e3c123c..f52cf16 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -487,10 +487,19 @@
   void andps(XmmRegister dst, const Address& src);
   void pand(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
 
+  void andnpd(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
+  void andnps(XmmRegister dst, XmmRegister src);
+  void pandn(XmmRegister dst, XmmRegister src);
+
   void orpd(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
   void orps(XmmRegister dst, XmmRegister src);
   void por(XmmRegister dst, XmmRegister src);
 
+  void pcmpeqb(XmmRegister dst, XmmRegister src);
+  void pcmpeqw(XmmRegister dst, XmmRegister src);
+  void pcmpeqd(XmmRegister dst, XmmRegister src);
+  void pcmpeqq(XmmRegister dst, XmmRegister src);
+
   void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm);
   void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm);
   void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm);
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 110d0dc..2304907 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -581,6 +581,18 @@
   DriverStr(RepeatFF(&x86::X86Assembler::pand, "pand %{reg2}, %{reg1}"), "pand");
 }
 
+TEST_F(AssemblerX86Test, AndnPD) {
+  DriverStr(RepeatFF(&x86::X86Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd");
+}
+
+TEST_F(AssemblerX86Test, AndnPS) {
+  DriverStr(RepeatFF(&x86::X86Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps");
+}
+
+TEST_F(AssemblerX86Test, PAndn) {
+  DriverStr(RepeatFF(&x86::X86Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn");
+}
+
 TEST_F(AssemblerX86Test, OrPD) {
   DriverStr(RepeatFF(&x86::X86Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd");
 }
@@ -593,6 +605,22 @@
   DriverStr(RepeatFF(&x86::X86Assembler::por, "por %{reg2}, %{reg1}"), "por");
 }
 
+TEST_F(AssemblerX86Test, PCmpeqB) {
+  DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "cmpeqb");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqW) {
+  DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "cmpeqw");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqD) {
+  DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "cmpeqd");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqQ) {
+  DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "cmpeqq");
+}
+
 TEST_F(AssemblerX86Test, ShufPS) {
   DriverStr(RepeatFFI(&x86::X86Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
 }
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 688fdcc..d20a696 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1375,6 +1375,32 @@
   EmitXmmRegisterOperand(dst.LowBits(), src);
 }
 
+void X86_64Assembler::andnpd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x55);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::andnps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x55);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pandn(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xDF);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
 void X86_64Assembler::orpd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
@@ -1401,6 +1427,43 @@
   EmitXmmRegisterOperand(dst.LowBits(), src);
 }
 
+void X86_64Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x74);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x75);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x76);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x38);
+  EmitUint8(0x29);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
 void X86_64Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 480e711..08e17e8 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -515,10 +515,19 @@
   void andps(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
   void pand(XmmRegister dst, XmmRegister src);
 
+  void andnpd(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
+  void andnps(XmmRegister dst, XmmRegister src);
+  void pandn(XmmRegister dst, XmmRegister src);
+
   void orpd(XmmRegister dst, XmmRegister src);  // no addr variant (for now)
   void orps(XmmRegister dst, XmmRegister src);
   void por(XmmRegister dst, XmmRegister src);
 
+  void pcmpeqb(XmmRegister dst, XmmRegister src);
+  void pcmpeqw(XmmRegister dst, XmmRegister src);
+  void pcmpeqd(XmmRegister dst, XmmRegister src);
+  void pcmpeqq(XmmRegister dst, XmmRegister src);
+
   void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm);
   void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm);
   void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index ba011c9..20062fd 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1269,6 +1269,18 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::pand, "pand %{reg2}, %{reg1}"), "pand");
 }
 
+TEST_F(AssemblerX86_64Test, andnpd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd");
+}
+
+TEST_F(AssemblerX86_64Test, andnps) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps");
+}
+
+TEST_F(AssemblerX86_64Test, Pandn) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn");
+}
+
 TEST_F(AssemblerX86_64Test, Orps) {
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::orps, "orps %{reg2}, %{reg1}"), "orps");
 }
@@ -1281,6 +1293,22 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::por, "por %{reg2}, %{reg1}"), "por");
 }
 
+TEST_F(AssemblerX86_64Test, PCmpeqb) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "pcmpeqb");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqw) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "pcmpeqw");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "pcmpeqd");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqq) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "pcmpeqq");
+}
+
 TEST_F(AssemblerX86_64Test, Shufps) {
   DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
 }
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 01c3359..1a1d163 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -714,12 +714,12 @@
 
 TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInReferenced) {
   ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInReferenced"));
-  ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public final"));
+  ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public"));
   ASSERT_TRUE(HasField("Ljava/lang/System;",
                        "out",
                        "Ljava/io/PrintStream;",
                        true,
-                       "public final static",
+                       "public static",
                        "Ljava/lang/System;"));
 }
 
@@ -727,13 +727,13 @@
   ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass1"));
   ASSERT_TRUE(HasClass("Ljava/util/SimpleTimeZone;", true, "public"));
   ASSERT_TRUE(HasField(
-      "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public final static", "Ljava/util/TimeZone;"));
+      "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public static", "Ljava/util/TimeZone;"));
 }
 
 TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass2) {
   ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass2"));
   ASSERT_TRUE(HasField(
-      "LMySimpleTimeZone;", "SHORT", "I", true, "public final static", "Ljava/util/TimeZone;"));
+      "LMySimpleTimeZone;", "SHORT", "I", true, "public static", "Ljava/util/TimeZone;"));
 }
 
 TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface1) {
@@ -743,7 +743,7 @@
                        "PI_ENABLE_OUTPUT_ESCAPING",
                        "Ljava/lang/String;",
                        true,
-                       "public final static",
+                       "public static",
                        "Ljavax/xml/transform/Result;"));
 }
 
@@ -753,7 +753,7 @@
                        "PI_ENABLE_OUTPUT_ESCAPING",
                        "Ljava/lang/String;",
                        true,
-                       "public final static",
+                       "public static",
                        "Ljavax/xml/transform/Result;"));
 }
 
@@ -763,7 +763,7 @@
                        "PI_ENABLE_OUTPUT_ESCAPING",
                        "Ljava/lang/String;",
                        true,
-                       "public final static",
+                       "public static",
                        "Ljavax/xml/transform/Result;"));
 }
 
@@ -773,13 +773,13 @@
                        "ELEMENT_NODE",
                        "S",
                        true,
-                       "public final static",
+                       "public static",
                        "Lorg/w3c/dom/Node;"));
 }
 
 TEST_F(VerifierDepsTest, StaticField_Unresolved_ReferrerInBoot) {
   ASSERT_TRUE(VerifyMethod("StaticField_Unresolved_ReferrerInBoot"));
-  ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public abstract"));
+  ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public"));
   ASSERT_TRUE(HasField("Ljava/util/TimeZone;", "x", "I", false));
 }
 
@@ -851,7 +851,7 @@
 
 TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass1) {
   ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass1"));
-  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
   ASSERT_TRUE(HasMethod("direct",
                         "Ljavax/net/ssl/SSLSocket;",
                         "setSocketImplFactory",
@@ -874,7 +874,7 @@
 
 TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface1) {
   ASSERT_TRUE(VerifyMethod("InvokeStatic_DeclaredInInterface1"));
-  ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public abstract interface"));
+  ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public interface"));
   ASSERT_TRUE(HasMethod("direct",
                         "Ljava/util/Map$Entry;",
                         "comparingByKey",
@@ -896,7 +896,7 @@
 
 TEST_F(VerifierDepsTest, InvokeStatic_Unresolved1) {
   ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved1"));
-  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
   ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
 }
 
@@ -914,7 +914,7 @@
 
 TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass1) {
   ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass1"));
-  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
   ASSERT_TRUE(HasMethod("direct",
                         "Ljavax/net/ssl/SSLSocket;",
                         "checkOldImpl",
@@ -932,7 +932,7 @@
 
 TEST_F(VerifierDepsTest, InvokeDirect_Unresolved1) {
   ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved1"));
-  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+  ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
   ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
 }
 
@@ -987,7 +987,7 @@
                         "size",
                         "()I",
                         true,
-                        "public abstract",
+                        "public",
                         "Ljava/util/Set;"));
 }
 
@@ -1016,13 +1016,13 @@
 
 TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInReferenced) {
   ASSERT_TRUE(VerifyMethod("InvokeInterface_Resolved_DeclaredInReferenced"));
-  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
   ASSERT_TRUE(HasMethod("interface",
                         "Ljava/lang/Runnable;",
                         "run",
                         "()V",
                         true,
-                        "public abstract",
+                        "public",
                         "Ljava/lang/Runnable;"));
 }
 
@@ -1038,7 +1038,7 @@
                         "run",
                         "()V",
                         true,
-                        "public abstract",
+                        "public",
                         "Ljava/lang/Runnable;"));
 }
 
@@ -1049,13 +1049,13 @@
                         "isEmpty",
                         "()Z",
                         true,
-                        "public abstract",
+                        "public",
                         "Ljava/util/Set;"));
 }
 
 TEST_F(VerifierDepsTest, InvokeInterface_Unresolved1) {
   ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved1"));
-  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
   ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "x", "()V", false));
 }
 
@@ -1066,20 +1066,20 @@
 
 TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) {
   ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable"));
-  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+  ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
   ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;", "Ljava/lang/Thread;", true));
   ASSERT_TRUE(HasMethod("interface",
                         "Ljava/lang/Runnable;",
                         "run",
                         "()V",
                         true,
-                        "public abstract",
+                        "public",
                         "Ljava/lang/Runnable;"));
 }
 
 TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) {
   ASSERT_FALSE(VerifyMethod("InvokeSuper_ThisNotAssignable"));
-  ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public final"));
+  ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public"));
   ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "Ljava/lang/Thread;", false));
   ASSERT_TRUE(HasMethod(
       "virtual", "Ljava/lang/Integer;", "intValue", "()I", true, "public", "Ljava/lang/Integer;"));
@@ -1087,12 +1087,12 @@
 
 TEST_F(VerifierDepsTest, ArgumentType_ResolvedReferenceArray) {
   ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedReferenceArray"));
-  ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public final abstract"));
+  ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public"));
 }
 
 TEST_F(VerifierDepsTest, NewArray_Resolved) {
   ASSERT_TRUE(VerifyMethod("NewArray_Resolved"));
-  ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public final abstract"));
+  ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public"));
 }
 
 TEST_F(VerifierDepsTest, EncodeDecode) {
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 96afb90..78ddde8 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -748,8 +748,7 @@
   const TypeId* ClassType() const { return class_type_; }
   uint32_t GetAccessFlags() const { return access_flags_; }
   const TypeId* Superclass() const { return superclass_; }
-  const TypeIdVector* Interfaces()
-      { return interfaces_ == nullptr ? nullptr : interfaces_->GetTypeList(); }
+  const TypeList* Interfaces() { return interfaces_; }
   uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); }
   const StringId* SourceFile() const { return source_file_; }
   AnnotationsDirectoryItem* Annotations() const { return annotations_; }
@@ -781,7 +780,7 @@
   uint32_t GetAddress() const { return address_; }
 
  private:
-  const TypeId* type_id_;
+  const TypeId* type_id_;  // This can be nullptr.
   uint32_t address_;
 
   DISALLOW_COPY_AND_ASSIGN(TypeAddrPair);
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index aec1d0c..5458129 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -20,6 +20,8 @@
 
 #include "dex_verify.h"
 
+#include <inttypes.h>
+
 #include "android-base/stringprintf.h"
 
 namespace art {
@@ -32,7 +34,7 @@
   dex_ir::Collections& orig = orig_header->GetCollections();
   dex_ir::Collections& output = output_header->GetCollections();
 
-  // Compare all id sections.
+  // Compare all id sections. They have a defined order that can't be changed by dexlayout.
   if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
       !VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
       !VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
@@ -40,6 +42,10 @@
       !VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
     return false;
   }
+  // Compare class defs. The order may have been changed by dexlayout.
+  if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
+    return false;
+  }
   return true;
 }
 
@@ -49,7 +55,7 @@
                                  std::string* error_msg) {
   if (orig.size() != output.size()) {
     *error_msg = StringPrintf(
-        "Mismatched size for %s section, %zu vs %zu.", section_name, orig.size(), output.size());
+        "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
     return false;
   }
   for (size_t i = 0; i < orig.size(); ++i) {
@@ -62,7 +68,7 @@
 
 bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) {
   if (strcmp(orig->Data(), output->Data()) != 0) {
-    *error_msg = StringPrintf("Mismatched string data for string id %u @ orig offset %x, %s vs %s.",
+    *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Data(),
@@ -74,7 +80,7 @@
 
 bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) {
   if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched string index for type id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->GetStringId()->GetIndex(),
@@ -86,7 +92,7 @@
 
 bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) {
   if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched string index for proto id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Shorty()->GetIndex(),
@@ -94,7 +100,7 @@
     return false;
   }
   if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched type index for proto id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->ReturnType()->GetIndex(),
@@ -102,7 +108,7 @@
     return false;
   }
   if (!VerifyTypeList(orig->Parameters(), output->Parameters())) {
-    *error_msg = StringPrintf("Mismatched type list for proto id %u @ orig offset %x.",
+    *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.",
                               orig->GetIndex(),
                               orig->GetOffset());
   }
@@ -112,7 +118,7 @@
 bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) {
   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
     *error_msg =
-        StringPrintf("Mismatched class type index for field id %u @ orig offset %x, %u vs %u.",
+        StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.",
                      orig->GetIndex(),
                      orig->GetOffset(),
                      orig->Class()->GetIndex(),
@@ -120,7 +126,7 @@
     return false;
   }
   if (orig->Type()->GetIndex() != output->Type()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched type index for field id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Class()->GetIndex(),
@@ -128,7 +134,7 @@
     return false;
   }
   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched string index for field id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Name()->GetIndex(),
@@ -140,7 +146,7 @@
 
 bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) {
   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched type index for method id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Class()->GetIndex(),
@@ -148,7 +154,7 @@
     return false;
   }
   if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) {
-    *error_msg = StringPrintf("Mismatched proto index for method id %u @ orig offset %x, %u vs %u.",
+    *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.",
                               orig->GetIndex(),
                               orig->GetOffset(),
                               orig->Class()->GetIndex(),
@@ -157,7 +163,7 @@
   }
   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
     *error_msg =
-        StringPrintf("Mismatched string index for method id %u @ orig offset %x, %u vs %u.",
+        StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.",
                      orig->GetIndex(),
                      orig->GetOffset(),
                      orig->Name()->GetIndex(),
@@ -167,6 +173,96 @@
   return true;
 }
 
+struct ClassDefCompare {
+  bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const {
+    return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex();
+  }
+};
+
+// The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
+// identify them and sort them for comparison.
+bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
+                     std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+                     std::string* error_msg) {
+  if (orig.size() != output.size()) {
+    *error_msg = StringPrintf(
+        "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
+    return false;
+  }
+  // Store the class defs into sets sorted by the class's type index.
+  std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
+  std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
+  for (size_t i = 0; i < orig.size(); ++i) {
+    orig_set.insert(orig[i].get());
+    output_set.insert(output[i].get());
+  }
+  auto orig_iter = orig_set.begin();
+  auto output_iter = output_set.begin();
+  while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
+    if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
+      return false;
+    }
+    orig_iter++;
+    output_iter++;
+  }
+  return true;
+}
+
+bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) {
+  if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) {
+    *error_msg =
+        StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.",
+                     orig->GetIndex(),
+                     orig->GetOffset(),
+                     orig->ClassType()->GetIndex(),
+                     output->ClassType()->GetIndex());
+    return false;
+  }
+  if (orig->GetAccessFlags() != output->GetAccessFlags()) {
+    *error_msg =
+        StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.",
+                     orig->GetIndex(),
+                     orig->GetOffset(),
+                     orig->GetAccessFlags(),
+                     output->GetAccessFlags());
+    return false;
+  }
+  uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex();
+  uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex();
+  if (orig_super != output_super) {
+    *error_msg =
+        StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.",
+                     orig->GetIndex(),
+                     orig->GetOffset(),
+                     orig_super,
+                     output_super);
+    return false;
+  }
+  if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) {
+    *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.",
+                              orig->GetIndex(),
+                              orig->GetOffset());
+    return false;
+  }
+  const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data();
+  const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data();
+  if (strcmp(orig_source, output_source) != 0) {
+    *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.",
+                              orig->GetIndex(),
+                              orig->GetOffset(),
+                              orig_source,
+                              output_source);
+    return false;
+  }
+  if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) {
+    return false;
+  }
+  if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) {
+    return false;
+  }
+  return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg);
+}
+
 bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) {
   if (orig == nullptr || output == nullptr) {
     return orig == output;
@@ -184,4 +280,841 @@
   return true;
 }
 
+bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
+                                dex_ir::AnnotationsDirectoryItem* output,
+                                std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty annotations directory.";
+      return false;
+    }
+    return true;
+  }
+  if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) {
+    return false;
+  }
+  if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(),
+                              output->GetFieldAnnotations(),
+                              orig->GetOffset(),
+                              error_msg)) {
+    return false;
+  }
+  if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(),
+                               output->GetMethodAnnotations(),
+                               orig->GetOffset(),
+                               error_msg)) {
+    return false;
+  }
+  return VerifyParameterAnnotations(orig->GetParameterAnnotations(),
+                                    output->GetParameterAnnotations(),
+                                    orig->GetOffset(),
+                                    error_msg);
+}
+
+bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
+                            dex_ir::FieldAnnotationVector* output,
+                            uint32_t orig_offset,
+                            std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = StringPrintf(
+          "Found unexpected empty field annotations for annotations directory at offset %x.",
+          orig_offset);
+      return false;
+    }
+    return true;
+  }
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig->size(),
+        output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    dex_ir::FieldAnnotation* orig_field = (*orig)[i].get();
+    dex_ir::FieldAnnotation* output_field = (*output)[i].get();
+    if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
+      *error_msg = StringPrintf(
+          "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.",
+          orig_offset,
+          orig_field->GetFieldId()->GetIndex(),
+          output_field->GetFieldId()->GetIndex());
+      return false;
+    }
+    if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(),
+                             output_field->GetAnnotationSetItem(),
+                             error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
+                             dex_ir::MethodAnnotationVector* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = StringPrintf(
+          "Found unexpected empty method annotations for annotations directory at offset %x.",
+          orig_offset);
+      return false;
+    }
+    return true;
+  }
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig->size(),
+        output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    dex_ir::MethodAnnotation* orig_method = (*orig)[i].get();
+    dex_ir::MethodAnnotation* output_method = (*output)[i].get();
+    if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
+      *error_msg = StringPrintf(
+          "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.",
+          orig_offset,
+          orig_method->GetMethodId()->GetIndex(),
+          output_method->GetMethodId()->GetIndex());
+      return false;
+    }
+    if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(),
+                             output_method->GetAnnotationSetItem(),
+                             error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
+                                dex_ir::ParameterAnnotationVector* output,
+                                uint32_t orig_offset,
+                                std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = StringPrintf(
+          "Found unexpected empty parameter annotations for annotations directory at offset %x.",
+          orig_offset);
+      return false;
+    }
+    return true;
+  }
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig->size(),
+        output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get();
+    dex_ir::ParameterAnnotation* output_param = (*output)[i].get();
+    if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) {
+      *error_msg = StringPrintf(
+          "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.",
+          orig_offset,
+          orig_param->GetMethodId()->GetIndex(),
+          output_param->GetMethodId()->GetIndex());
+      return false;
+    }
+    if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(),
+                                    output_param->GetAnnotations(),
+                                    error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
+                                dex_ir::AnnotationSetRefList* output,
+                                std::string* error_msg) {
+  std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems();
+  std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems();
+  if (orig_items->size() != output_items->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched annotation set ref list size at offset %x: %zu vs %zu.",
+        orig->GetOffset(),
+        orig_items->size(),
+        output_items->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig_items->size(); ++i) {
+    if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
+                         dex_ir::AnnotationSetItem* output,
+                         std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty annotation set.";
+      return false;
+    }
+    return true;
+  }
+  std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems();
+  std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems();
+  if (orig_items->size() != output_items->size()) {
+    *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.",
+                              orig->GetOffset(),
+                              orig_items->size(),
+                              output_items->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig_items->size(); ++i) {
+    if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
+                      dex_ir::AnnotationItem* output,
+                      std::string* error_msg) {
+  if (orig->GetVisibility() != output->GetVisibility()) {
+    *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->GetVisibility(),
+                              output->GetVisibility());
+    return false;
+  }
+  return VerifyEncodedAnnotation(orig->GetAnnotation(),
+                                 output->GetAnnotation(),
+                                 orig->GetOffset(),
+                                 error_msg);
+}
+
+bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
+                             dex_ir::EncodedAnnotation* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg) {
+  if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) {
+    *error_msg = StringPrintf(
+        "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.",
+        orig_offset,
+        orig->GetType()->GetIndex(),
+        output->GetType()->GetIndex());
+    return false;
+  }
+  dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements();
+  dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements();
+  if (orig_elements->size() != output_elements->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig_elements->size(),
+        output_elements->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig_elements->size(); ++i) {
+    if (!VerifyAnnotationElement((*orig_elements)[i].get(),
+                                 (*output_elements)[i].get(),
+                                 orig_offset,
+                                 error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
+                             dex_ir::AnnotationElement* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg) {
+  if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) {
+    *error_msg = StringPrintf(
+        "Mismatched annotation element name for annotation at offset %x: %u vs %u.",
+        orig_offset,
+        orig->GetName()->GetIndex(),
+        output->GetName()->GetIndex());
+    return false;
+  }
+  return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg);
+}
+
+bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
+                        dex_ir::EncodedValue* output,
+                        uint32_t orig_offset,
+                        std::string* error_msg) {
+  if (orig->Type() != output->Type()) {
+    *error_msg = StringPrintf(
+        "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.",
+        orig_offset,
+        orig->Type(),
+        output->Type());
+    return false;
+  }
+  switch (orig->Type()) {
+    case DexFile::kDexAnnotationByte:
+      if (orig->GetByte() != output->GetByte()) {
+        *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.",
+                                  orig_offset,
+                                  orig->GetByte(),
+                                  output->GetByte());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationShort:
+      if (orig->GetShort() != output->GetShort()) {
+        *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.",
+                                  orig_offset,
+                                  orig->GetShort(),
+                                  output->GetShort());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationChar:
+      if (orig->GetChar() != output->GetChar()) {
+        *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.",
+                                  orig_offset,
+                                  orig->GetChar(),
+                                  output->GetChar());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationInt:
+      if (orig->GetInt() != output->GetInt()) {
+        *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.",
+                                  orig_offset,
+                                  orig->GetInt(),
+                                  output->GetInt());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationLong:
+      if (orig->GetLong() != output->GetLong()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".",
+            orig_offset,
+            orig->GetLong(),
+            output->GetLong());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationFloat:
+      // The float value is encoded, so compare as if it's an int.
+      if (orig->GetInt() != output->GetInt()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).",
+                                  orig_offset,
+                                  orig->GetInt(),
+                                  output->GetInt());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationDouble:
+      // The double value is encoded, so compare as if it's a long.
+      if (orig->GetLong() != output->GetLong()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded double for annotation at offset %x: %" PRIx64
+            " (encoded) vs %" PRIx64 " (encoded).",
+            orig_offset,
+            orig->GetLong(),
+            output->GetLong());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationString:
+      if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded string for annotation at offset %x: %s vs %s.",
+            orig_offset,
+            orig->GetStringId()->Data(),
+            output->GetStringId()->Data());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationType:
+      if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) {
+        *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.",
+                                  orig_offset,
+                                  orig->GetTypeId()->GetIndex(),
+                                  output->GetTypeId()->GetIndex());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum:
+      if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) {
+        *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.",
+                                  orig_offset,
+                                  orig->GetFieldId()->GetIndex(),
+                                  output->GetFieldId()->GetIndex());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationMethod:
+      if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded method for annotation at offset %x: %u vs %u.",
+            orig_offset,
+            orig->GetMethodId()->GetIndex(),
+            output->GetMethodId()->GetIndex());
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationArray:
+      if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) {
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationAnnotation:
+      if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(),
+                                   output->GetEncodedAnnotation(),
+                                   orig_offset,
+                                   error_msg)) {
+        return false;
+      }
+      break;
+    case DexFile::kDexAnnotationNull:
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      if (orig->GetBoolean() != output->GetBoolean()) {
+        *error_msg = StringPrintf(
+            "Mismatched encoded boolean for annotation at offset %x: %d vs %d.",
+            orig_offset,
+            orig->GetBoolean(),
+            output->GetBoolean());
+        return false;
+      }
+      break;
+    default:
+      break;
+  }
+  return true;
+}
+
+bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
+                        dex_ir::EncodedArrayItem* output,
+                        std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty encoded array.";
+      return false;
+    }
+    return true;
+  }
+  dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues();
+  dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues();
+  if (orig_vector->size() != output_vector->size()) {
+    *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.",
+                              orig->GetOffset(),
+                              orig_vector->size(),
+                              output_vector->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig_vector->size(); ++i) {
+    if (!VerifyEncodedValue((*orig_vector)[i].get(),
+                            (*output_vector)[i].get(),
+                            orig->GetOffset(),
+                            error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty class data.";
+      return false;
+    }
+    return true;
+  }
+  if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) {
+    return false;
+  }
+  if (!VerifyFields(orig->InstanceFields(),
+                    output->InstanceFields(),
+                    orig->GetOffset(),
+                    error_msg)) {
+    return false;
+  }
+  if (!VerifyMethods(orig->DirectMethods(),
+                     output->DirectMethods(),
+                     orig->GetOffset(),
+                     error_msg)) {
+    return false;
+  }
+  return VerifyMethods(orig->VirtualMethods(),
+                       output->VirtualMethods(),
+                       orig->GetOffset(),
+                       error_msg);
+}
+
+bool VerifyFields(dex_ir::FieldItemVector* orig,
+                  dex_ir::FieldItemVector* output,
+                  uint32_t orig_offset,
+                  std::string* error_msg) {
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.",
+                              orig_offset,
+                              orig->size(),
+                              output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    dex_ir::FieldItem* orig_field = (*orig)[i].get();
+    dex_ir::FieldItem* output_field = (*output)[i].get();
+    if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
+      *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.",
+                                orig_offset,
+                                orig_field->GetFieldId()->GetIndex(),
+                                output_field->GetFieldId()->GetIndex());
+      return false;
+    }
+    if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) {
+      *error_msg = StringPrintf(
+          "Mismatched field access flags for class data at offset %x: %u vs %u.",
+          orig_offset,
+          orig_field->GetAccessFlags(),
+          output_field->GetAccessFlags());
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyMethods(dex_ir::MethodItemVector* orig,
+                   dex_ir::MethodItemVector* output,
+                   uint32_t orig_offset,
+                   std::string* error_msg) {
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.",
+                              orig_offset,
+                              orig->size(),
+                              output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    dex_ir::MethodItem* orig_method = (*orig)[i].get();
+    dex_ir::MethodItem* output_method = (*output)[i].get();
+    if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
+      *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.",
+                                orig_offset,
+                                orig_method->GetMethodId()->GetIndex(),
+                                output_method->GetMethodId()->GetIndex());
+      return false;
+    }
+    if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) {
+      *error_msg = StringPrintf(
+          "Mismatched method access flags for class data at offset %x: %u vs %u.",
+          orig_offset,
+          orig_method->GetAccessFlags(),
+          output_method->GetAccessFlags());
+      return false;
+    }
+    if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty code item.";
+      return false;
+    }
+    return true;
+  }
+  if (orig->RegistersSize() != output->RegistersSize()) {
+    *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->RegistersSize(),
+                              output->RegistersSize());
+    return false;
+  }
+  if (orig->InsSize() != output->InsSize()) {
+    *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->InsSize(),
+                              output->InsSize());
+    return false;
+  }
+  if (orig->OutsSize() != output->OutsSize()) {
+    *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->OutsSize(),
+                              output->OutsSize());
+    return false;
+  }
+  if (orig->TriesSize() != output->TriesSize()) {
+    *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->TriesSize(),
+                              output->TriesSize());
+    return false;
+  }
+  if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) {
+    return false;
+  }
+  if (orig->InsnsSize() != output->InsnsSize()) {
+    *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.",
+                              orig->GetOffset(),
+                              orig->InsnsSize(),
+                              output->InsnsSize());
+    return false;
+  }
+  if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) {
+    *error_msg = StringPrintf("Mismatched insns for code item at offset %x.",
+                              orig->GetOffset());
+    return false;
+  }
+  if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) {
+    return false;
+  }
+  return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg);
+}
+
+bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
+                     dex_ir::DebugInfoItem* output,
+                     std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty debug info.";
+      return false;
+    }
+    return true;
+  }
+  if (!VerifyPositionInfo(orig->GetPositionInfo(),
+                          output->GetPositionInfo(),
+                          orig->GetOffset(),
+                          error_msg)) {
+    return false;
+  }
+  return VerifyLocalInfo(orig->GetLocalInfo(),
+                         output->GetLocalInfo(),
+                         orig->GetOffset(),
+                         error_msg);
+}
+
+bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
+                        dex_ir::PositionInfoVector& output,
+                        uint32_t orig_offset,
+                        std::string* error_msg) {
+  if (orig.size() != output.size()) {
+    *error_msg = StringPrintf(
+        "Mismatched number of positions for debug info at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig.size(),
+        output.size());
+    return false;
+  }
+  for (size_t i = 0; i < orig.size(); ++i) {
+    if (orig[i]->address_ != output[i]->address_) {
+      *error_msg = StringPrintf(
+          "Mismatched position address for debug info at offset %x: %u vs %u.",
+          orig_offset,
+          orig[i]->address_,
+          output[i]->address_);
+      return false;
+    }
+    if (orig[i]->line_ != output[i]->line_) {
+      *error_msg = StringPrintf("Mismatched position line for debug info at offset %x: %u vs %u.",
+                                orig_offset,
+                                orig[i]->line_,
+                                output[i]->line_);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
+                     dex_ir::LocalInfoVector& output,
+                     uint32_t orig_offset,
+                     std::string* error_msg) {
+  if (orig.size() != output.size()) {
+    *error_msg = StringPrintf(
+        "Mismatched number of locals for debug info at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig.size(),
+        output.size());
+    return false;
+  }
+  for (size_t i = 0; i < orig.size(); ++i) {
+    if (orig[i]->name_ != output[i]->name_) {
+      *error_msg = StringPrintf("Mismatched local name for debug info at offset %x: %s vs %s.",
+                                orig_offset,
+                                orig[i]->name_.c_str(),
+                                output[i]->name_.c_str());
+      return false;
+    }
+    if (orig[i]->descriptor_ != output[i]->descriptor_) {
+      *error_msg = StringPrintf(
+          "Mismatched local descriptor for debug info at offset %x: %s vs %s.",
+          orig_offset,
+          orig[i]->descriptor_.c_str(),
+          output[i]->descriptor_.c_str());
+      return false;
+    }
+    if (orig[i]->signature_ != output[i]->signature_) {
+      *error_msg = StringPrintf("Mismatched local signature for debug info at offset %x: %s vs %s.",
+                                orig_offset,
+                                orig[i]->signature_.c_str(),
+                                output[i]->signature_.c_str());
+      return false;
+    }
+    if (orig[i]->start_address_ != output[i]->start_address_) {
+      *error_msg = StringPrintf(
+          "Mismatched local start address for debug info at offset %x: %u vs %u.",
+          orig_offset,
+          orig[i]->start_address_,
+          output[i]->start_address_);
+      return false;
+    }
+    if (orig[i]->end_address_ != output[i]->end_address_) {
+      *error_msg = StringPrintf(
+          "Mismatched local end address for debug info at offset %x: %u vs %u.",
+          orig_offset,
+          orig[i]->end_address_,
+          output[i]->end_address_);
+      return false;
+    }
+    if (orig[i]->reg_ != output[i]->reg_) {
+      *error_msg = StringPrintf("Mismatched local reg for debug info at offset %x: %u vs %u.",
+                                orig_offset,
+                                orig[i]->reg_,
+                                output[i]->reg_);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyTries(dex_ir::TryItemVector* orig,
+                 dex_ir::TryItemVector* output,
+                 uint32_t orig_offset,
+                 std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty try items.";
+      return false;
+    }
+    return true;
+  }
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
+                              orig_offset,
+                              orig->size(),
+                              output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    const dex_ir::TryItem* orig_try = (*orig)[i].get();
+    const dex_ir::TryItem* output_try = (*output)[i].get();
+    if (orig_try->StartAddr() != output_try->StartAddr()) {
+      *error_msg = StringPrintf(
+          "Mismatched try item start addr for code item at offset %x: %u vs %u.",
+          orig_offset,
+          orig_try->StartAddr(),
+          output_try->StartAddr());
+      return false;
+    }
+    if (orig_try->InsnCount() != output_try->InsnCount()) {
+      *error_msg = StringPrintf(
+          "Mismatched try item insn count for code item at offset %x: %u vs %u.",
+          orig_offset,
+          orig_try->InsnCount(),
+                                output_try->InsnCount());
+      return false;
+    }
+    if (!VerifyHandler(orig_try->GetHandlers(),
+                       output_try->GetHandlers(),
+                       orig_offset,
+                       error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
+                    dex_ir::CatchHandlerVector* output,
+                    uint32_t orig_offset,
+                    std::string* error_msg) {
+  if (orig == nullptr || output == nullptr) {
+    if (orig != output) {
+      *error_msg = "Found unexpected empty catch handlers.";
+      return false;
+    }
+    return true;
+  }
+  if (orig->size() != output->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig->size(),
+        output->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig->size(); ++i) {
+    if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VerifyHandler(const dex_ir::CatchHandler* orig,
+                   const dex_ir::CatchHandler* output,
+                   uint32_t orig_offset,
+                   std::string* error_msg) {
+  dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
+  dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
+  if (orig_handlers->size() != output_handlers->size()) {
+    *error_msg = StringPrintf(
+        "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
+        orig_offset,
+        orig_handlers->size(),
+        output_handlers->size());
+    return false;
+  }
+  for (size_t i = 0; i < orig_handlers->size(); ++i) {
+    const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
+    const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
+    if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
+      if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
+        *error_msg = StringPrintf(
+            "Found unexpected catch all catch handler for code item at offset %x.",
+            orig_offset);
+        return false;
+      }
+    } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
+      *error_msg = StringPrintf(
+          "Mismatched catch handler type for code item at offset %x: %u vs %u.",
+          orig_offset,
+          orig_handler->GetTypeId()->GetIndex(),
+          output_handler->GetTypeId()->GetIndex());
+      return false;
+    }
+    if (orig_handler->GetAddress() != output_handler->GetAddress()) {
+      *error_msg = StringPrintf(
+          "Mismatched catch handler address for code item at offset %x: %u vs %u.",
+          orig_offset,
+          orig_handler->GetAddress(),
+          output_handler->GetAddress());
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace art
diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h
index a19431c..58c95d6 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -24,12 +24,12 @@
 #include "dex_ir.h"
 
 namespace art {
-
 // Check that the output dex file contains the same data as the original.
 // Compares the dex IR of both dex files. Allows the dex files to have different layouts.
 bool VerifyOutputDexFile(dex_ir::Header* orig_header,
                          dex_ir::Header* output_header,
                          std::string* error_msg);
+
 template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
                                  std::vector<std::unique_ptr<T>>& output,
                                  const char* section_name,
@@ -39,8 +39,87 @@
 bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg);
 bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg);
 bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg);
+
+bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
+                     std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+                     std::string* error_msg);
+bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg);
+
 bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output);
 
+bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
+                                dex_ir::AnnotationsDirectoryItem* output,
+                                std::string* error_msg);
+bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
+                            dex_ir::FieldAnnotationVector* output,
+                            uint32_t orig_offset,
+                            std::string* error_msg);
+bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
+                             dex_ir::MethodAnnotationVector* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg);
+bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
+                                dex_ir::ParameterAnnotationVector* output,
+                                uint32_t orig_offset,
+                                std::string* error_msg);
+bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
+                                dex_ir::AnnotationSetRefList* output,
+                                std::string* error_msg);
+bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
+                         dex_ir::AnnotationSetItem* output,
+                         std::string* error_msg);
+bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
+                      dex_ir::AnnotationItem* output,
+                      std::string* error_msg);
+bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
+                             dex_ir::EncodedAnnotation* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg);
+bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
+                             dex_ir::AnnotationElement* output,
+                             uint32_t orig_offset,
+                             std::string* error_msg);
+bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
+                        dex_ir::EncodedValue* output,
+                        uint32_t orig_offset,
+                        std::string* error_msg);
+bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
+                        dex_ir::EncodedArrayItem* output,
+                        std::string* error_msg);
+
+bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg);
+bool VerifyFields(dex_ir::FieldItemVector* orig,
+                  dex_ir::FieldItemVector* output,
+                  uint32_t orig_offset,
+                  std::string* error_msg);
+bool VerifyMethods(dex_ir::MethodItemVector* orig,
+                   dex_ir::MethodItemVector* output,
+                   uint32_t orig_offset,
+                   std::string* error_msg);
+bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg);
+bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
+                     dex_ir::DebugInfoItem* output,
+                     std::string* error_msg);
+bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
+                        dex_ir::PositionInfoVector& output,
+                        uint32_t orig_offset,
+                        std::string* error_msg);
+bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
+                     dex_ir::LocalInfoVector& output,
+                     uint32_t orig_offset,
+                     std::string* error_msg);
+bool VerifyTries(dex_ir::TryItemVector* orig,
+                 dex_ir::TryItemVector* output,
+                 uint32_t orig_offset,
+                 std::string* error_msg);
+bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
+                    dex_ir::CatchHandlerVector* output,
+                    uint32_t orig_offset,
+                    std::string* error_msg);
+bool VerifyHandler(const dex_ir::CatchHandler* orig,
+                   const dex_ir::CatchHandler* output,
+                   uint32_t orig_offset,
+                   std::string* error_msg);
 }  // namespace art
 
 #endif  // ART_DEXLAYOUT_DEX_VERIFY_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index a310424..615bcf9 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1369,10 +1369,11 @@
   }
 
   // Interfaces.
-  const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
+  const dex_ir::TypeList* interfaces = class_def->Interfaces();
   if (interfaces != nullptr) {
-    for (uint32_t i = 0; i < interfaces->size(); i++) {
-      DumpInterface((*interfaces)[i], i);
+    const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
+    for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
+      DumpInterface((*interfaces_vector)[i], i);
     }  // for
   }
 
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 685e26c..b47f8f0 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -347,7 +347,11 @@
 
 inline uint16_t ArtMethod::GetClassDefIndex() {
   DCHECK(!IsProxyMethod());
-  return GetDeclaringClass()->GetDexClassDefIndex();
+  if (LIKELY(!IsObsolete())) {
+    return GetDeclaringClass()->GetDexClassDefIndex();
+  } else {
+    return FindObsoleteDexClassDefIndex();
+  }
 }
 
 inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9d74e7c..80a8773 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -104,6 +104,16 @@
   UNREACHABLE();
 }
 
+uint16_t ArtMethod::FindObsoleteDexClassDefIndex() {
+  DCHECK(!Runtime::Current()->IsAotCompiler()) << PrettyMethod();
+  DCHECK(IsObsolete());
+  const DexFile* dex_file = GetDexFile();
+  const dex::TypeIndex declaring_class_type = dex_file->GetMethodId(GetDexMethodIndex()).class_idx_;
+  const DexFile::ClassDef* class_def = dex_file->FindClassDef(declaring_class_type);
+  CHECK(class_def != nullptr);
+  return dex_file->GetIndexForClassDef(*class_def);
+}
+
 mirror::String* ArtMethod::GetNameAsString(Thread* self) {
   CHECK(!IsProxyMethod());
   StackHandleScope<1> hs(self);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index cd1950c..2248c3b 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -700,6 +700,8 @@
   } ptr_sized_fields_;
 
  private:
+  uint16_t FindObsoleteDexClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_);
+
   bool IsAnnotatedWith(jclass klass, uint32_t visibility);
 
   static constexpr size_t PtrSizedFieldsOffset(PointerSize pointer_size) {
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index d39ea35..6b9654d 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -41,7 +41,80 @@
 };
 
 namespace {
-mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+
+// A helper class that contains all the data needed to do annotation lookup.
+class ClassData {
+ public:
+  explicit ClassData(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
+    : ClassData(ScopedNullHandle<mirror::Class>(),  // klass
+                method,
+                *method->GetDexFile(),
+                &method->GetClassDef()) {}
+
+  // Requires Scope to be able to create at least 1 handles.
+  template <typename Scope>
+  ClassData(Scope& hs, ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_)
+    : ClassData(hs.NewHandle(field->GetDeclaringClass())) { }
+
+  explicit ClassData(Handle<mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_)
+    : ClassData(klass,  // klass
+                nullptr,  // method
+                klass->GetDexFile(),
+                klass->GetClassDef()) {}
+
+  const DexFile& GetDexFile() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    return dex_file_;
+  }
+
+  const DexFile::ClassDef* GetClassDef() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    return class_def_;
+  }
+
+  ObjPtr<mirror::DexCache> GetDexCache() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (method_ != nullptr) {
+      return method_->GetDexCache();
+    } else {
+      return real_klass_->GetDexCache();
+    }
+  }
+
+  ObjPtr<mirror::ClassLoader> GetClassLoader() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (method_ != nullptr) {
+      return method_->GetDeclaringClass()->GetClassLoader();
+    } else {
+      return real_klass_->GetClassLoader();
+    }
+  }
+
+  ObjPtr<mirror::Class> GetRealClass() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (method_ != nullptr) {
+      return method_->GetDeclaringClass();
+    } else {
+      return real_klass_.Get();
+    }
+  }
+
+ private:
+  ClassData(Handle<mirror::Class> klass,
+            ArtMethod* method,
+            const DexFile& dex_file,
+            const DexFile::ClassDef* class_def) REQUIRES_SHARED(Locks::mutator_lock_)
+      : real_klass_(klass),
+        method_(method),
+        dex_file_(dex_file),
+        class_def_(class_def) {
+    DCHECK((method_ == nullptr) || real_klass_.IsNull());
+  }
+
+  Handle<mirror::Class> real_klass_;
+  ArtMethod* method_;
+  const DexFile& dex_file_;
+  const DexFile::ClassDef* class_def_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClassData);
+};
+
+mirror::Object* CreateAnnotationMember(const ClassData& klass,
                                        Handle<mirror::Class> annotation_class,
                                        const uint8_t** annotation)
     REQUIRES_SHARED(Locks::mutator_lock_);
@@ -185,9 +258,8 @@
 const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile* dex_file = method->GetDexFile();
-  mirror::Class* klass = method->GetDeclaringClass();
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
-      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+      dex_file->GetAnnotationsDirectory(method->GetClassDef());
   if (annotations_dir == nullptr) {
     return nullptr;
   }
@@ -209,9 +281,8 @@
 const DexFile::ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile* dex_file = method->GetDexFile();
-  mirror::Class* klass = method->GetDeclaringClass();
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
-      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+      dex_file->GetAnnotationsDirectory(method->GetClassDef());
   if (annotations_dir == nullptr) {
     return nullptr;
   }
@@ -230,30 +301,34 @@
   return nullptr;
 }
 
-const DexFile::AnnotationSetItem* FindAnnotationSetForClass(Handle<mirror::Class> klass)
+const DexFile::AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
-      dex_file.GetAnnotationsDirectory(*klass->GetClassDef());
+      dex_file.GetAnnotationsDirectory(*klass.GetClassDef());
   if (annotations_dir == nullptr) {
     return nullptr;
   }
   return dex_file.GetClassAnnotationSet(annotations_dir);
 }
 
-mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass, const uint8_t** annotation)
+mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** annotation)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   uint32_t type_index = DecodeUnsignedLeb128(annotation);
   uint32_t size = DecodeUnsignedLeb128(annotation);
 
   Thread* self = Thread::Current();
   ScopedObjectAccessUnchecked soa(self);
-  StackHandleScope<2> hs(self);
+  StackHandleScope<4> hs(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> annotation_class(hs.NewHandle(
-      class_linker->ResolveType(klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get())));
+      class_linker->ResolveType(klass.GetDexFile(),
+                                dex::TypeIndex(type_index),
+                                hs.NewHandle(klass.GetDexCache()),
+                                hs.NewHandle(klass.GetClassLoader()))));
   if (annotation_class == nullptr) {
-    LOG(INFO) << "Unable to resolve " << klass->PrettyClass() << " annotation class " << type_index;
+    LOG(INFO) << "Unable to resolve " << klass.GetRealClass()->PrettyClass()
+              << " annotation class " << type_index;
     DCHECK(Thread::Current()->IsExceptionPending());
     Thread::Current()->ClearException();
     return nullptr;
@@ -300,13 +375,13 @@
 }
 
 template <bool kTransactionActive>
-bool ProcessAnnotationValue(Handle<mirror::Class> klass,
+bool ProcessAnnotationValue(const ClassData& klass,
                             const uint8_t** annotation_ptr,
                             DexFile::AnnotationValue* annotation_value,
                             Handle<mirror::Class> array_class,
                             DexFile::AnnotationResultStyle result_style)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   Thread* self = Thread::Current();
   ObjPtr<mirror::Object> element_object = nullptr;
   bool set_object = false;
@@ -361,9 +436,8 @@
         annotation_value->value_.SetI(index);
       } else {
         StackHandleScope<1> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
         element_object = Runtime::Current()->GetClassLinker()->ResolveString(
-            klass->GetDexFile(), dex::StringIndex(index), dex_cache);
+            klass.GetDexFile(), dex::StringIndex(index), hs.NewHandle(klass.GetDexCache()));
         set_object = true;
         if (element_object == nullptr) {
           return false;
@@ -377,8 +451,12 @@
         annotation_value->value_.SetI(index);
       } else {
         dex::TypeIndex type_index(index);
+        StackHandleScope<2> hs(self);
         element_object = Runtime::Current()->GetClassLinker()->ResolveType(
-            klass->GetDexFile(), type_index, klass.Get());
+            klass.GetDexFile(),
+            type_index,
+            hs.NewHandle(klass.GetDexCache()),
+            hs.NewHandle(klass.GetClassLoader()));
         set_object = true;
         if (element_object == nullptr) {
           CHECK(self->IsExceptionPending());
@@ -399,12 +477,13 @@
       if (result_style == DexFile::kAllRaw) {
         annotation_value->value_.SetI(index);
       } else {
-        StackHandleScope<2> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
         ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+        StackHandleScope<2> hs(self);
         ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
-            klass->GetDexFile(), index, dex_cache, class_loader);
+            klass.GetDexFile(),
+            index,
+            hs.NewHandle(klass.GetDexCache()),
+            hs.NewHandle(klass.GetClassLoader()));
         if (method == nullptr) {
           return false;
         }
@@ -439,10 +518,11 @@
         annotation_value->value_.SetI(index);
       } else {
         StackHandleScope<2> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
         ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
-            klass->GetDexFile(), index, dex_cache, class_loader);
+            klass.GetDexFile(),
+            index,
+            hs.NewHandle(klass.GetDexCache()),
+            hs.NewHandle(klass.GetClassLoader()));
         if (field == nullptr) {
           return false;
         }
@@ -467,10 +547,12 @@
         annotation_value->value_.SetI(index);
       } else {
         StackHandleScope<3> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
         ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
-            klass->GetDexFile(), index, dex_cache, class_loader, true);
+            klass.GetDexFile(),
+            index,
+            hs.NewHandle(klass.GetDexCache()),
+            hs.NewHandle(klass.GetClassLoader()),
+            true);
         if (enum_field == nullptr) {
           return false;
         } else {
@@ -595,10 +677,10 @@
   return true;
 }
 
-mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+mirror::Object* CreateAnnotationMember(const ClassData& klass,
                                        Handle<mirror::Class> annotation_class,
                                        const uint8_t** annotation) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   Thread* self = Thread::Current();
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<5> hs(self);
@@ -666,12 +748,12 @@
 }
 
 const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet(
-    Handle<mirror::Class> klass,
+    const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set,
     uint32_t visibility,
     Handle<mirror::Class> annotation_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   for (uint32_t i = 0; i < annotation_set->size_; ++i) {
     const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i);
     if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
@@ -679,12 +761,16 @@
     }
     const uint8_t* annotation = annotation_item->annotation_;
     uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+    StackHandleScope<2> hs(Thread::Current());
     mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
-        klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get());
+        klass.GetDexFile(),
+        dex::TypeIndex(type_index),
+        hs.NewHandle(klass.GetDexCache()),
+        hs.NewHandle(klass.GetClassLoader()));
     if (resolved_class == nullptr) {
       std::string temp;
       LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
-                                   klass->GetDescriptor(&temp), type_index);
+                                   klass.GetRealClass()->GetDescriptor(&temp), type_index);
       CHECK(Thread::Current()->IsExceptionPending());
       Thread::Current()->ClearException();
       continue;
@@ -698,7 +784,7 @@
 }
 
 mirror::Object* GetAnnotationObjectFromAnnotationSet(
-    Handle<mirror::Class> klass,
+    const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set,
     uint32_t visibility,
     Handle<mirror::Class> annotation_class)
@@ -712,13 +798,13 @@
   return ProcessEncodedAnnotation(klass, &annotation);
 }
 
-mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass,
+mirror::Object* GetAnnotationValue(const ClassData& klass,
                                    const DexFile::AnnotationItem* annotation_item,
                                    const char* annotation_name,
                                    Handle<mirror::Class> array_class,
                                    uint32_t expected_type)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   const uint8_t* annotation =
       SearchEncodedAnnotation(dex_file, annotation_item->annotation_, annotation_name);
   if (annotation == nullptr) {
@@ -745,10 +831,10 @@
   return annotation_value.value_.GetL();
 }
 
-mirror::ObjectArray<mirror::String>* GetSignatureValue(Handle<mirror::Class> klass,
+mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   StackHandleScope<1> hs(Thread::Current());
   const DexFile::AnnotationItem* annotation_item =
       SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Signature;",
@@ -771,10 +857,10 @@
   return obj->AsObjectArray<mirror::String>();
 }
 
-mirror::ObjectArray<mirror::Class>* GetThrowsValue(Handle<mirror::Class> klass,
+mirror::ObjectArray<mirror::Class>* GetThrowsValue(const ClassData& klass,
                                                    const DexFile::AnnotationSetItem* annotation_set)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   StackHandleScope<1> hs(Thread::Current());
   const DexFile::AnnotationItem* annotation_item =
       SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;",
@@ -798,11 +884,11 @@
 }
 
 mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet(
-    Handle<mirror::Class> klass,
+    const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set,
     uint32_t visibility)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   Thread* self = Thread::Current();
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<2> hs(self);
@@ -856,11 +942,11 @@
 }
 
 mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList(
-    Handle<mirror::Class> klass,
+    const ClassData& klass,
     const DexFile::AnnotationSetRefList* set_ref_list,
     uint32_t size)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile& dex_file = klass.GetDexFile();
   Thread* self = Thread::Current();
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<1> hs(self);
@@ -899,15 +985,17 @@
     return nullptr;
   }
   StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
-  return GetAnnotationObjectFromAnnotationSet(field_class, annotation_set,
-                                              DexFile::kDexVisibilityRuntime, annotation_class);
+  const ClassData field_class(hs, field);
+  return GetAnnotationObjectFromAnnotationSet(field_class,
+                                              annotation_set,
+                                              DexFile::kDexVisibilityRuntime,
+                                              annotation_class);
 }
 
 mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) {
   const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
   StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  const ClassData field_class(hs, field);
   return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime);
 }
 
@@ -917,7 +1005,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  const ClassData field_class(hs, field);
   return GetSignatureValue(field_class, annotation_set);
 }
 
@@ -927,17 +1015,17 @@
     return false;
   }
   StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  const ClassData field_class(hs, field);
   const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
       field_class, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
   return annotation_item != nullptr;
 }
 
 mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) {
-  const DexFile* dex_file = method->GetDexFile();
-  mirror::Class* klass = method->GetDeclaringClass();
+  const ClassData klass(method);
+  const DexFile* dex_file = &klass.GetDexFile();
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
-      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+      dex_file->GetAnnotationsDirectory(*klass.GetClassDef());
   if (annotations_dir == nullptr) {
     return nullptr;
   }
@@ -965,10 +1053,9 @@
     return nullptr;
   }
   DexFile::AnnotationValue annotation_value;
-  StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+  StackHandleScope<1> hs(Thread::Current());
   Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */)));
-  if (!ProcessAnnotationValue<false>(h_klass,
+  if (!ProcessAnnotationValue<false>(klass,
                                      &annotation,
                                      &annotation_value,
                                      return_type,
@@ -983,17 +1070,15 @@
   if (annotation_set == nullptr) {
     return nullptr;
   }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetAnnotationObjectFromAnnotationSet(method_class, annotation_set,
+  return GetAnnotationObjectFromAnnotationSet(ClassData(method), annotation_set,
                                               DexFile::kDexVisibilityRuntime, annotation_class);
 }
 
 mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) {
   const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return ProcessAnnotationSet(method_class, annotation_set, DexFile::kDexVisibilityRuntime);
+  return ProcessAnnotationSet(ClassData(method),
+                              annotation_set,
+                              DexFile::kDexVisibilityRuntime);
 }
 
 mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) {
@@ -1001,9 +1086,7 @@
   if (annotation_set == nullptr) {
     return nullptr;
   }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetThrowsValue(method_class, annotation_set);
+  return GetThrowsValue(ClassData(method), annotation_set);
 }
 
 mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) {
@@ -1019,9 +1102,7 @@
     return nullptr;
   }
   uint32_t size = set_ref_list->size_;
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return ProcessAnnotationSetRefList(method_class, set_ref_list, size);
+  return ProcessAnnotationSetRefList(ClassData(method), set_ref_list, size);
 }
 
 mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method,
@@ -1045,9 +1126,7 @@
   const DexFile::AnnotationSetItem* annotation_set =
      dex_file->GetSetRefItemItem(annotation_set_ref);
 
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetAnnotationObjectFromAnnotationSet(method_class,
+  return GetAnnotationObjectFromAnnotationSet(ClassData(method),
                                               annotation_set,
                                               DexFile::kDexVisibilityRuntime,
                                               annotation_class);
@@ -1072,7 +1151,7 @@
     return false;
   }
 
-  StackHandleScope<5> hs(Thread::Current());
+  StackHandleScope<4> hs(Thread::Current());
 
   // Extract the parameters' names String[].
   ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString();
@@ -1082,9 +1161,9 @@
     return false;
   }
 
-  Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass());
+  ClassData data(method);
   Handle<mirror::Object> names_obj =
-      hs.NewHandle(GetAnnotationValue(klass,
+      hs.NewHandle(GetAnnotationValue(data,
                                       annotation_item,
                                       "names",
                                       string_array_class,
@@ -1099,7 +1178,7 @@
     return false;
   }
   Handle<mirror::Object> access_flags_obj =
-      hs.NewHandle(GetAnnotationValue(klass,
+      hs.NewHandle(GetAnnotationValue(data,
                                       annotation_item,
                                       "accessFlags",
                                       int_array_class,
@@ -1118,9 +1197,7 @@
   if (annotation_set == nullptr) {
     return nullptr;
   }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetSignatureValue(method_class, annotation_set);
+  return GetSignatureValue(ClassData(method), annotation_set);
 }
 
 bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
@@ -1129,37 +1206,39 @@
   if (annotation_set == nullptr) {
     return false;
   }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
   const DexFile::AnnotationItem* annotation_item =
-      GetAnnotationItemFromAnnotationSet(method_class, annotation_set, visibility,
-                                         annotation_class);
+      GetAnnotationItemFromAnnotationSet(ClassData(method),
+                                         annotation_set, visibility, annotation_class);
   return annotation_item != nullptr;
 }
 
 mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
                                       Handle<mirror::Class> annotation_class) {
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
-  return GetAnnotationObjectFromAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime,
+  return GetAnnotationObjectFromAnnotationSet(data,
+                                              annotation_set,
+                                              DexFile::kDexVisibilityRuntime,
                                               annotation_class);
 }
 
 mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) {
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  return ProcessAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
+  return ProcessAnnotationSet(data, annotation_set, DexFile::kDexVisibilityRuntime);
 }
 
 mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) {
-  const DexFile& dex_file = klass->GetDexFile();
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
   const DexFile::AnnotationItem* annotation_item =
-      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/MemberClasses;",
+      SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/MemberClasses;",
                           DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return nullptr;
@@ -1172,7 +1251,7 @@
     return nullptr;
   }
   mirror::Object* obj =
-      GetAnnotationValue(klass, annotation_item, "value", class_array_class,
+      GetAnnotationValue(data, annotation_item, "value", class_array_class,
                          DexFile::kDexAnnotationArray);
   if (obj == nullptr) {
     return nullptr;
@@ -1181,18 +1260,18 @@
 }
 
 mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) {
-  const DexFile& dex_file = klass->GetDexFile();
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
   const DexFile::AnnotationItem* annotation_item =
-      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingClass;",
+      SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/EnclosingClass;",
                           DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return nullptr;
   }
-  mirror::Object* obj = GetAnnotationValue(klass, annotation_item, "value",
+  mirror::Object* obj = GetAnnotationValue(data, annotation_item, "value",
                                            ScopedNullHandle<mirror::Class>(),
                                            DexFile::kDexAnnotationType);
   if (obj == nullptr) {
@@ -1202,28 +1281,30 @@
 }
 
 mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) {
-  const DexFile& dex_file = klass->GetDexFile();
   mirror::Class* declaring_class = GetDeclaringClass(klass);
   if (declaring_class != nullptr) {
     return declaring_class;
   }
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
   const DexFile::AnnotationItem* annotation_item =
-      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+      SearchAnnotationSet(data.GetDexFile(),
+                          annotation_set,
+                          "Ldalvik/annotation/EnclosingMethod;",
                           DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return nullptr;
   }
   const uint8_t* annotation =
-      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "value");
+      SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value");
   if (annotation == nullptr) {
     return nullptr;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue<false>(klass,
+  if (!ProcessAnnotationValue<false>(data,
                                      &annotation,
                                      &annotation_value,
                                      ScopedNullHandle<mirror::Class>(),
@@ -1234,10 +1315,11 @@
     return nullptr;
   }
   StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
   ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
-      klass->GetDexFile(), annotation_value.value_.GetI(), dex_cache, class_loader);
+      data.GetDexFile(),
+      annotation_value.value_.GetI(),
+      hs.NewHandle(data.GetDexCache()),
+      hs.NewHandle(data.GetClassLoader()));
   if (method == nullptr) {
     return nullptr;
   }
@@ -1245,39 +1327,44 @@
 }
 
 mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) {
-  const DexFile& dex_file = klass->GetDexFile();
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
   const DexFile::AnnotationItem* annotation_item =
-      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+      SearchAnnotationSet(data.GetDexFile(),
+                          annotation_set,
+                          "Ldalvik/annotation/EnclosingMethod;",
                           DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return nullptr;
   }
-  return GetAnnotationValue(klass, annotation_item, "value", ScopedNullHandle<mirror::Class>(),
+  return GetAnnotationValue(data, annotation_item, "value", ScopedNullHandle<mirror::Class>(),
       DexFile::kDexAnnotationMethod);
 }
 
 bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) {
-  const DexFile& dex_file = klass->GetDexFile();
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return false;
   }
   const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(
-      dex_file, annotation_set, "Ldalvik/annotation/InnerClass;", DexFile::kDexVisibilitySystem);
+      data.GetDexFile(),
+      annotation_set,
+      "Ldalvik/annotation/InnerClass;",
+      DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return false;
   }
   const uint8_t* annotation =
-      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "name");
+      SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "name");
   if (annotation == nullptr) {
     return false;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue<false>(klass,
+  if (!ProcessAnnotationValue<false>(data,
                                      &annotation,
                                      &annotation_value,
                                      ScopedNullHandle<mirror::Class>(),
@@ -1293,24 +1380,24 @@
 }
 
 bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) {
-  const DexFile& dex_file = klass->GetDexFile();
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return false;
   }
   const DexFile::AnnotationItem* annotation_item =
-      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/InnerClass;",
+      SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/InnerClass;",
                           DexFile::kDexVisibilitySystem);
   if (annotation_item == nullptr) {
     return false;
   }
   const uint8_t* annotation =
-      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "accessFlags");
+      SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "accessFlags");
   if (annotation == nullptr) {
     return false;
   }
   DexFile::AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue<false>(klass,
+  if (!ProcessAnnotationValue<false>(data,
                                      &annotation,
                                      &annotation_value,
                                      ScopedNullHandle<mirror::Class>(),
@@ -1325,20 +1412,22 @@
 }
 
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) {
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return nullptr;
   }
-  return GetSignatureValue(klass, annotation_set);
+  return GetSignatureValue(data, annotation_set);
 }
 
 bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) {
-  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  ClassData data(klass);
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
   if (annotation_set == nullptr) {
     return false;
   }
   const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
-      klass, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
+      data, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
   return annotation_item != nullptr;
 }
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index aea9708..7136f10 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2171,7 +2171,9 @@
       fall_back_to_non_moving = true;
       to_ref = heap_->non_moving_space_->Alloc(Thread::Current(), obj_size,
                                                &non_moving_space_bytes_allocated, nullptr, &dummy);
-      CHECK(to_ref != nullptr) << "Fall-back non-moving space allocation failed";
+      CHECK(to_ref != nullptr) << "Fall-back non-moving space allocation failed for a "
+                               << obj_size << " byte object in region type "
+                               << region_space_->GetRegionType(from_ref);
       bytes_allocated = non_moving_space_bytes_allocated;
       // Mark it in the mark bitmap.
       accounting::ContinuousSpaceBitmap* mark_bitmap =
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 00487c6..2724b00 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -42,8 +42,6 @@
                            const std::vector<std::string>& code_paths)
     : jit_code_cache_(jit_code_cache),
       shutting_down_(false),
-      last_save_number_of_methods_(0),
-      last_save_number_of_classes_(0),
       last_time_ns_saver_woke_up_(0),
       jit_activity_notifications_(0),
       wait_lock_("ProfileSaver wait lock"),
@@ -171,10 +169,10 @@
   }
 }
 
-ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
+ProfileSaver::ProfileInfoCache* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
   auto info_it = profile_cache_.find(filename);
   if (info_it == profile_cache_.end()) {
-    info_it = profile_cache_.Put(filename, ProfileCompilationInfo());
+    info_it = profile_cache_.Put(filename, ProfileInfoCache());
   }
   return &info_it->second;
 }
@@ -248,8 +246,9 @@
                        << " (" << classes.GetDexLocation() << ")";
       }
     }
-    ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
-    info->AddMethodsAndClasses(profile_methods_for_location, resolved_classes_for_location);
+    ProfileInfoCache* cached_info = GetCachedProfiledInfo(filename);
+    cached_info->profile.AddMethodsAndClasses(profile_methods_for_location,
+                                              resolved_classes_for_location);
     total_number_of_profile_entries_cached += resolved_classes_for_location.size();
   }
   max_number_of_profile_entries_cached_ = std::max(
@@ -283,14 +282,15 @@
       total_number_of_code_cache_queries_++;
     }
 
-    ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename);
-    cached_info->AddMethodsAndClasses(profile_methods, std::set<DexCacheResolvedClasses>());
+    ProfileInfoCache* cached_info = GetCachedProfiledInfo(filename);
+    ProfileCompilationInfo* cached_profile = &cached_info->profile;
+    cached_profile->AddMethodsAndClasses(profile_methods, std::set<DexCacheResolvedClasses>());
     int64_t delta_number_of_methods =
-        cached_info->GetNumberOfMethods() -
-        static_cast<int64_t>(last_save_number_of_methods_);
+        cached_profile->GetNumberOfMethods() -
+        static_cast<int64_t>(cached_info->last_save_number_of_methods);
     int64_t delta_number_of_classes =
-        cached_info->GetNumberOfResolvedClasses() -
-        static_cast<int64_t>(last_save_number_of_classes_);
+        cached_profile->GetNumberOfResolvedClasses() -
+        static_cast<int64_t>(cached_info->last_save_number_of_classes);
 
     if (delta_number_of_methods < options_.GetMinMethodsToSave() &&
         delta_number_of_classes < options_.GetMinClassesToSave()) {
@@ -304,12 +304,12 @@
     uint64_t bytes_written;
     // Force the save. In case the profile data is corrupted or the the profile
     // has the wrong version this will "fix" the file to the correct format.
-    if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
-      last_save_number_of_methods_ = cached_info->GetNumberOfMethods();
-      last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses();
+    if (cached_profile->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
+      cached_info->last_save_number_of_methods = cached_profile->GetNumberOfMethods();
+      cached_info->last_save_number_of_classes = cached_profile->GetNumberOfResolvedClasses();
       // Clear resolved classes. No need to store them around as
       // they don't change after the first write.
-      cached_info->ClearResolvedClasses();
+      cached_profile->ClearResolvedClasses();
       if (bytes_written > 0) {
         total_number_of_writes_++;
         total_bytes_written_ += bytes_written;
@@ -326,8 +326,8 @@
       total_number_of_failed_writes_++;
     }
     total_number_of_profile_entries_cached +=
-        cached_info->GetNumberOfMethods() +
-        cached_info->GetNumberOfResolvedClasses();
+        cached_profile->GetNumberOfMethods() +
+        cached_profile->GetNumberOfResolvedClasses();
   }
   max_number_of_profile_entries_cached_ = std::max(
       max_number_of_profile_entries_cached_,
@@ -526,10 +526,8 @@
                                  uint16_t method_idx) {
   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
   if (instance_ != nullptr) {
-    ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile);
-    if (info != nullptr) {
-      return info->ContainsMethod(MethodReference(dex_file, method_idx));
-    }
+    const ProfileCompilationInfo& info = instance_->GetCachedProfiledInfo(profile)->profile;
+    return info.ContainsMethod(MethodReference(dex_file, method_idx));
   }
   return false;
 }
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index ec8342a..8e0682d 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -59,6 +59,14 @@
                             uint16_t method_idx);
 
  private:
+  // A cache structure which keeps track of the data saved to disk.
+  // It is used to reduce the number of disk read/writes.
+  struct ProfileInfoCache {
+    ProfileCompilationInfo profile;
+    uint32_t last_save_number_of_methods = 0;
+    uint32_t last_save_number_of_classes = 0;
+  };
+
   ProfileSaver(const ProfileSaverOptions& options,
                const std::string& output_filename,
                jit::JitCodeCache* jit_code_cache,
@@ -90,7 +98,7 @@
   // Retrieves the cached profile compilation info for the given profile file.
   // If no entry exists, a new empty one will be created, added to the cache and
   // then returned.
-  ProfileCompilationInfo* GetCachedProfiledInfo(const std::string& filename);
+  ProfileInfoCache* GetCachedProfiledInfo(const std::string& filename);
   // Fetches the current resolved classes and methods from the ClassLinker and stores them in the
   // profile_cache_ for later save.
   void FetchAndCacheResolvedClassesAndMethods();
@@ -110,8 +118,6 @@
       GUARDED_BY(Locks::profiler_lock_);
 
   bool shutting_down_ GUARDED_BY(Locks::profiler_lock_);
-  uint32_t last_save_number_of_methods_;
-  uint32_t last_save_number_of_classes_;
   uint64_t last_time_ns_saver_woke_up_ GUARDED_BY(wait_lock_);
   uint32_t jit_activity_notifications_;
 
@@ -119,7 +125,7 @@
   // profile information. The size of this cache is usually very small and tops
   // to just a few hundreds entries in the ProfileCompilationInfo objects.
   // It helps avoiding unnecessary writes to disk.
-  SafeMap<std::string, ProfileCompilationInfo> profile_cache_;
+  SafeMap<std::string, ProfileInfoCache> profile_cache_;
 
   // Save period condition support.
   Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 5048bad..898d07d 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -61,7 +61,7 @@
 
    private:
     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
-    static constexpr uint8_t kVdexVersion[] = { '0', '0', '4', '\0' };  // dexlayout incompatibility
+    static constexpr uint8_t kVdexVersion[] = { '0', '0', '5', '\0' };  // access flags
 
     uint8_t magic_[4];
     uint8_t version_[4];
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 52f7e34..740b7dd 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -309,6 +309,7 @@
   // Note: no check for IsInstantiable() here. We may produce this in case an InstantiationError
   //       would be thrown at runtime, but we need to continue verification and *not* create a
   //       hard failure or abort.
+  CheckConstructorInvariants(this);
 }
 
 std::string UnresolvedMergedType::Dump() const {
@@ -789,7 +790,7 @@
   if (!klass_.IsNull()) {
     CHECK(!descriptor_.empty()) << *this;
     std::string temp;
-    CHECK_EQ(descriptor_.ToString(), klass_.Read()->GetDescriptor(&temp)) << *this;
+    CHECK_EQ(descriptor_, klass_.Read()->GetDescriptor(&temp)) << *this;
   }
 }
 
@@ -820,9 +821,7 @@
       reg_type_cache_(reg_type_cache),
       resolved_part_(resolved),
       unresolved_types_(unresolved, false, unresolved.GetAllocator()) {
-  if (kIsDebugBuild) {
-    CheckInvariants();
-  }
+  CheckConstructorInvariants(this);
 }
 void UnresolvedMergedType::CheckInvariants() const {
   CHECK(reg_type_cache_ != nullptr);
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 472381d..dedf77f 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -274,14 +274,17 @@
           uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : descriptor_(descriptor),
         klass_(klass),
-        cache_id_(cache_id) {
+        cache_id_(cache_id) {}
+
+  template <typename Class>
+  void CheckConstructorInvariants(Class* this_ ATTRIBUTE_UNUSED) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    static_assert(std::is_final<Class>::value, "Class must be final.");
     if (kIsDebugBuild) {
       CheckInvariants();
     }
   }
 
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
-
   const StringPiece descriptor_;
   mutable GcRoot<mirror::Class> klass_;  // Non-const only due to moving classes.
   const uint16_t cache_id_;
@@ -289,6 +292,8 @@
   friend class RegTypeCache;
 
  private:
+  virtual void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+
   /*
    * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
    * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
@@ -339,7 +344,9 @@
  private:
   ConflictType(mirror::Class* klass, const StringPiece& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : RegType(klass, descriptor, cache_id) {}
+      : RegType(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   static const ConflictType* instance_;
 };
@@ -368,7 +375,9 @@
  private:
   UndefinedType(mirror::Class* klass, const StringPiece& descriptor,
                 uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : RegType(klass, descriptor, cache_id) {}
+      : RegType(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   static const UndefinedType* instance_;
 };
@@ -387,7 +396,7 @@
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_);
 };
 
-class IntegerType : public Cat1Type {
+class IntegerType FINAL : public Cat1Type {
  public:
   bool IsInteger() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
@@ -401,7 +410,9 @@
  private:
   IntegerType(mirror::Class* klass, const StringPiece& descriptor,
               uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const IntegerType* instance_;
 };
 
@@ -419,7 +430,9 @@
  private:
   BooleanType(mirror::Class* klass, const StringPiece& descriptor,
               uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   static const BooleanType* instance_;
 };
@@ -438,7 +451,9 @@
  private:
   ByteType(mirror::Class* klass, const StringPiece& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const ByteType* instance_;
 };
 
@@ -456,7 +471,9 @@
  private:
   ShortType(mirror::Class* klass, const StringPiece& descriptor,
             uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const ShortType* instance_;
 };
 
@@ -474,7 +491,9 @@
  private:
   CharType(mirror::Class* klass, const StringPiece& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const CharType* instance_;
 };
 
@@ -492,7 +511,9 @@
  private:
   FloatType(mirror::Class* klass, const StringPiece& descriptor,
             uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat1Type(klass, descriptor, cache_id) {}
+      : Cat1Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const FloatType* instance_;
 };
 
@@ -517,7 +538,9 @@
  private:
   LongLoType(mirror::Class* klass, const StringPiece& descriptor,
              uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat2Type(klass, descriptor, cache_id) {}
+      : Cat2Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const LongLoType* instance_;
 };
 
@@ -535,7 +558,9 @@
  private:
   LongHiType(mirror::Class* klass, const StringPiece& descriptor,
              uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat2Type(klass, descriptor, cache_id) {}
+      : Cat2Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const LongHiType* instance_;
 };
 
@@ -554,7 +579,9 @@
  private:
   DoubleLoType(mirror::Class* klass, const StringPiece& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat2Type(klass, descriptor, cache_id) {}
+      : Cat2Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const DoubleLoType* instance_;
 };
 
@@ -572,7 +599,9 @@
  private:
   DoubleHiType(mirror::Class* klass, const StringPiece& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : Cat2Type(klass, descriptor, cache_id) {}
+      : Cat2Type(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   static const DoubleHiType* instance_;
 };
 
@@ -637,7 +666,9 @@
  public:
   PreciseConstType(uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {}
+      : ConstantType(constant, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   bool IsPreciseConstant() const OVERRIDE { return true; }
 
@@ -648,7 +679,9 @@
  public:
   PreciseConstLoType(uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {}
+      : ConstantType(constant, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   bool IsPreciseConstantLo() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -657,7 +690,9 @@
  public:
   PreciseConstHiType(uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {}
+      : ConstantType(constant, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   bool IsPreciseConstantHi() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -667,6 +702,7 @@
   ImpreciseConstType(uint32_t constat, uint16_t cache_id)
        REQUIRES_SHARED(Locks::mutator_lock_)
        : ConstantType(constat, cache_id) {
+    CheckConstructorInvariants(this);
   }
   bool IsImpreciseConstant() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
@@ -676,7 +712,9 @@
  public:
   ImpreciseConstLoType(uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {}
+      : ConstantType(constant, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   bool IsImpreciseConstantLo() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -685,7 +723,9 @@
  public:
   ImpreciseConstHiType(uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {}
+      : ConstantType(constant, cache_id) {
+    CheckConstructorInvariants(this);
+  }
   bool IsImpreciseConstantHi() const OVERRIDE { return true; }
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -718,7 +758,9 @@
                              const StringPiece& descriptor,
                              uint32_t allocation_pc, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : UninitializedType(klass, descriptor, allocation_pc, cache_id) {}
+      : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   bool IsUninitializedReference() const OVERRIDE { return true; }
 
@@ -735,9 +777,7 @@
                                  uint32_t allocation_pc, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : UninitializedType(nullptr, descriptor, allocation_pc, cache_id) {
-    if (kIsDebugBuild) {
-      CheckInvariants();
-    }
+    CheckConstructorInvariants(this);
   }
 
   bool IsUnresolvedAndUninitializedReference() const OVERRIDE { return true; }
@@ -747,7 +787,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 };
 
 // Similar to UninitializedReferenceType but special case for the this argument
@@ -759,9 +799,7 @@
                                  uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : UninitializedType(klass, descriptor, 0, cache_id) {
-    if (kIsDebugBuild) {
-      CheckInvariants();
-    }
+    CheckConstructorInvariants(this);
   }
 
   virtual bool IsUninitializedThisReference() const OVERRIDE { return true; }
@@ -771,7 +809,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 };
 
 class UnresolvedUninitializedThisRefType FINAL : public UninitializedType {
@@ -780,9 +818,7 @@
                                      uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : UninitializedType(nullptr, descriptor, 0, cache_id) {
-    if (kIsDebugBuild) {
-      CheckInvariants();
-    }
+    CheckConstructorInvariants(this);
   }
 
   bool IsUnresolvedAndUninitializedThisReference() const OVERRIDE { return true; }
@@ -792,7 +828,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 };
 
 // A type of register holding a reference to an Object of type GetClass or a
@@ -801,7 +837,9 @@
  public:
   ReferenceType(mirror::Class* klass, const StringPiece& descriptor,
                 uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : RegType(klass, descriptor, cache_id) {}
+      : RegType(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
 
   bool IsReference() const OVERRIDE { return true; }
 
@@ -848,9 +886,7 @@
   UnresolvedReferenceType(const StringPiece& descriptor, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : UnresolvedType(descriptor, cache_id) {
-    if (kIsDebugBuild) {
-      CheckInvariants();
-    }
+    CheckConstructorInvariants(this);
   }
 
   bool IsUnresolvedReference() const OVERRIDE { return true; }
@@ -860,7 +896,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 };
 
 // Type representing the super-class of an unresolved type.
@@ -872,9 +908,7 @@
       : UnresolvedType("", cache_id),
         unresolved_child_id_(child_id),
         reg_type_cache_(reg_type_cache) {
-    if (kIsDebugBuild) {
-      CheckInvariants();
-    }
+    CheckConstructorInvariants(this);
   }
 
   bool IsUnresolvedSuperClass() const OVERRIDE { return true; }
@@ -889,7 +923,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 
   const uint16_t unresolved_child_id_;
   const RegTypeCache* const reg_type_cache_;
@@ -925,7 +959,7 @@
   std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+  void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 
   const RegTypeCache* const reg_type_cache_;
 
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 000cf7c..d477ecd 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -68,13 +68,17 @@
   return (it == dex_deps_.end()) ? nullptr : it->second.get();
 }
 
+// Access flags that impact vdex verification.
+static constexpr uint32_t kAccVdexAccessFlags =
+    kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccInterface;
+
 template <typename T>
 uint16_t VerifierDeps::GetAccessFlags(T* element) {
   static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
   if (element == nullptr) {
     return VerifierDeps::kUnresolvedMarker;
   } else {
-    uint16_t access_flags = Low16Bits(element->GetAccessFlags());
+    uint16_t access_flags = Low16Bits(element->GetAccessFlags()) & kAccVdexAccessFlags;
     CHECK_NE(access_flags, VerifierDeps::kUnresolvedMarker);
     return access_flags;
   }
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
index 666fe89..d83ee82 100644
--- a/test/701-easy-div-rem/build
+++ b/test/701-easy-div-rem/build
@@ -21,12 +21,4 @@
 mkdir src
 python ./genMain.py
 
-# Increase the file size limitation for classes.lst as the machine generated
-# source file contains a lot of methods and is quite large.
-
-# Jack generates big temp files so only apply ulimit for dx.
-if [ ${USE_JACK} = "false" ]; then
-  ulimit -S 4096
-fi
-
 ./default-build
diff --git a/test/961-default-iface-resolution-gen/build b/test/961-default-iface-resolution-gen/build
index ccebbe4..2f7e3ba 100755
--- a/test/961-default-iface-resolution-gen/build
+++ b/test/961-default-iface-resolution-gen/build
@@ -17,15 +17,6 @@
 # make us exit on a failure
 set -e
 
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
-  ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
 if [[ $@ != *"--jvm"* ]]; then
   # Don't do anything with jvm
   # Hard-wired use of experimental jack.
@@ -39,6 +30,3 @@
 ./util-src/generate_java.py ./src ./expected.txt
 
 ./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/964-default-iface-init-gen/build b/test/964-default-iface-init-gen/build
index ccebbe4..2f7e3ba 100755
--- a/test/964-default-iface-init-gen/build
+++ b/test/964-default-iface-init-gen/build
@@ -17,15 +17,6 @@
 # make us exit on a failure
 set -e
 
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
-  ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
 if [[ $@ != *"--jvm"* ]]; then
   # Don't do anything with jvm
   # Hard-wired use of experimental jack.
@@ -39,6 +30,3 @@
 ./util-src/generate_java.py ./src ./expected.txt
 
 ./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/968-default-partial-compile-gen/build b/test/968-default-partial-compile-gen/build
index 1e9f8aa..00ccb89 100755
--- a/test/968-default-partial-compile-gen/build
+++ b/test/968-default-partial-compile-gen/build
@@ -17,15 +17,6 @@
 # make us exit on a failure
 set -e
 
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
-  ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
 # TODO: Support running with jack.
 
 if [[ $@ == *"--jvm"* ]]; then
@@ -45,6 +36,3 @@
   # Use the default build script
   ./default-build "$@" "$EXTRA_ARGS" --experimental default-methods
 fi
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/970-iface-super-resolution-gen/build b/test/970-iface-super-resolution-gen/build
index fd1b271..7217fac 100755
--- a/test/970-iface-super-resolution-gen/build
+++ b/test/970-iface-super-resolution-gen/build
@@ -17,15 +17,6 @@
 # make us exit on a failure
 set -e
 
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
-  ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
 # Should we compile with Java source code. By default we will use Smali.
 USES_JAVA_SOURCE="false"
 if [[ $@ == *"--jvm"* ]]; then
@@ -50,6 +41,3 @@
 fi
 
 ./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/971-iface-super/build b/test/971-iface-super/build
index 1e9f8aa..00ccb89 100755
--- a/test/971-iface-super/build
+++ b/test/971-iface-super/build
@@ -17,15 +17,6 @@
 # make us exit on a failure
 set -e
 
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
-  ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
 # TODO: Support running with jack.
 
 if [[ $@ == *"--jvm"* ]]; then
@@ -45,6 +36,3 @@
   # Use the default build script
   ./default-build "$@" "$EXTRA_ARGS" --experimental default-methods
 fi
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check
new file mode 100755
index 0000000..987066f
--- /dev/null
+++ b/test/980-redefine-object/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The number of paused background threads (and therefore InterruptedExceptions)
+# can change so we will just delete their lines from the log.
+
+sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt
new file mode 100644
index 0000000..6e9bce0
--- /dev/null
+++ b/test/980-redefine-object/expected.txt
@@ -0,0 +1,52 @@
+	Initializing and loading the TestWatcher class that will (eventually) be notified of object allocations
+	Allocating an j.l.Object before redefining Object class
+	Allocating a Transform before redefining Object class
+	Redefining the Object class to add a hook into the <init> method
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Allocating an j.l.Object after redefining Object class
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Allocating a Transform after redefining Object class
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Allocating an int[] after redefining Object class
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Allocating an array list
+Object allocated of type 'Ljava/util/ArrayList;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Adding a bunch of stuff to the array list
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Allocating a linked list
+Object allocated of type 'Ljava/util/LinkedList;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Adding a bunch of stuff to the linked list
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Throwing from down 4 stack frames
+Object allocated of type 'Ljava/lang/Exception;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Exception caught.
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+	Finishing test!
diff --git a/test/980-redefine-object/info.txt b/test/980-redefine-object/info.txt
new file mode 100644
index 0000000..f3e01b5
--- /dev/null
+++ b/test/980-redefine-object/info.txt
@@ -0,0 +1,23 @@
+Tests basic functions in the jvmti plugin.
+
+This tests that we are able to redefine methods/constructors on the
+java.lang.Object class at runtime.
+
+This also (indirectly) tests that we correctly handle reading annotations on
+obsolete methods. This is something that is not normally done since there is no
+way to get a reference to an obsolete method outside of the runtime but some
+annotations on the Object class are read by the runtime directly.
+
+NB This test cannot be run on the RI at the moment.
+
+If this test starts failing during the doCommonClassRedefinition call it is
+possible that the definition of Object contained in the base64 DEX_BYTES array
+has become stale and will need to be recreated. The only difference from the
+normal Object dex bytes is that (a) it contains only the bytes of the Object
+class itself, and (b) it adds an
+'invoke-static {p0}, Ljava/lang/Object;->NotifyConstructed(Ljava/lang/Object;)V'
+to the <init> function.
+
+It is also possible it could fail due to the pattern of allocations caused by
+doing string concatenation or printing changing. In this case you should simply
+update the expected.txt file.
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
new file mode 100644
index 0000000..daae087
--- /dev/null
+++ b/test/980-redefine-object/redefine_object.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <iostream>
+
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "jni.h"
+#include "jvmti.h"
+#include "ScopedUtfChars.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test980RedefineObjects {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) {
+  BindFunctionsOnClass(jvmti_env, env, target);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed(
+    JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) {
+  char* sig = nullptr;
+  char* generic_sig = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
+                                                              &sig,
+                                                              &generic_sig))) {
+    // Exception.
+    return;
+  }
+  std::cout << "Object allocated of type '" << sig << "'" << std::endl;
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig));
+}
+
+}  // namespace Test980RedefineObjects
+}  // namespace art
diff --git a/test/980-redefine-object/run b/test/980-redefine-object/run
new file mode 100755
index 0000000..c6e62ae
--- /dev/null
+++ b/test/980-redefine-object/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java
new file mode 100644
index 0000000..d15e688
--- /dev/null
+++ b/test/980-redefine-object/src-ex/TestWatcher.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art.test;
+
+public class TestWatcher {
+  // NB This function is native since it is called in the Object.<init> method and so cannot cause
+  // any java allocations at all. The normal System.out.print* functions will cause allocations to
+  // occur so we cannot use them. This means the easiest way to report the object as being created
+  // is to go into native code and do it there.
+  public static native void NotifyConstructed(Object o);
+}
diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java
new file mode 100644
index 0000000..348951c
--- /dev/null
+++ b/test/980-redefine-object/src/Main.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.LinkedList;
+
+public class Main {
+
+  // TODO We should make this run on the RI.
+  /**
+   * This test cannot be run on the RI.
+   */
+  private static final byte[] CLASS_BYTES = new byte[0];
+
+  // TODO It might be a good idea to replace this hard-coded Object definition with a
+  // retransformation based test.
+  /**
+   * Base64 encoding of the following smali file.
+   *
+   *  .class public Ljava/lang/Object;
+   *  .source "Object.java"
+   *  # instance fields
+   *  .field private transient shadow$_klass_:Ljava/lang/Class;
+   *      .annotation system Ldalvik/annotation/Signature;
+   *          value = {
+   *              "Ljava/lang/Class",
+   *              "<*>;"
+   *          }
+   *      .end annotation
+   *  .end field
+   *
+   *  .field private transient shadow$_monitor_:I
+   *  # direct methods
+   *  .method public constructor <init>()V
+   *      .registers 1
+   *      .prologue
+   *      invoke-static {p0}, Lart/test/TestWatcher;->NotifyConstructed(Ljava/lang/Object;)V
+   *      return-void
+   *  .end method
+   *
+   *  .method static identityHashCode(Ljava/lang/Object;)I
+   *      .registers 7
+   *      .prologue
+   *      iget v0, p0, Ljava/lang/Object;->shadow$_monitor_:I
+   *      const/high16 v3, -0x40000000    # -2.0f
+   *      const/high16 v2, -0x80000000
+   *      const v1, 0xfffffff
+   *      const/high16 v4, -0x40000000    # -2.0f
+   *      and-int/2addr v4, v0
+   *      const/high16 v5, -0x80000000
+   *      if-ne v4, v5, :cond_15
+   *      const v4, 0xfffffff
+   *      and-int/2addr v4, v0
+   *      return v4
+   *      :cond_15
+   *      invoke-static {p0}, Ljava/lang/Object;->identityHashCodeNative(Ljava/lang/Object;)I
+   *      move-result v4
+   *      return v4
+   *  .end method
+   *
+   *  .method private static native identityHashCodeNative(Ljava/lang/Object;)I
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   *
+   *  .method private native internalClone()Ljava/lang/Object;
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   *
+   *
+   *  # virtual methods
+   *  .method protected clone()Ljava/lang/Object;
+   *      .registers 4
+   *      .annotation system Ldalvik/annotation/Throws;
+   *          value = {
+   *              Ljava/lang/CloneNotSupportedException;
+   *          }
+   *      .end annotation
+   *
+   *      .prologue
+   *      instance-of v0, p0, Ljava/lang/Cloneable;
+   *      if-nez v0, :cond_2d
+   *      new-instance v0, Ljava/lang/CloneNotSupportedException;
+   *      new-instance v1, Ljava/lang/StringBuilder;
+   *      invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+   *      const-string/jumbo v2, "Class "
+   *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v1
+   *      invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+   *      move-result-object v2
+   *      invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String;
+   *      move-result-object v2
+   *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v1
+   *      const-string/jumbo v2, " doesn\'t implement Cloneable"
+   *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v1
+   *      invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+   *      move-result-object v1
+   *      invoke-direct {v0, v1}, Ljava/lang/CloneNotSupportedException;-><init>(Ljava/lang/String;)V
+   *      throw v0
+   *      :cond_2d
+   *      invoke-direct {p0}, Ljava/lang/Object;->internalClone()Ljava/lang/Object;
+   *      move-result-object v0
+   *      return-object v0
+   *  .end method
+   *
+   *  .method public equals(Ljava/lang/Object;)Z
+   *      .registers 3
+   *      .prologue
+   *      if-ne p0, p1, :cond_4
+   *      const/4 v0, 0x1
+   *      :goto_3
+   *      return v0
+   *      :cond_4
+   *      const/4 v0, 0x0
+   *      goto :goto_3
+   *  .end method
+   *
+   *  .method protected finalize()V
+   *      .registers 1
+   *      .annotation system Ldalvik/annotation/Throws;
+   *          value = {
+   *              Ljava/lang/Throwable;
+   *          }
+   *      .end annotation
+   *      .prologue
+   *      return-void
+   *  .end method
+   *
+   *  .method public final getClass()Ljava/lang/Class;
+   *      .registers 2
+   *      .annotation system Ldalvik/annotation/Signature;
+   *          value = {
+   *              "()",
+   *              "Ljava/lang/Class",
+   *              "<*>;"
+   *          }
+   *      .end annotation
+   *      .prologue
+   *      iget-object v0, p0, Ljava/lang/Object;->shadow$_klass_:Ljava/lang/Class;
+   *      return-object v0
+   *  .end method
+   *
+   *  .method public hashCode()I
+   *      .registers 2
+   *      .prologue
+   *      invoke-static {p0}, Ljava/lang/Object;->identityHashCode(Ljava/lang/Object;)I
+   *      move-result v0
+   *      return v0
+   *  .end method
+   *
+   *  .method public final native notify()V
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   *
+   *  .method public final native notifyAll()V
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   *
+   *  .method public toString()Ljava/lang/String;
+   *      .registers 3
+   *      .prologue
+   *      new-instance v0, Ljava/lang/StringBuilder;
+   *      invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
+   *      invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+   *      move-result-object v1
+   *      invoke-virtual {v1}, Ljava/lang/Class;->getName()Ljava/lang/String;
+   *      move-result-object v1
+   *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v0
+   *      const-string/jumbo v1, "@"
+   *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v0
+   *      invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+   *      move-result v1
+   *      invoke-static {v1}, Ljava/lang/Integer;->toHexString(I)Ljava/lang/String;
+   *      move-result-object v1
+   *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+   *      move-result-object v0
+   *      invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+   *      move-result-object v0
+   *      return-object v0
+   *  .end method
+   *
+   *  .method public final native wait()V
+   *      .annotation system Ldalvik/annotation/Throws;
+   *          value = {
+   *              Ljava/lang/InterruptedException;
+   *          }
+   *      .end annotation
+   *
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   *
+   *  .method public final wait(J)V
+   *      .registers 4
+   *      .annotation system Ldalvik/annotation/Throws;
+   *          value = {
+   *              Ljava/lang/InterruptedException;
+   *          }
+   *      .end annotation
+   *      .prologue
+   *      const/4 v0, 0x0
+   *      invoke-virtual {p0, p1, p2, v0}, Ljava/lang/Object;->wait(JI)V
+   *      return-void
+   *  .end method
+   *
+   *  .method public final native wait(JI)V
+   *      .annotation system Ldalvik/annotation/Throws;
+   *          value = {
+   *              Ljava/lang/InterruptedException;
+   *          }
+   *      .end annotation
+   *
+   *      .annotation build Ldalvik/annotation/optimization/FastNative;
+   *      .end annotation
+   *  .end method
+   */
+  private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+      "ZGV4CjAzNQDUlMR9j03MYuOKekKs2p7zJzu2IfDb7RlMCgAAcAAAAHhWNBIAAAAAAAAAAIgJAAA6" +
+      "AAAAcAAAABEAAABYAQAADQAAAJwBAAACAAAAOAIAABYAAABIAgAAAQAAAPgCAAA0BwAAGAMAABgD" +
+      "AAA2AwAAOgMAAEADAABIAwAASwMAAFMDAABWAwAAWgMAAF0DAABgAwAAZAMAAGgDAACAAwAAnwMA" +
+      "ALsDAADoAwAA+gMAAA0EAAA1BAAATAQAAGEEAACDBAAAlwQAAKsEAADGBAAA3QQAAPAEAAD9BAAA" +
+      "AAUAAAQFAAAJBQAADQUAABAFAAAUBQAAHAUAACMFAAArBQAANQUAAD8FAABIBQAAUgUAAGQFAAB8" +
+      "BQAAiwUAAJUFAACnBQAAugUAAM0FAADVBQAA3QUAAOgFAADtBQAA/QUAAA8GAAAcBgAAJgYAAC0G" +
+      "AAAGAAAACAAAAAwAAAANAAAADgAAAA8AAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAA" +
+      "ABkAAAAcAAAAIAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAPAYAAAkAAAAGAAAAAAAAAAkAAAALAAAA" +
+      "AAAAAAkAAAAMAAAAAAAAAAoAAAAMAAAARAYAAAsAAAANAAAAVAYAABwAAAAPAAAAAAAAAB0AAAAP" +
+      "AAAATAYAAB4AAAAPAAAANAYAAB8AAAAPAAAAPAYAAB8AAAAPAAAAVAYAACEAAAAQAAAAPAYAAAsA" +
+      "BgA0AAAACwAAADUAAAACAAoAGgAAAAYABAAnAAAABwALAAMAAAAJAAUANgAAAAsABwADAAAACwAD" +
+      "ACMAAAALAAwAJAAAAAsABwAlAAAACwACACYAAAALAAAAKAAAAAsAAQApAAAACwABACoAAAALAAMA" +
+      "KwAAAAsABwAxAAAACwAHADIAAAALAAQANwAAAAsABwA5AAAACwAIADkAAAALAAkAOQAAAA0ABwAD" +
+      "AAAADQAGACIAAAANAAQANwAAAAsAAAABAAAA/////wAAAAAbAAAA0AYAAD4JAAAAAAAAHCBkb2Vz" +
+      "bid0IGltcGxlbWVudCBDbG9uZWFibGUAAigpAAQ8Kj47AAY8aW5pdD4AAUAABkNsYXNzIAABSQAC" +
+      "SUwAAUoAAUwAAkxJAAJMTAAWTGFydC90ZXN0L1Rlc3RXYXRjaGVyOwAdTGRhbHZpay9hbm5vdGF0" +
+      "aW9uL1NpZ25hdHVyZTsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ACtMZGFsdmlrL2Fubm90" +
+      "YXRpb24vb3B0aW1pemF0aW9uL0Zhc3ROYXRpdmU7ABBMamF2YS9sYW5nL0NsYXNzABFMamF2YS9s" +
+      "YW5nL0NsYXNzOwAmTGphdmEvbGFuZy9DbG9uZU5vdFN1cHBvcnRlZEV4Y2VwdGlvbjsAFUxqYXZh" +
+      "L2xhbmcvQ2xvbmVhYmxlOwATTGphdmEvbGFuZy9JbnRlZ2VyOwAgTGphdmEvbGFuZy9JbnRlcnJ1" +
+      "cHRlZEV4Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlM" +
+      "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABVMamF2YS9sYW5nL1Rocm93YWJsZTsAEU5vdGlmeUNv" +
+      "bnN0cnVjdGVkAAtPYmplY3QuamF2YQABVgACVkoAA1ZKSQACVkwAAVoAAlpMAAZhcHBlbmQABWNs" +
+      "b25lAAZlcXVhbHMACGZpbmFsaXplAAhnZXRDbGFzcwAHZ2V0TmFtZQAIaGFzaENvZGUAEGlkZW50" +
+      "aXR5SGFzaENvZGUAFmlkZW50aXR5SGFzaENvZGVOYXRpdmUADWludGVybmFsQ2xvbmUACGxvY2tX" +
+      "b3JkABBsb2NrV29yZEhhc2hNYXNrABFsb2NrV29yZFN0YXRlSGFzaAARbG9ja1dvcmRTdGF0ZU1h" +
+      "c2sABm1pbGxpcwAGbm90aWZ5AAlub3RpZnlBbGwAA29iagAOc2hhZG93JF9rbGFzc18AEHNoYWRv" +
+      "dyRfbW9uaXRvcl8AC3RvSGV4U3RyaW5nAAh0b1N0cmluZwAFdmFsdWUABHdhaXQAAAIAAAABAAAA" +
+      "AQAAAAsAAAABAAAAAAAAAAEAAAABAAAAAQAAAAwAAgQBOBwBGAcCBAE4HAEYCgIDATgcAhcQFwIC" +
+      "BAE4HAEYDgAFAAIDATgcAxcBFxAXAgAAAAAAAAAAAAEAAABaBgAAAgAAAGIGAAB8BgAAAQAAAGIG" +
+      "AAABAAAAagYAAAEAAAB0BgAAAQAAAHwGAAABAAAAfwYAAAAAAAABAAAACgAAAAAAAAAAAAAAsAYA" +
+      "AAUAAACUBgAABwAAALgGAAAIAAAAyAYAAAsAAADABgAADAAAAMAGAAANAAAAwAYAAA4AAADABgAA" +
+      "EAAAAJwGAAARAAAAqAYAABIAAACcBgAAKAAHDgBwATQHDi0DAC0BLQMDMAEtAwIvATwDAS4BeFsA" +
+      "7AEABw5LARoPOsYArAEBNAcOAMUEAAcOAEEABw4AaAAHDgCRAgAHDgCmAwExBw5LAAAAAQABAAEA" +
+      "AAA4BwAABAAAAHEQAAAAAA4ABwABAAEAAAA9BwAAGgAAAFJgAQAVAwDAFQIAgBQB////DxUEAMC1" +
+      "BBUFAIAzVAcAFAT///8PtQQPBHEQCwAGAAoEDwQEAAEAAgAAAFkHAAAyAAAAIDAIADkAKwAiAAcA" +
+      "IgENAHAQEwABABsCBQAAAG4gFAAhAAwBbhAIAAMADAJuEAEAAgAMAm4gFAAhAAwBGwIAAAAAbiAU" +
+      "ACEADAFuEBUAAQAMAXAgAgAQACcAcBAMAAMADAARAAMAAgAAAAAAZQcAAAYAAAAzIQQAEhAPABIA" +
+      "KP4BAAEAAAAAAGwHAAABAAAADgAAAAIAAQAAAAAAcgcAAAMAAABUEAAAEQAAAAIAAQABAAAAdwcA" +
+      "AAUAAABxEAoAAQAKAA8AAAADAAEAAgAAAHwHAAApAAAAIgANAHAQEwAAAG4QCAACAAwBbhABAAEA" +
+      "DAFuIBQAEAAMABsBBAAAAG4gFAAQAAwAbhAJAAIACgFxEAMAAQAMAW4gFAAQAAwAbhAVAAAADAAR" +
+      "AAAABAADAAQAAACCBwAABQAAABIAbkASACEDDgAAAgQLAIIBAYIBBIGABIwPBgikDwGKAgABggIA" +
+      "BQToDwEB3BABBPgQARGMEQEBpBEEkQIAAZECAAEBwBEBkQIAARGkEgGRAgAAABAAAAAAAAAAAQAA" +
+      "AAAAAAABAAAAOgAAAHAAAAACAAAAEQAAAFgBAAADAAAADQAAAJwBAAAEAAAAAgAAADgCAAAFAAAA" +
+      "FgAAAEgCAAAGAAAAAQAAAPgCAAACIAAAOgAAABgDAAABEAAABQAAADQGAAAEIAAABgAAAFoGAAAD" +
+      "EAAACQAAAIwGAAAGIAAAAQAAANAGAAADIAAACQAAADgHAAABIAAACQAAAIwHAAAAIAAAAQAAAD4J" +
+      "AAAAEAAAAQAAAIgJAAA=");
+
+  private static final String LISTENER_LOCATION =
+      System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar";
+
+  public static void main(String[] args) {
+    doTest();
+  }
+
+  private static void ensureTestWatcherInitialized() {
+    try {
+      // Make sure the TestWatcher class can be found from the Object <init> function.
+      addToBootClassLoader(LISTENER_LOCATION);
+      // Load TestWatcher from the bootclassloader and make sure it is initialized.
+      Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null);
+      // Bind the native functions of testwatcher_class.
+      bindFunctionsForClass(testwatcher_class);
+    } catch (Exception e) {
+      throw new Error("Exception while making testwatcher", e);
+    }
+  }
+
+  // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and
+  // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called.
+  private static void safePrintln(Object o) {
+    System.out.flush();
+    System.out.print("\t" + o + "\n");
+    System.out.flush();
+  }
+
+  private static void throwFrom(int depth) throws Exception {
+    if (depth <= 0) {
+      throw new Exception("Throwing the exception");
+    } else {
+      throwFrom(depth - 1);
+    }
+  }
+
+  public static void doTest() {
+    safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " +
+                "notified of object allocations");
+    // Make sure the TestWatcher class is initialized before we do anything else.
+    ensureTestWatcherInitialized();
+    safePrintln("Allocating an j.l.Object before redefining Object class");
+    // Make sure these aren't shown.
+    Object o = new Object();
+    safePrintln("Allocating a Transform before redefining Object class");
+    Transform t = new Transform();
+
+    // Redefine the Object Class.
+    safePrintln("Redefining the Object class to add a hook into the <init> method");
+    doCommonClassRedefinition(Object.class, CLASS_BYTES, DEX_BYTES);
+
+    safePrintln("Allocating an j.l.Object after redefining Object class");
+    Object o2 = new Object();
+    safePrintln("Allocating a Transform after redefining Object class");
+    Transform t2 = new Transform();
+
+    // This shouldn't cause the Object constructor to be run.
+    safePrintln("Allocating an int[] after redefining Object class");
+    int[] abc = new int[12];
+
+    // Try adding stuff to an array list.
+    safePrintln("Allocating an array list");
+    ArrayList<Object> al = new ArrayList<>();
+    safePrintln("Adding a bunch of stuff to the array list");
+    al.add(new Object());
+    al.add(new Object());
+    al.add(o2);
+    al.add(o);
+    al.add(t);
+    al.add(t2);
+    al.add(new Transform());
+
+    // Try adding stuff to a LinkedList
+    safePrintln("Allocating a linked list");
+    LinkedList<Object> ll = new LinkedList<>();
+    safePrintln("Adding a bunch of stuff to the linked list");
+    ll.add(new Object());
+    ll.add(new Object());
+    ll.add(o2);
+    ll.add(o);
+    ll.add(t);
+    ll.add(t2);
+    ll.add(new Transform());
+
+    // Try making an exception.
+    safePrintln("Throwing from down 4 stack frames");
+    try {
+      throwFrom(4);
+    } catch (Exception e) {
+      safePrintln("Exception caught.");
+    }
+
+    safePrintln("Finishing test!");
+  }
+
+  private static native void addToBootClassLoader(String s);
+
+  private static native void bindFunctionsForClass(Class<?> target);
+
+  // Transforms the class
+  private static native void doCommonClassRedefinition(Class<?> target,
+                                                       byte[] class_file,
+                                                       byte[] dex_file);
+}
diff --git a/test/980-redefine-object/src/Transform.java b/test/980-redefine-object/src/Transform.java
new file mode 100644
index 0000000..23f67d9
--- /dev/null
+++ b/test/980-redefine-object/src/Transform.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Transform { }
diff --git a/test/Android.bp b/test/Android.bp
index 9911af0..4ebfd74 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -275,6 +275,7 @@
         "936-search-onload/search_onload.cc",
         "944-transform-classloaders/classloader.cc",
         "945-obsolete-native/obsolete_native.cc",
+        "980-redefine-object/redefine_object.cc",
     ],
     shared_libs: [
         "libbase",
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index e4e571c..808e58a 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -444,27 +444,11 @@
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
 
+COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
 if [ "$RELOCATE" = "y" ]; then
-    COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
     FLAGS="${FLAGS} -Xrelocate"
-    if [ "$HOST" = "y" ]; then
-        # Run test sets a fairly draconian ulimit that we will likely blow right over
-        # since we are relocating. Get the total size of the /system/framework directory
-        # in 512 byte blocks and set it as the ulimit. This should be more than enough
-        # room.
-        if [ ! `uname` = "Darwin" ]; then  # TODO: Darwin doesn't support "du -B..."
-          ulimit -S $(du -c -B512 ${ANDROID_HOST_OUT}/framework 2>/dev/null | tail -1 | cut -f1) || exit 1
-        fi
-    fi
 else
     FLAGS="$FLAGS -Xnorelocate"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
-fi
-
-if [ "$HOST" = "y" ]; then
-    # Increase ulimit to 128MB in case we are running hprof test,
-    # or string append test with art-debug-gc.
-    ulimit -S 128000 || exit 1
 fi
 
 if [ "$HOST" = "n" ]; then
diff --git a/test/run-test b/test/run-test
index 1ac2857..1715423 100755
--- a/test/run-test
+++ b/test/run-test
@@ -766,27 +766,14 @@
 
   run_args="${run_args} --testlib ${testlib}"
 
-# To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
-build_file_size_limit=2048
-run_file_size_limit=2048
-
-# Add tests requiring a higher ulimit to this list. Ulimits might need to be raised to deal with
-# large amounts of expected output or large generated files.
-if echo "$test_dir" | grep -Eq "(083|089|961|964|971)" > /dev/null; then
-  build_file_size_limit=5120
-  run_file_size_limit=5120
-fi
-if [ "$run_checker" = "yes" -a "$target_mode" = "yes" ]; then
-  # We will need to `adb pull` the .cfg output from the target onto the host to
-  # run checker on it. This file can be big.
-  build_file_size_limit=32768
-  run_file_size_limit=32768
-fi
-if [ ${USE_JACK} = "false" ]; then
-  # Set ulimit if we build with dx only, Jack can generate big temp files.
-  if ! ulimit -S "$build_file_size_limit"; then
-    err_echo "ulimit file size setting failed"
-  fi
+# To cause tests to fail fast, limit the file sizes created by dx, dex2oat and
+# ART output to approximately 128MB. This should be more than sufficient
+# for any test while still catching cases of runaway output.
+# Set a hard limit to encourage ART developers to increase the ulimit here if
+# needed to support a test case rather than resetting the limit in the run
+# script for the particular test in question.
+if ! ulimit -f -H 128000; then
+  err_echo "ulimit file size setting failed"
 fi
 
 good="no"
@@ -797,9 +784,6 @@
     build_exit="$?"
     echo "build exit status: $build_exit" 1>&2
     if [ "$build_exit" = '0' ]; then
-        if ! ulimit -S "$run_file_size_limit"; then
-          err_echo "ulimit file size setting failed"
-        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" 2>&1
         run_exit="$?"
@@ -825,9 +809,6 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
-        if ! ulimit -S "$run_file_size_limit"; then
-          err_echo "ulimit file size setting failed"
-        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         if [ "$run_checker" = "yes" ]; then
@@ -862,9 +843,6 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
-        if ! ulimit -S "$run_file_size_limit"; then
-          err_echo "ulimit file size setting failed"
-        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         run_exit="$?"
@@ -934,9 +912,6 @@
       echo "${test_dir}: not bisecting, checker test." 1>&2
     else
       # Increase file size limit, bisection search can generate large logfiles.
-      if ! ulimit -S unlimited; then
-        err_echo "ulimit file size setting failed"
-      fi
       echo "${test_dir}: bisecting..." 1>&2
       cwd=`pwd`
       maybe_device_mode=""
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index b814e14..be84f89 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -184,10 +184,18 @@
   if env.ART_TEST_OPTIMIZING_GRAPH_COLOR:
     COMPILER_TYPES.add('regalloc_gc')
     OPTIMIZING_COMPILER_TYPES.add('regalloc_gc')
-  if env.ART_TEST_OPTIMIZING or not COMPILER_TYPES: # Default
+  if env.ART_TEST_OPTIMIZING:
     COMPILER_TYPES.add('optimizing')
     OPTIMIZING_COMPILER_TYPES.add('optimizing')
 
+  # By default we run all 'compiler' variants.
+  if not COMPILER_TYPES:
+    COMPILER_TYPES.add('optimizing')
+    COMPILER_TYPES.add('jit')
+    COMPILER_TYPES.add('interpreter')
+    COMPILER_TYPES.add('interp-ac')
+    OPTIMIZING_COMPILER_TYPES.add('optimizing')
+
   if env.ART_TEST_RUN_TEST_RELOCATE:
     RELOCATE_TYPES.add('relocate')
   if env.ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT:
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index 4ddd0aa..6316a9c 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -520,11 +520,14 @@
       LOG(FATAL) << "Could not load " << class_name;
     }
   }
+  BindFunctionsOnClass(jenv, env, klass.get());
+}
 
+void BindFunctionsOnClass(jvmtiEnv* jenv, JNIEnv* env, jclass klass) {
   // Use JVMTI to get the methods.
   jint method_count;
   jmethodID* methods;
-  jvmtiError methods_result = jenv->GetClassMethods(klass.get(), &method_count, &methods);
+  jvmtiError methods_result = jenv->GetClassMethods(klass, &method_count, &methods);
   if (methods_result != JVMTI_ERROR_NONE) {
     LOG(FATAL) << "Could not get methods";
   }
@@ -538,7 +541,7 @@
     }
     constexpr jint kNative = static_cast<jint>(kAccNative);
     if ((modifiers & kNative) != 0) {
-      BindMethod(jenv, env, klass.get(), methods[i]);
+      BindMethod(jenv, env, klass, methods[i]);
     }
   }
 
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 0a316ed..f10356d 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -81,6 +81,7 @@
 //
 // This will abort on failure.
 void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name);
+void BindFunctionsOnClass(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass);
 
 }  // namespace art