Merge "Refactor compact dex writing"
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 60c7a8f..d2cfa4f 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -461,6 +461,10 @@
 
   const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
 
+  HBasicBlock* GetSuccessor() const {
+    return successor_;
+  }
+
  private:
   // If not null, the block to branch to after the suspend check.
   HBasicBlock* const successor_;
@@ -1996,8 +2000,19 @@
 void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
                                                         HBasicBlock* successor) {
   SuspendCheckSlowPathMIPS* slow_path =
-    new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS(instruction, successor);
-  codegen_->AddSlowPath(slow_path);
+      down_cast<SuspendCheckSlowPathMIPS*>(instruction->GetSlowPath());
+
+  if (slow_path == nullptr) {
+    slow_path =
+        new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS(instruction, successor);
+    instruction->SetSlowPath(slow_path);
+    codegen_->AddSlowPath(slow_path);
+    if (successor != nullptr) {
+      DCHECK(successor->IsLoopHeader());
+    }
+  } else {
+    DCHECK_EQ(slow_path->GetSuccessor(), successor);
+  }
 
   __ LoadFromOffset(kLoadUnsignedHalfword,
                     TMP,
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5292638..28ca7cb 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -415,6 +415,10 @@
 
   const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS64"; }
 
+  HBasicBlock* GetSuccessor() const {
+    return successor_;
+  }
+
  private:
   // If not null, the block to branch to after the suspend check.
   HBasicBlock* const successor_;
@@ -1834,8 +1838,19 @@
 void InstructionCodeGeneratorMIPS64::GenerateSuspendCheck(HSuspendCheck* instruction,
                                                           HBasicBlock* successor) {
   SuspendCheckSlowPathMIPS64* slow_path =
-    new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS64(instruction, successor);
-  codegen_->AddSlowPath(slow_path);
+      down_cast<SuspendCheckSlowPathMIPS64*>(instruction->GetSlowPath());
+
+  if (slow_path == nullptr) {
+    slow_path =
+        new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS64(instruction, successor);
+    instruction->SetSlowPath(slow_path);
+    codegen_->AddSlowPath(slow_path);
+    if (successor != nullptr) {
+      DCHECK(successor->IsLoopHeader());
+    }
+  } else {
+    DCHECK_EQ(slow_path->GetSuccessor(), successor);
+  }
 
   __ LoadFromOffset(kLoadUnsignedHalfword,
                     TMP,
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 4a8fbf2..98ccce7 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -3203,6 +3203,26 @@
   }
 }
 
+// static boolean java.lang.Thread.interrupted()
+void IntrinsicLocationsBuilderMIPS::VisitThreadInterrupted(HInvoke* invoke) {
+  LocationSummary* locations =
+      new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitThreadInterrupted(HInvoke* invoke) {
+  MipsAssembler* assembler = GetAssembler();
+  Register out = invoke->GetLocations()->Out().AsRegister<Register>();
+  int32_t offset = Thread::InterruptedOffset<kMipsPointerSize>().Int32Value();
+  __ LoadFromOffset(kLoadWord, out, TR, offset);
+  MipsLabel done;
+  __ Beqz(out, &done);
+  __ Sync(0);
+  __ StoreToOffset(kStoreWord, ZERO, TR, offset);
+  __ Sync(0);
+  __ Bind(&done);
+}
+
 // Unimplemented intrinsics.
 
 UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
@@ -3232,8 +3252,6 @@
 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong)
 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject)
 
-UNIMPLEMENTED_INTRINSIC(MIPS, ThreadInterrupted)
-
 UNREACHABLE_INTRINSICS(MIPS)
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 512fb68..f629134 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2586,6 +2586,26 @@
   }
 }
 
+// static boolean java.lang.Thread.interrupted()
+void IntrinsicLocationsBuilderMIPS64::VisitThreadInterrupted(HInvoke* invoke) {
+  LocationSummary* locations =
+      new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitThreadInterrupted(HInvoke* invoke) {
+  Mips64Assembler* assembler = GetAssembler();
+  GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
+  int32_t offset = Thread::InterruptedOffset<kMips64PointerSize>().Int32Value();
+  __ LoadFromOffset(kLoadWord, out, TR, offset);
+  Mips64Label done;
+  __ Beqzc(out, &done);
+  __ Sync(0);
+  __ StoreToOffset(kStoreWord, ZERO, TR, offset);
+  __ Sync(0);
+  __ Bind(&done);
+}
+
 UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
 
@@ -2605,8 +2625,6 @@
 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong)
 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject)
 
-UNIMPLEMENTED_INTRINSIC(MIPS64, ThreadInterrupted)
-
 UNREACHABLE_INTRINSICS(MIPS64)
 
 #undef __
diff --git a/runtime/Android.bp b/runtime/Android.bp
index d9bb04e..52ec782 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -616,6 +616,7 @@
         "prebuilt_tools_test.cc",
         "reference_table_test.cc",
         "runtime_callbacks_test.cc",
+        "subtype_check_info_test.cc",
         "thread_pool_test.cc",
         "transaction_test.cc",
         "type_lookup_table_test.cc",
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index e18f110..3cf2b93 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -110,9 +110,9 @@
 #define SHADOWFRAME_DEX_PC_PTR_OFFSET (SHADOWFRAME_LINK_OFFSET + 3 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(SHADOWFRAME_DEX_PC_PTR_OFFSET,
             static_cast<int32_t>(art::ShadowFrame::DexPCPtrOffset()))
-#define SHADOWFRAME_CODE_ITEM_OFFSET (SHADOWFRAME_LINK_OFFSET + 4 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_CODE_ITEM_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::CodeItemOffset()))
+#define SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET (SHADOWFRAME_LINK_OFFSET + 4 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET,
+            static_cast<int32_t>(art::ShadowFrame::DexInstructionsOffset()))
 #define SHADOWFRAME_LOCK_COUNT_DATA_OFFSET (SHADOWFRAME_LINK_OFFSET + 5 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(SHADOWFRAME_LOCK_COUNT_DATA_OFFSET,
             static_cast<int32_t>(art::ShadowFrame::LockCountDataOffset()))
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index 74265bb..e158212 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -46,8 +46,6 @@
 DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_IS_GC_MARKING_OFFSET), (static_cast<int32_t>(art::Thread::IsGcMarkingOffset<art::kRuntimePointerSize>().Int32Value())))
 #define THREAD_CARD_TABLE_OFFSET 136
 DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_CARD_TABLE_OFFSET), (static_cast<int32_t>(art::Thread::CardTableOffset<art::kRuntimePointerSize>().Int32Value())))
-#define CODEITEM_INSNS_OFFSET 16
-DEFINE_CHECK_EQ(static_cast<int32_t>(CODEITEM_INSNS_OFFSET), (static_cast<int32_t>(__builtin_offsetof(art::DexFile::CodeItem, insns_))))
 #define MIRROR_CLASS_DEX_CACHE_OFFSET 16
 DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_CLASS_DEX_CACHE_OFFSET), (static_cast<int32_t>(art::mirror::Class::DexCacheOffset().Int32Value())))
 #define MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET 48
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 038405e..01b7d4e 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -314,7 +314,10 @@
             return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
                                                    false);
           }
-          bool returned = ExecuteMterpImpl(self, code_item, &shadow_frame, &result_register);
+          bool returned = ExecuteMterpImpl(self,
+                                           code_item->insns_,
+                                           &shadow_frame,
+                                           &result_register);
           if (returned) {
             return result_register;
           } else {
diff --git a/runtime/interpreter/interpreter_mterp_impl.h b/runtime/interpreter/interpreter_mterp_impl.h
index 1be20fa..7aa5a34 100644
--- a/runtime/interpreter/interpreter_mterp_impl.h
+++ b/runtime/interpreter/interpreter_mterp_impl.h
@@ -32,7 +32,7 @@
 
 // Mterp does not support transactions or access check, thus no templated versions.
 extern "C" bool ExecuteMterpImpl(Thread* self,
-                                 const DexFile::CodeItem* code_item,
+                                 const uint16_t* dex_instructions,
                                  ShadowFrame* shadow_frame,
                                  JValue* result_register) REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/interpreter/mterp/arm/entry.S b/runtime/interpreter/mterp/arm/entry.S
index 5781414..de617a9 100644
--- a/runtime/interpreter/mterp/arm/entry.S
+++ b/runtime/interpreter/mterp/arm/entry.S
@@ -46,8 +46,8 @@
     /* Remember the return register */
     str     r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the code_item */
-    str     r1, [r2, #SHADOWFRAME_CODE_ITEM_OFFSET]
+    /* Remember the dex instruction pointer */
+    str     r1, [r2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
 
     /* set up "named" registers */
     mov     rSELF, r0
@@ -55,8 +55,7 @@
     add     rFP, r2, #SHADOWFRAME_VREGS_OFFSET     @ point to vregs.
     VREG_INDEX_TO_ADDR rREFS, r0                   @ point to reference array in shadow frame
     ldr     r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET]   @ Get starting dex_pc.
-    add     rPC, r1, #CODEITEM_INSNS_OFFSET        @ Point to base of insns[]
-    add     rPC, rPC, r0, lsl #1                   @ Create direct pointer to 1st dex opcode
+    add     rPC, r1, r0, lsl #1                    @ Create direct pointer to 1st dex opcode
     EXPORT_PC
 
     /* Starting ibase */
diff --git a/runtime/interpreter/mterp/arm/footer.S b/runtime/interpreter/mterp/arm/footer.S
index c6801e5..f3a3ad2 100644
--- a/runtime/interpreter/mterp/arm/footer.S
+++ b/runtime/interpreter/mterp/arm/footer.S
@@ -97,11 +97,10 @@
     bl      MterpHandleException                    @ (self, shadow_frame)
     cmp     r0, #0
     beq     MterpExceptionReturn                    @ no local catch, back to caller.
-    ldr     r0, [rFP, #OFF_FP_CODE_ITEM]
+    ldr     r0, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
     ldr     r1, [rFP, #OFF_FP_DEX_PC]
     ldr     rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     rPC, r0, #CODEITEM_INSNS_OFFSET
-    add     rPC, rPC, r1, lsl #1                    @ generate new dex_pc_ptr
+    add     rPC, r0, r1, lsl #1                     @ generate new dex_pc_ptr
     /* Do we need to switch interpreters? */
     bl      MterpShouldSwitchInterpreters
     cmp     r0, #0
diff --git a/runtime/interpreter/mterp/arm/header.S b/runtime/interpreter/mterp/arm/header.S
index 597d9d4..51c2ba4 100644
--- a/runtime/interpreter/mterp/arm/header.S
+++ b/runtime/interpreter/mterp/arm/header.S
@@ -110,7 +110,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
@@ -130,9 +130,8 @@
 .endm
 
 .macro EXPORT_DEX_PC tmp
-    ldr  \tmp, [rFP, #OFF_FP_CODE_ITEM]
+    ldr  \tmp, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
     str  rPC, [rFP, #OFF_FP_DEX_PC_PTR]
-    add  \tmp, #CODEITEM_INSNS_OFFSET
     sub  \tmp, rPC, \tmp
     asr  \tmp, #1
     str  \tmp, [rFP, #OFF_FP_DEX_PC]
diff --git a/runtime/interpreter/mterp/arm/op_aget_wide.S b/runtime/interpreter/mterp/arm/op_aget_wide.S
index 853a7a4..66ec950 100644
--- a/runtime/interpreter/mterp/arm/op_aget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_aget_wide.S
@@ -10,7 +10,6 @@
     mov     r3, r0, lsr #8              @ r3<- CC
     GET_VREG r0, r2                     @ r0<- vBB (array object)
     GET_VREG r1, r3                     @ r1<- vCC (requested index)
-    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     cmp     r0, #0                      @ null array object?
     beq     common_errNullObject        @ yes, bail
     ldr     r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]    @ r3<- arrayObj->length
@@ -18,6 +17,7 @@
     cmp     r1, r3                      @ compare unsigned index, length
     bcs     common_errArrayIndex        @ index >= length, bail
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r9, lr, ip        @ Zero out the shadow regs
     ldrd    r2, [r0, #MIRROR_WIDE_ARRAY_DATA_OFFSET]  @ r2/r3<- vBB[vCC]
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm64/entry.S b/runtime/interpreter/mterp/arm64/entry.S
index 7306e4e..f3d40ff 100644
--- a/runtime/interpreter/mterp/arm64/entry.S
+++ b/runtime/interpreter/mterp/arm64/entry.S
@@ -36,8 +36,8 @@
     /* Remember the return register */
     str     x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the code_item */
-    str     x1, [x2, #SHADOWFRAME_CODE_ITEM_OFFSET]
+    /* Remember the dex instruction pointer */
+    str     x1, [x2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
 
     /* set up "named" registers */
     mov     xSELF, x0
@@ -45,8 +45,7 @@
     add     xFP, x2, #SHADOWFRAME_VREGS_OFFSET     // point to vregs.
     add     xREFS, xFP, w0, lsl #2                 // point to reference array in shadow frame
     ldr     w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET]   // Get starting dex_pc.
-    add     xPC, x1, #CODEITEM_INSNS_OFFSET        // Point to base of insns[]
-    add     xPC, xPC, w0, lsl #1                   // Create direct pointer to 1st dex opcode
+    add     xPC, x1, w0, lsl #1                    // Create direct pointer to 1st dex opcode
     EXPORT_PC
 
     /* Starting ibase */
diff --git a/runtime/interpreter/mterp/arm64/footer.S b/runtime/interpreter/mterp/arm64/footer.S
index fafa606..0ce3543 100644
--- a/runtime/interpreter/mterp/arm64/footer.S
+++ b/runtime/interpreter/mterp/arm64/footer.S
@@ -93,11 +93,10 @@
     add     x1, xFP, #OFF_FP_SHADOWFRAME
     bl      MterpHandleException                    // (self, shadow_frame)
     cbz     w0, MterpExceptionReturn                // no local catch, back to caller.
-    ldr     x0, [xFP, #OFF_FP_CODE_ITEM]
+    ldr     x0, [xFP, #OFF_FP_DEX_INSTRUCTIONS]
     ldr     w1, [xFP, #OFF_FP_DEX_PC]
     ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     xPC, x0, #CODEITEM_INSNS_OFFSET
-    add     xPC, xPC, x1, lsl #1                    // generate new dex_pc_ptr
+    add     xPC, x0, x1, lsl #1                     // generate new dex_pc_ptr
     /* Do we need to switch interpreters? */
     bl      MterpShouldSwitchInterpreters
     cbnz    w0, MterpFallback
diff --git a/runtime/interpreter/mterp/arm64/header.S b/runtime/interpreter/mterp/arm64/header.S
index cedfa49..47f12d2 100644
--- a/runtime/interpreter/mterp/arm64/header.S
+++ b/runtime/interpreter/mterp/arm64/header.S
@@ -116,7 +116,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 404c260..92dd19e 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -577,7 +577,7 @@
     self->AssertNoPendingException();
   }
   if (kTraceExecutionEnabled) {
-    uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
+    uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetDexInstructions();
     TraceExecution(*shadow_frame, inst, dex_pc);
   }
   if (kTestExportPC) {
diff --git a/runtime/interpreter/mterp/mterp_stub.cc b/runtime/interpreter/mterp/mterp_stub.cc
index 35f8f1c..e515ec4 100644
--- a/runtime/interpreter/mterp/mterp_stub.cc
+++ b/runtime/interpreter/mterp/mterp_stub.cc
@@ -38,8 +38,10 @@
 /*
  * The platform-specific implementation must provide this.
  */
-extern "C" bool ExecuteMterpImpl(Thread* self, const DexFile::CodeItem* code_item,
-                                 ShadowFrame* shadow_frame, JValue* result_register)
+extern "C" bool ExecuteMterpImpl(Thread* self,
+                                 const uint16_t* dex_instructions,
+                                 ShadowFrame* shadow_frame,
+                                 JValue* result_register)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   UNUSED(self); UNUSED(shadow_frame); UNUSED(code_item); UNUSED(result_register);
   UNIMPLEMENTED(art::FATAL);
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 8ca5bd4..69d7edb 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -117,7 +117,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
@@ -137,9 +137,8 @@
 .endm
 
 .macro EXPORT_DEX_PC tmp
-    ldr  \tmp, [rFP, #OFF_FP_CODE_ITEM]
+    ldr  \tmp, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
     str  rPC, [rFP, #OFF_FP_DEX_PC_PTR]
-    add  \tmp, #CODEITEM_INSNS_OFFSET
     sub  \tmp, rPC, \tmp
     asr  \tmp, #1
     str  \tmp, [rFP, #OFF_FP_DEX_PC]
@@ -365,8 +364,8 @@
     /* Remember the return register */
     str     r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the code_item */
-    str     r1, [r2, #SHADOWFRAME_CODE_ITEM_OFFSET]
+    /* Remember the dex instruction pointer */
+    str     r1, [r2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
 
     /* set up "named" registers */
     mov     rSELF, r0
@@ -374,8 +373,7 @@
     add     rFP, r2, #SHADOWFRAME_VREGS_OFFSET     @ point to vregs.
     VREG_INDEX_TO_ADDR rREFS, r0                   @ point to reference array in shadow frame
     ldr     r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET]   @ Get starting dex_pc.
-    add     rPC, r1, #CODEITEM_INSNS_OFFSET        @ Point to base of insns[]
-    add     rPC, rPC, r0, lsl #1                   @ Create direct pointer to 1st dex opcode
+    add     rPC, r1, r0, lsl #1                    @ Create direct pointer to 1st dex opcode
     EXPORT_PC
 
     /* Starting ibase */
@@ -1836,7 +1834,6 @@
     mov     r3, r0, lsr #8              @ r3<- CC
     GET_VREG r0, r2                     @ r0<- vBB (array object)
     GET_VREG r1, r3                     @ r1<- vCC (requested index)
-    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     cmp     r0, #0                      @ null array object?
     beq     common_errNullObject        @ yes, bail
     ldr     r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]    @ r3<- arrayObj->length
@@ -1844,6 +1841,7 @@
     cmp     r1, r3                      @ compare unsigned index, length
     bcs     common_errArrayIndex        @ index >= length, bail
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r9, lr, ip        @ Zero out the shadow regs
     ldrd    r2, [r0, #MIRROR_WIDE_ARRAY_DATA_OFFSET]  @ r2/r3<- vBB[vCC]
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -12044,11 +12042,10 @@
     bl      MterpHandleException                    @ (self, shadow_frame)
     cmp     r0, #0
     beq     MterpExceptionReturn                    @ no local catch, back to caller.
-    ldr     r0, [rFP, #OFF_FP_CODE_ITEM]
+    ldr     r0, [rFP, #OFF_FP_DEX_INSTRUCTIONS]
     ldr     r1, [rFP, #OFF_FP_DEX_PC]
     ldr     rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     rPC, r0, #CODEITEM_INSNS_OFFSET
-    add     rPC, rPC, r1, lsl #1                    @ generate new dex_pc_ptr
+    add     rPC, r0, r1, lsl #1                     @ generate new dex_pc_ptr
     /* Do we need to switch interpreters? */
     bl      MterpShouldSwitchInterpreters
     cmp     r0, #0
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index d4423ab..82edab4 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -123,7 +123,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
 /*
@@ -394,8 +394,8 @@
     /* Remember the return register */
     str     x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
 
-    /* Remember the code_item */
-    str     x1, [x2, #SHADOWFRAME_CODE_ITEM_OFFSET]
+    /* Remember the dex instruction pointer */
+    str     x1, [x2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
 
     /* set up "named" registers */
     mov     xSELF, x0
@@ -403,8 +403,7 @@
     add     xFP, x2, #SHADOWFRAME_VREGS_OFFSET     // point to vregs.
     add     xREFS, xFP, w0, lsl #2                 // point to reference array in shadow frame
     ldr     w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET]   // Get starting dex_pc.
-    add     xPC, x1, #CODEITEM_INSNS_OFFSET        // Point to base of insns[]
-    add     xPC, xPC, w0, lsl #1                   // Create direct pointer to 1st dex opcode
+    add     xPC, x1, w0, lsl #1                    // Create direct pointer to 1st dex opcode
     EXPORT_PC
 
     /* Starting ibase */
@@ -7182,11 +7181,10 @@
     add     x1, xFP, #OFF_FP_SHADOWFRAME
     bl      MterpHandleException                    // (self, shadow_frame)
     cbz     w0, MterpExceptionReturn                // no local catch, back to caller.
-    ldr     x0, [xFP, #OFF_FP_CODE_ITEM]
+    ldr     x0, [xFP, #OFF_FP_DEX_INSTRUCTIONS]
     ldr     w1, [xFP, #OFF_FP_DEX_PC]
     ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
-    add     xPC, x0, #CODEITEM_INSNS_OFFSET
-    add     xPC, xPC, x1, lsl #1                    // generate new dex_pc_ptr
+    add     xPC, x0, x1, lsl #1                     // generate new dex_pc_ptr
     /* Do we need to switch interpreters? */
     bl      MterpShouldSwitchInterpreters
     cbnz    w0, MterpFallback
diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S
index 514ecac..cbab61e 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -135,7 +135,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
@@ -371,15 +371,14 @@
 
     /* Remember the code_item */
     movl    IN_ARG1(%esp), %ecx
-    movl    %ecx, SHADOWFRAME_CODE_ITEM_OFFSET(%edx)
+    movl    %ecx, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(%edx)
 
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(%edx), %eax
     leal    SHADOWFRAME_VREGS_OFFSET(%edx), rFP
     leal    (rFP, %eax, 4), rREFS
     movl    SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax
-    lea     CODEITEM_INSNS_OFFSET(%ecx), rPC
-    lea     (rPC, %eax, 2), rPC
+    lea     (%ecx, %eax, 2), rPC
     EXPORT_PC
 
     /* Set up for backwards branches & osr profiling */
@@ -12749,10 +12748,9 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movl    OFF_FP_CODE_ITEM(rFP), %eax
+    movl    OFF_FP_DEX_INSTRUCTIONS(rFP), %eax
     movl    OFF_FP_DEX_PC(rFP), %ecx
-    lea     CODEITEM_INSNS_OFFSET(%eax), rPC
-    lea     (rPC, %ecx, 2), rPC
+    lea     (%eax, %ecx, 2), rPC
     movl    rPC, OFF_FP_DEX_PC_PTR(rFP)
     /* Do we need to switch interpreters? */
     call    SYMBOL(MterpShouldSwitchInterpreters)
diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S
index cfee2b8..83c3e4f 100644
--- a/runtime/interpreter/mterp/out/mterp_x86_64.S
+++ b/runtime/interpreter/mterp/out/mterp_x86_64.S
@@ -131,7 +131,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
 
@@ -354,15 +354,14 @@
     movq    IN_ARG3, SHADOWFRAME_RESULT_REGISTER_OFFSET(IN_ARG2)
 
     /* Remember the code_item */
-    movq    IN_ARG1, SHADOWFRAME_CODE_ITEM_OFFSET(IN_ARG2)
+    movq    IN_ARG1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(IN_ARG2)
 
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(IN_ARG2), %eax
     leaq    SHADOWFRAME_VREGS_OFFSET(IN_ARG2), rFP
     leaq    (rFP, %rax, 4), rREFS
     movl    SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax
-    leaq    CODEITEM_INSNS_OFFSET(IN_ARG1), rPC
-    leaq    (rPC, %rax, 2), rPC
+    leaq    (IN_ARG1, %rax, 2), rPC
     EXPORT_PC
 
     /* Starting ibase */
@@ -11967,10 +11966,9 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movq    OFF_FP_CODE_ITEM(rFP), %rax
+    movq    OFF_FP_DEX_INSTRUCTIONS(rFP), %rax
     mov     OFF_FP_DEX_PC(rFP), %ecx
-    leaq    CODEITEM_INSNS_OFFSET(%rax), rPC
-    leaq    (rPC, %rcx, 2), rPC
+    leaq    (%rax, %rcx, 2), rPC
     movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
     /* Do we need to switch interpreters? */
     call    SYMBOL(MterpShouldSwitchInterpreters)
diff --git a/runtime/interpreter/mterp/x86/entry.S b/runtime/interpreter/mterp/x86/entry.S
index 34adf53..055e834 100644
--- a/runtime/interpreter/mterp/x86/entry.S
+++ b/runtime/interpreter/mterp/x86/entry.S
@@ -53,15 +53,14 @@
 
     /* Remember the code_item */
     movl    IN_ARG1(%esp), %ecx
-    movl    %ecx, SHADOWFRAME_CODE_ITEM_OFFSET(%edx)
+    movl    %ecx, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(%edx)
 
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(%edx), %eax
     leal    SHADOWFRAME_VREGS_OFFSET(%edx), rFP
     leal    (rFP, %eax, 4), rREFS
     movl    SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax
-    lea     CODEITEM_INSNS_OFFSET(%ecx), rPC
-    lea     (rPC, %eax, 2), rPC
+    lea     (%ecx, %eax, 2), rPC
     EXPORT_PC
 
     /* Set up for backwards branches & osr profiling */
diff --git a/runtime/interpreter/mterp/x86/footer.S b/runtime/interpreter/mterp/x86/footer.S
index 088cb12..0b08cf9 100644
--- a/runtime/interpreter/mterp/x86/footer.S
+++ b/runtime/interpreter/mterp/x86/footer.S
@@ -115,10 +115,9 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movl    OFF_FP_CODE_ITEM(rFP), %eax
+    movl    OFF_FP_DEX_INSTRUCTIONS(rFP), %eax
     movl    OFF_FP_DEX_PC(rFP), %ecx
-    lea     CODEITEM_INSNS_OFFSET(%eax), rPC
-    lea     (rPC, %ecx, 2), rPC
+    lea     (%eax, %ecx, 2), rPC
     movl    rPC, OFF_FP_DEX_PC_PTR(rFP)
     /* Do we need to switch interpreters? */
     call    SYMBOL(MterpShouldSwitchInterpreters)
diff --git a/runtime/interpreter/mterp/x86/header.S b/runtime/interpreter/mterp/x86/header.S
index 3a2dcb7..370012f 100644
--- a/runtime/interpreter/mterp/x86/header.S
+++ b/runtime/interpreter/mterp/x86/header.S
@@ -128,7 +128,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME OFF_FP(0)
 
diff --git a/runtime/interpreter/mterp/x86_64/entry.S b/runtime/interpreter/mterp/x86_64/entry.S
index 0f969eb..83b845b 100644
--- a/runtime/interpreter/mterp/x86_64/entry.S
+++ b/runtime/interpreter/mterp/x86_64/entry.S
@@ -50,15 +50,14 @@
     movq    IN_ARG3, SHADOWFRAME_RESULT_REGISTER_OFFSET(IN_ARG2)
 
     /* Remember the code_item */
-    movq    IN_ARG1, SHADOWFRAME_CODE_ITEM_OFFSET(IN_ARG2)
+    movq    IN_ARG1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(IN_ARG2)
 
     /* set up "named" registers */
     movl    SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(IN_ARG2), %eax
     leaq    SHADOWFRAME_VREGS_OFFSET(IN_ARG2), rFP
     leaq    (rFP, %rax, 4), rREFS
     movl    SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax
-    leaq    CODEITEM_INSNS_OFFSET(IN_ARG1), rPC
-    leaq    (rPC, %rax, 2), rPC
+    leaq    (IN_ARG1, %rax, 2), rPC
     EXPORT_PC
 
     /* Starting ibase */
diff --git a/runtime/interpreter/mterp/x86_64/footer.S b/runtime/interpreter/mterp/x86_64/footer.S
index ac6cd19..3cc7532 100644
--- a/runtime/interpreter/mterp/x86_64/footer.S
+++ b/runtime/interpreter/mterp/x86_64/footer.S
@@ -98,10 +98,9 @@
     call    SYMBOL(MterpHandleException)
     testb   %al, %al
     jz      MterpExceptionReturn
-    movq    OFF_FP_CODE_ITEM(rFP), %rax
+    movq    OFF_FP_DEX_INSTRUCTIONS(rFP), %rax
     mov     OFF_FP_DEX_PC(rFP), %ecx
-    leaq    CODEITEM_INSNS_OFFSET(%rax), rPC
-    leaq    (rPC, %rcx, 2), rPC
+    leaq    (%rax, %rcx, 2), rPC
     movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
     /* Do we need to switch interpreters? */
     call    SYMBOL(MterpShouldSwitchInterpreters)
diff --git a/runtime/interpreter/mterp/x86_64/header.S b/runtime/interpreter/mterp/x86_64/header.S
index f229e84..9d21f3f 100644
--- a/runtime/interpreter/mterp/x86_64/header.S
+++ b/runtime/interpreter/mterp/x86_64/header.S
@@ -124,7 +124,7 @@
 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
-#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET)
 #define OFF_FP_COUNTDOWN_OFFSET OFF_FP(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET)
 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
 
diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h
index 80fdadb..88275cc 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -92,7 +92,7 @@
   }
 
   uint32_t GetDexPC() const {
-    return (dex_pc_ptr_ == nullptr) ? dex_pc_ : dex_pc_ptr_ - code_item_->insns_;
+    return (dex_pc_ptr_ == nullptr) ? dex_pc_ : dex_pc_ptr_ - dex_instructions_;
   }
 
   int16_t GetCachedHotnessCountdown() const {
@@ -146,12 +146,8 @@
     return &vregs_[i + NumberOfVRegs()];
   }
 
-  void SetCodeItem(const DexFile::CodeItem* code_item) {
-    code_item_ = code_item;
-  }
-
-  const DexFile::CodeItem* GetCodeItem() const {
-    return code_item_;
+  const uint16_t* GetDexInstructions() const {
+    return dex_instructions_;
   }
 
   float GetVRegFloat(size_t i) const {
@@ -324,8 +320,8 @@
     return OFFSETOF_MEMBER(ShadowFrame, dex_pc_ptr_);
   }
 
-  static size_t CodeItemOffset() {
-    return OFFSETOF_MEMBER(ShadowFrame, code_item_);
+  static size_t DexInstructionsOffset() {
+    return OFFSETOF_MEMBER(ShadowFrame, dex_instructions_);
   }
 
   static size_t CachedHotnessCountdownOffset() {
@@ -372,7 +368,7 @@
         method_(method),
         result_register_(nullptr),
         dex_pc_ptr_(nullptr),
-        code_item_(nullptr),
+        dex_instructions_(nullptr),
         number_of_vregs_(num_vregs),
         dex_pc_(dex_pc),
         cached_hotness_countdown_(0),
@@ -403,7 +399,8 @@
   ArtMethod* method_;
   JValue* result_register_;
   const uint16_t* dex_pc_ptr_;
-  const DexFile::CodeItem* code_item_;
+  // Dex instruction base of the code item.
+  const uint16_t* dex_instructions_;
   LockCountData lock_count_data_;  // This may contain GC roots when lock counting is active.
   const uint32_t number_of_vregs_;
   uint32_t dex_pc_;
diff --git a/runtime/subtype_check_bits.h b/runtime/subtype_check_bits.h
new file mode 100644
index 0000000..4305ff8
--- /dev/null
+++ b/runtime/subtype_check_bits.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_SUBTYPE_CHECK_BITS_H_
+#define ART_RUNTIME_SUBTYPE_CHECK_BITS_H_
+
+#include "base/bit_string.h"
+#include "base/bit_struct.h"
+#include "base/bit_utils.h"
+
+namespace art {
+
+/**
+ * The SubtypeCheckBits memory layout (in bits):
+ *
+ *                                 Variable
+ *                                     |
+ *        <---- up to 23 bits ---->    v               +---> 1 bit
+ *                                                     |
+ *  +-------------------------+--------+-----------+---++
+ *  |             Bitstring                        |    |
+ *  +-------------------------+--------+-----------+    |
+ *  |      Path To Root       |  Next  | (unused)  | OF |
+ *  +---+---------------------+--------+           |    |
+ *  |   |    |    |    | ...  |        | (0....0)  |    |
+ *  +---+---------------------+--------+-----------+----+
+ * MSB                                                LSB
+ *
+ * The bitstring takes up to 23 bits; anything exceeding that is truncated:
+ * - Path To Root is a list of chars, encoded as a BitString:
+ *     starting at the root (in MSB), each character is a sibling index unique to the parent,
+ *   Paths longer than BitString::kCapacity are truncated to fit within the BitString.
+ * - Next is a single BitStringChar (immediatelly following Path To Root)
+ *     When new children are assigned paths, they get allocated the parent's Next value.
+ *     The next value is subsequently incremented.
+ *
+ * The exact bit position of (unused) is variable-length:
+ * In the cases that the "Path To Root" + "Next" does not fill up the entire
+ * BitString capacity, the remaining bits are (unused) and left as 0s.
+ *
+ * There is also an additional "OF" (overflow) field to indicate that the
+ * PathToRoot has been truncated.
+ *
+ * See subtype_check.h and subtype_check_info.h for more details.
+ */
+BITSTRUCT_DEFINE_START(SubtypeCheckBits, /*size*/ BitString::BitStructSizeOf() + 1u)
+  BitStructUint</*lsb*/0, /*width*/1> overflow_;
+  BitStructField<BitString, /*lsb*/1> bitstring_;
+BITSTRUCT_DEFINE_END(SubtypeCheckBits);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_SUBTYPE_CHECK_BITS_H_
diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h
new file mode 100644
index 0000000..f60e0ac
--- /dev/null
+++ b/runtime/subtype_check_info.h
@@ -0,0 +1,527 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
+#define ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
+
+#include "base/bit_string.h"
+#include "subtype_check_bits.h"
+
+// Forward-declare for testing purposes.
+struct SubtypeCheckInfoTest;
+
+namespace art {
+
+/**
+ * SubtypeCheckInfo is a logical label for the class SubtypeCheck data, which is necessary to
+ * perform efficient O(1) subtype comparison checks. See also subtype_check.h
+ * for the more general explanation of how the labels are used overall.
+ *
+ * For convenience, we also store the class depth within an SubtypeCheckInfo, since nearly all
+ * calculations are dependent on knowing the depth of the class.
+ *
+ * A SubtypeCheckInfo logically has:
+ *          * Depth - How many levels up to the root (j.l.Object)?
+ *          * PathToRoot - Possibly truncated BitString that encodes path to root
+ *          * Next - The value a newly inserted Child would get appended to its path.
+ *          * Overflow - If this path can never become a full path.
+ *
+ * Depending on the values of the above, it can be in one of these logical states,
+ * which are introduced in subtype_check.h:
+ *
+ *               Transient States                         Terminal States
+ *
+ *  +-----------------+     +--------------------+     +-------------------+
+ *  |                 |     |                    |     |                   |
+ *  |  Uninitialized  | +--->    Initialized     | +--->     Assigned      |
+ *  |                 |     |                    |     |                   |
+ *  +--------+--------+     +---------+----------+     +-------------------+
+ *           |                        |
+ *           |                        |
+ *           |                        |                +-------------------+
+ *           |                        +---------------->                   |
+ *           |                                         |     Overflowed    |
+ *           +----------------------------------------->                   |
+ *                                                     +-------------------+
+ *
+ * Invariants:
+ *
+ *   Initialized      => Parent >= Initialized
+ *
+ *   Assigned         => Parent == Assigned
+ *
+ *   Overflowed       => Parent == Overflowed || Parent.Next == Overflowed
+ *
+ * Thread-safety invariants:
+ *
+ *   Initialized      => Parent == Assigned
+ *   // For a class that has an Initialized bitstring, its superclass needs to have an
+ *   // Assigned bitstring since if its super class's bitstring is not Assigned yet,
+ *   // once it becomes Assigned, we cannot update its children's bitstrings to maintain
+ *   // all the tree invariants (below) atomically.
+ *
+ * --------------------------------------------------------------------------------------------
+ * Knowing these transitions above, we can more closely define the various terms and operations:
+ *
+ * Definitions:
+ *   (see also base/bit_string.h definitions).
+ *
+ *           Depth :=  Distance(Root, Class)
+ *     Safe(Depth) :=  Min(Depth, MaxBitstringLen)
+ *      PathToRoot :=  Bitstring[0..Safe(Depth))
+ *           Next  :=  Bitstring[Depth]
+ *           OF    ∈   {False, True}
+ *    TruncPath(D) :=  PathToRoot[0..D)
+ *
+ * Local Invariants:
+ *
+ *   Uninitialized <=> StrLen(PathToRoot) == 0
+ *                     Next == 0
+ *   Initialized   <=> StrLen(PathToRoot) < Depth
+ *                     Next == 0
+ *   Assigned      <=> StrLen(PathToRoot) == Depth
+ *                     Next > 1
+ *   Overflowed    <=> OF == True
+ *
+ * Tree Invariants:
+ *
+ *   Uninitialized =>
+ *     forall child ∈ Children(Class):
+ *       child.State == Uninitialized
+ *
+ *   Assigned       =>
+ *     forall child ∈ Children(Class):
+ *       Next > Child.PathToRoot[Child.Depth-1]
+ *
+ *   ! Uninitialized =>
+ *     forall ancestor ∈ Ancestors(Class):
+ *       TruncPath(ancestor.Depth) == ancestor.PathToRoot
+ *     forall unrelated ∈ (Classes - Ancestors(Class))
+ *         s.t. unrelated.State == Assigned:
+ *       TruncPath(unrelated.Depth) != unrelated.PathToRoot
+ *
+ * Thread-safety invariants:
+ *
+ *   Initialized   <=> StrLen(PathToRoot) == Safe(Depth - 1)
+ *   // Initialized State corresponds to exactly 1 bitstring.
+ *   // Cannot transition from Initialized to Initialized.
+ */
+struct SubtypeCheckInfo {
+  // See above documentation for possible state transitions.
+  enum State {
+    kUninitialized,
+    kInitialized,
+    kAssigned,
+    kOverflowed
+  };
+
+  // The result of a "src IsSubType target" check:
+  enum Result {
+    kUnknownSubtypeOf,  // Not enough data. Operand states weren't high enough.
+    kNotSubtypeOf,      // Enough data. src is not a subchild of the target.
+    kSubtypeOf          // Enough data. src is a subchild of the target.
+  };
+
+  // Chop off the depth, returning only the bitstring+of state.
+  // (Used to store into memory, since storing the depth would be redundant.)
+  SubtypeCheckBits GetSubtypeCheckBits() const {
+    return bitstring_and_of_;
+  }
+
+  // Create from the depth and the bitstring+of state.
+  // This is done for convenience to avoid passing in "depth" everywhere,
+  // since our current state is almost always a function of depth.
+  static SubtypeCheckInfo Create(SubtypeCheckBits compressed_value, size_t depth) {
+    SubtypeCheckInfo io;
+    io.depth_ = depth;
+    io.bitstring_and_of_ = compressed_value;
+    io.DcheckInvariants();
+    return io;
+  }
+
+  // Is this a subtype of the target?
+  //
+  // The current state must be at least Initialized, and the target state
+  // must be Assigned, otherwise the result will return kUnknownSubtypeOf.
+  //
+  // Normally, return kSubtypeOf or kNotSubtypeOf.
+  Result IsSubtypeOf(const SubtypeCheckInfo& target) {
+    if (target.GetState() != SubtypeCheckInfo::kAssigned) {
+      return Result::kUnknownSubtypeOf;
+    } else if (GetState() == SubtypeCheckInfo::kUninitialized) {
+      return Result::kUnknownSubtypeOf;
+    }
+
+    BitString::StorageType source_value = GetEncodedPathToRoot();
+    BitString::StorageType target_value = target.GetEncodedPathToRoot();
+    BitString::StorageType target_mask = target.GetEncodedPathToRootMask();
+
+    bool result = (source_value & target_mask) == (target_value);
+    if (result) {
+      DCHECK_EQ(GetPathToRoot().Truncate(target.GetSafeDepth()), target.GetPathToRoot())
+          << "Source: " << *this << ", Target: " << target;
+    } else {
+      DCHECK_NE(GetPathToRoot().Truncate(target.GetSafeDepth()), target.GetPathToRoot())
+          << "Source: " << *this << ", Target: " << target;
+    }
+
+    // Note: We could've also used shifts here, as described in subtype_check_bits.h,
+    // but it doesn't make much of a difference in the Runtime since we aren't trying to optimize
+    // for code size.
+
+    return result ? Result::kSubtypeOf : Result::kNotSubtypeOf;
+  }
+
+  // Returns a new root SubtypeCheckInfo with a blank PathToRoot.
+  // Post-condition: The return valued has an Assigned state.
+  static SubtypeCheckInfo CreateRoot() {
+    SubtypeCheckInfo io{};  // NOLINT
+    io.depth_ = 0u;
+    io.SetNext(io.GetNext() + 1u);
+
+    // The root is always considered assigned once it is no longer Initialized.
+    DCHECK_EQ(SubtypeCheckInfo::kAssigned, io.GetState());
+    return io;
+  }
+
+  // Copies the current PathToRoot into the child.
+  //
+  // If assign_next is true, then also assign a new SubtypeCheckInfo for a child by
+  // assigning the current Next value to its PathToRoot[Depth] component.
+  // Updates the current Next value as a side effect.
+  //
+  // Preconditions: State is either Assigned or Overflowed.
+  // Returns: A new child >= Initialized state.
+  SubtypeCheckInfo CreateChild(bool assign_next) {
+    SubtypeCheckInfo child = *this;  // Copy everything (path, next, of).
+    child.depth_ = depth_ + 1u;
+
+    // Must be Assigned or Overflowed in order to create a subchild.
+    DCHECK(GetState() == kAssigned || GetState() == kOverflowed)
+        << "Unexpected bitstring state: " << GetState();
+
+    // Begin transition to >= Initialized.
+
+    // Always attempt to re-initialize Child's Next value.
+    // Next must be non-0 to disambiguate it from Uninitialized.
+    child.MaybeInitNext();
+
+    // Always clear the inherited Parent's next Value on the child.
+    OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{});  // NOLINT
+
+    // The state is now Initialized | Overflowed.
+    DCHECK_NE(kAssigned, child.GetState()) << child.GetBitString();
+    DCHECK_NE(kUninitialized, child.GetState()) << child.GetBitString();
+
+    if (assign_next == false) {
+      child.DcheckInvariants();
+      return child;
+    }
+
+    // Begin transition to >= Assigned.
+
+    // Assign attempt.
+    if (HasNext() && !bitstring_and_of_.overflow_) {
+      // Do not bother assigning if parent had overflowed.
+      BitStringChar next = GetNext();
+      if (next != next.MaximumValue()) {
+        // The parent's "next" value is now the child's latest path element.
+        OverwriteNextValueFromParent(/*inout*/&child, next);
+        // Update self next value, so that future CreateChild calls
+        // do not get the same path value.
+        SetNext(next + 1u);
+      } else {
+        child.MarkOverflowed();  // Too wide.
+      }
+    } else {
+      child.MarkOverflowed();  // Too deep, or parent was already overflowed.
+    }
+
+    // The state is now Assigned | Overflowed.
+    DCHECK(child.GetState() == kAssigned || child.GetState() == kOverflowed);
+
+    child.DcheckInvariants();
+    return child;
+  }
+
+  // Get the current state (Uninitialized, Initialized, Assigned, or Overflowed).
+  // See the "SubtypeCheckInfo" documentation above which explains how a state is determined.
+  State GetState() const {
+    if (GetBitString() == BitString{}) {  // NOLINT
+      // Empty bitstring (all 0s) -> uninitialized.
+      DCHECK(!bitstring_and_of_.overflow_);
+      return kUninitialized;
+    }
+
+    if (bitstring_and_of_.overflow_) {
+      // Overflowed if and only if the OF bit was set.
+      return kOverflowed;
+    }
+
+    // Either Assigned or Initialized.
+    BitString path_to_root = GetPathToRoot();
+
+    DCHECK(!HasNext() || GetNext() != BitStringChar{})  // NOLINT
+        << "Expected (Assigned|Initialized) state to have >0 Next value: "
+        << GetNext() << " path: " << path_to_root;
+
+    if (path_to_root.Length() == depth_) {
+      return kAssigned;
+    }
+
+    return kInitialized;
+  }
+
+  // Retrieve the path to root bitstring as a plain uintN_t value that is amenable to
+  // be used by a fast check "encoded_src & mask_target == encoded_target".
+  BitString::StorageType GetEncodedPathToRoot() const {
+    BitString::StorageType data = static_cast<BitString::StorageType>(GetPathToRoot());
+    // Bit strings are logically in the least-significant memory.
+    // Shift it so the bits are all most-significant.
+    return data << (BitSizeOf(data) - BitStructSizeOf<BitString>());
+  }
+
+  // Retrieve the path to root bitstring mask as a plain uintN_t that is amenable to
+  // be used by a fast check "encoded_src & mask_target == encoded_target".
+  BitString::StorageType GetEncodedPathToRootMask() const {
+    size_t num_bitchars = GetSafeDepth();
+    size_t bitlength = BitString::GetBitLengthTotalAtPosition(num_bitchars);
+
+    BitString::StorageType mask_all =
+        std::numeric_limits<BitString::StorageType>::max();
+    BitString::StorageType mask_lsb =
+        MaskLeastSignificant<BitString::StorageType>(
+            BitSizeOf<BitString::StorageType>() - bitlength);
+
+    BitString::StorageType result = mask_all & ~mask_lsb;
+
+    // TODO: refactor above code into MaskMostSignificant?
+    return result;
+  }
+
+  // Get the "Next" bitchar, assuming that there is one to get.
+  BitStringChar GetNext() const {
+    DCHECK(HasNext());
+    return GetBitString()[depth_];
+  }
+
+  // Try to get the Next value, if there is one.
+  // Returns: Whether or not there was a Next value.
+  bool MaybeGetNext(/*out*/BitStringChar* next) const {
+    DCHECK(next != nullptr);
+
+    if (HasNext()) {
+      *next = GetBitString()[depth_];
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  // Constructor intended for testing. Runs all invariant checks.
+  SubtypeCheckInfo(BitString path_to_root, BitStringChar next, bool overflow, size_t depth) {
+    SubtypeCheckBits iod;
+    iod.bitstring_ = path_to_root;
+    iod.overflow_ = overflow;
+
+    bitstring_and_of_ = iod;
+    depth_ = depth;
+
+    // Len(Path-to-root) <= Depth.
+    DCHECK_GE(depth_, path_to_root.Length())
+        << "Path was too long for the depth, path: " << path_to_root;
+
+    bool did_overlap = false;
+    if (HasNext()) {
+      if (kIsDebugBuild) {
+        did_overlap = (GetNext() != BitStringChar{});  // NOLINT
+      }
+
+      SetNext(next);
+
+      DCHECK_EQ(next, GetNext());
+    }
+    // "Next" must be set before we can check the invariants.
+    DcheckInvariants();
+    DCHECK(!did_overlap)
+          << "Path to root overlapped with Next value, path: " << path_to_root;
+    DCHECK_EQ(path_to_root, GetPathToRoot());
+  }
+
+  // Factory intended for testing. Skips DcheckInvariants.
+  static SubtypeCheckInfo MakeUnchecked(BitString bitstring, bool overflow, size_t depth) {
+    SubtypeCheckBits iod;
+    iod.bitstring_ = bitstring;
+    iod.overflow_ = overflow;
+
+    SubtypeCheckInfo io;
+    io.depth_ = depth;
+    io.bitstring_and_of_ = iod;
+
+    return io;
+  }
+
+  void SetNext(BitStringChar next) {
+    DCHECK(HasNext());
+    BitString bs = GetBitString();
+    bs.SetAt(depth_, next);
+    SetBitString(bs);
+  }
+
+  void SetNextUnchecked(BitStringChar next) {
+    BitString bs = GetBitString();
+    bs.SetAt(depth_, next);
+    SetBitStringUnchecked(bs);
+  }
+
+  void MaybeInitNext() {
+    if (HasNext()) {
+      // Clearing out the "Next" value like this
+      // is often an intermediate operation which temporarily
+      // violates the invariants. Do not do the extra dchecks.
+      SetNextUnchecked(BitStringChar{});  // NOLINT
+      SetNextUnchecked(GetNext()+1u);
+    }
+  }
+
+  BitString GetPathToRoot() const {
+    size_t end = GetSafeDepth();
+    return GetBitString().Truncate(end);
+  }
+
+  bool HasNext() const {
+    return depth_ < BitString::kCapacity;
+  }
+
+  void MarkOverflowed() {
+    bitstring_and_of_.overflow_ = true;
+  }
+
+  static constexpr bool HasBitStringCharStorage(size_t idx) {
+    return idx < BitString::kCapacity;
+  }
+
+  size_t GetSafeDepth() const {
+    return GetSafeDepth(depth_);
+  }
+
+  // Get a "safe" depth, one that is truncated to the bitstring max capacity.
+  // Using a value larger than this will cause undefined behavior.
+  static size_t GetSafeDepth(size_t depth) {
+    return std::min(depth, BitString::kCapacity);
+  }
+
+  BitString GetBitString() const {
+    return bitstring_and_of_.bitstring_;
+  }
+
+  void SetBitString(const BitString& val) {
+    SetBitStringUnchecked(val);
+    DcheckInvariants();
+  }
+
+  void SetBitStringUnchecked(const BitString& val) {
+    bitstring_and_of_.bitstring_ = val;
+  }
+
+  void OverwriteNextValueFromParent(/*inout*/SubtypeCheckInfo* child, BitStringChar value) const {
+    // Helper function for CreateChild.
+    if (HasNext()) {
+      // When we copied the "Next" value, it is now our
+      // last path component in the child.
+      // Always overwrite it with either a cleared value or the parent's Next value.
+      BitString bs = child->GetBitString();
+
+      // Safe write. This.Next always occupies same slot as Child[Depth_].
+      DCHECK(child->HasBitStringCharStorage(depth_));
+
+      bs.SetAt(depth_, value);
+
+      // The child is temporarily in a bad state until it is fixed up further.
+      // Do not do the normal dchecks which do not allow transient badness.
+      child->SetBitStringUnchecked(bs);
+    }
+  }
+
+  void DcheckInvariants() const {
+    if (kIsDebugBuild) {
+      CHECK_GE(GetSafeDepth(depth_ + 1u), GetBitString().Length())
+          << "Bitstring too long for depth, bitstring: " << GetBitString() << ", depth: " << depth_;
+
+      BitString path_to_root = GetPathToRoot();
+
+      // A 'null' (\0) character in path-to-root must be followed only
+      // by other null characters.
+      size_t i;
+      for (i = 0; i < BitString::kCapacity; ++i) {
+        BitStringChar bc = path_to_root[i];
+        if (bc == 0u) {
+          break;
+        }
+      }
+
+      // All characters following a 0 must also be 0.
+      for (; i < BitString::kCapacity; ++i) {
+        BitStringChar bc = path_to_root[i];
+        if (bc != 0u) {
+          LOG(FATAL) << "Path to root had non-0s following 0s: " << path_to_root;
+        }
+      }
+
+       // Trigger any dchecks in GetState.
+      (void)GetState();
+    }
+  }
+
+  SubtypeCheckInfo() = default;
+  size_t depth_;
+  SubtypeCheckBits bitstring_and_of_;
+
+  friend struct ::SubtypeCheckInfoTest;
+  friend std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io);
+};
+
+// Prints the SubtypeCheckInfo::State, e.g. "kUnitialized".
+inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo::State& state) {
+  switch (state) {
+    case SubtypeCheckInfo::kUninitialized:
+      os << "kUninitialized";
+      break;
+    case SubtypeCheckInfo::kInitialized:
+      os << "kInitialized";
+      break;
+    case SubtypeCheckInfo::kAssigned:
+      os << "kAssigned";
+      break;
+    case SubtypeCheckInfo::kOverflowed:
+      os << "kOverflowed";
+      break;
+    default:
+      os << "(Invalid SubtypeCheckInfo::State " << static_cast<int>(state) << ")";
+  }
+  return os;
+}
+
+// Prints e.g. "SubtypeCheckInfo{BitString[1,2,3], depth: 3, of:1}"
+inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io) {
+  os << "SubtypeCheckInfo{" << io.GetBitString() << ", "
+     << "depth: " << io.depth_ << ", of:" << io.bitstring_and_of_.overflow_ << "}";
+  return os;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
diff --git a/runtime/subtype_check_info_test.cc b/runtime/subtype_check_info_test.cc
new file mode 100644
index 0000000..bc2e84e
--- /dev/null
+++ b/runtime/subtype_check_info_test.cc
@@ -0,0 +1,421 @@
+/*
+ * 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 "subtype_check_info.h"
+
+#include "gtest/gtest.h"
+#include "android-base/logging.h"
+
+namespace art {
+
+constexpr size_t BitString::kBitSizeAtPosition[BitString::kCapacity];
+constexpr size_t BitString::kCapacity;
+
+};  // namespace art
+
+using namespace art;  // NOLINT
+
+// These helper functions are only used by the test,
+// so they are not in the main BitString class.
+std::string Stringify(BitString bit_string) {
+  std::stringstream ss;
+  ss << bit_string;
+  return ss.str();
+}
+
+BitStringChar MakeBitStringChar(size_t idx, size_t val) {
+  return BitStringChar(val, BitString::MaybeGetBitLengthAtPosition(idx));
+}
+
+BitStringChar MakeBitStringChar(size_t val) {
+  return BitStringChar(val, MinimumBitsToStore(val));
+}
+
+BitString MakeBitString(std::initializer_list<size_t> values = {}) {
+  CHECK_GE(BitString::kCapacity, values.size());
+
+  BitString bs{};  // NOLINT
+
+  size_t i = 0;
+  for (size_t val : values) {
+    bs.SetAt(i, MakeBitStringChar(i, val));
+    ++i;
+  }
+
+  return bs;
+}
+
+template <typename T>
+size_t AsUint(const T& value) {
+  size_t uint_value = 0;
+  memcpy(&uint_value, &value, sizeof(value));
+  return uint_value;
+}
+
+// Make max bistring, e.g. BitString[4095,7,255] for {12,3,8}
+template <size_t kCount = BitString::kCapacity>
+BitString MakeBitStringMax() {
+  BitString bs{};  // NOLINT
+
+  for (size_t i = 0; i < kCount; ++i) {
+    bs.SetAt(i,
+             MakeBitStringChar(i, MaxInt<BitStringChar::StorageType>(BitString::kBitSizeAtPosition[i])));
+  }
+
+  return bs;
+}
+
+BitString SetBitStringCharAt(BitString bit_string, size_t i, size_t val) {
+  BitString bs = bit_string;
+  bs.SetAt(i, MakeBitStringChar(i, val));
+  return bs;
+}
+
+struct SubtypeCheckInfoTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    android::base::InitLogging(/*argv*/nullptr);
+  }
+
+  virtual void TearDown() {
+  }
+
+  static SubtypeCheckInfo MakeSubtypeCheckInfo(BitString path_to_root = {},
+                                               BitStringChar next = {},
+                                               bool overflow = false,
+                                               size_t depth = 1u) {
+    // Depth=1 is good default because it will go through all state transitions,
+    // and its children will also go through all state transitions.
+    return SubtypeCheckInfo(path_to_root, next, overflow, depth);
+  }
+
+  static SubtypeCheckInfo MakeSubtypeCheckInfoInfused(BitString bs = {},
+                                                      bool overflow = false,
+                                                      size_t depth = 1u) {
+    // Depth=1 is good default because it will go through all state transitions,
+    // and its children will also go through all state transitions.
+    SubtypeCheckBits iod;
+    iod.bitstring_ = bs;
+    iod.overflow_ = overflow;
+    return SubtypeCheckInfo::Create(iod, depth);
+  }
+
+  static SubtypeCheckInfo MakeSubtypeCheckInfoUnchecked(BitString bs = {},
+                                                        bool overflow = false,
+                                                        size_t depth = 1u) {
+    // Depth=1 is good default because it will go through all state transitions,
+    // and its children will also go through all state transitions.
+    return SubtypeCheckInfo::MakeUnchecked(bs, overflow, depth);
+  }
+
+  static bool HasNext(SubtypeCheckInfo io) {
+    return io.HasNext();
+  }
+
+  static BitString GetPathToRoot(SubtypeCheckInfo io) {
+    return io.GetPathToRoot();
+  }
+
+  // Create an SubtypeCheckInfo with the same depth, but with everything else reset.
+  // Returns: SubtypeCheckInfo in the Uninitialized state.
+  static SubtypeCheckInfo CopyCleared(SubtypeCheckInfo sc) {
+    SubtypeCheckInfo cleared_copy{};  // NOLINT
+    cleared_copy.depth_ = sc.depth_;
+    DCHECK_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy.GetState());
+    return cleared_copy;
+  }
+};
+
+const char* GetExpectedMessageForDeathTest(const char* msg) {
+#ifdef ART_TARGET_ANDROID
+  // On Android, dcheck failure messages go to logcat,
+  // which gtest death tests does not check, and thus the tests would fail with
+  // "unexpected message ''"
+  UNUSED(msg);
+  return "";  // Still ensures there was a bad return code, but match anything.
+#else
+  return msg;
+#endif
+}
+
+TEST_F(SubtypeCheckInfoTest, IllegalValues) {
+  // This test relies on BitString being at least 3 large.
+  // It will need to be updated otherwise.
+  ASSERT_LE(3u, BitString::kCapacity);
+
+  // Illegal values during construction would cause a Dcheck failure and crash.
+  ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({1u}),
+                                    /*next*/MakeBitStringChar(0),
+                                    /*overflow*/false,
+                                    /*depth*/0u),
+               GetExpectedMessageForDeathTest("Path was too long for the depth"));
+  ASSERT_DEATH(MakeSubtypeCheckInfoInfused(MakeBitString({1u, 1u}),
+                                           /*overflow*/false,
+                                           /*depth*/0u),
+               GetExpectedMessageForDeathTest("Bitstring too long for depth"));
+  ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({1u}),
+                                    /*next*/MakeBitStringChar(0),
+                                    /*overflow*/false,
+                                    /*depth*/1u),
+               GetExpectedMessageForDeathTest("Expected \\(Assigned\\|Initialized\\) "
+                                              "state to have >0 Next value"));
+  ASSERT_DEATH(MakeSubtypeCheckInfoInfused(MakeBitString({0u, 2u, 1u}),
+                                           /*overflow*/false,
+                                           /*depth*/2u),
+               GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
+  ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({0u, 2u}),
+                                    /*next*/MakeBitStringChar(1u),
+                                    /*overflow*/false,
+                                    /*depth*/2u),
+               GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
+  ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({0u, 1u, 1u}),
+                                    /*next*/MakeBitStringChar(0),
+                                    /*overflow*/false,
+                                    /*depth*/3u),
+               GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
+
+  // These are really slow (~1sec per death test on host),
+  // keep them down to a minimum.
+}
+
+TEST_F(SubtypeCheckInfoTest, States) {
+  EXPECT_EQ(SubtypeCheckInfo::kUninitialized, MakeSubtypeCheckInfo().GetState());
+  EXPECT_EQ(SubtypeCheckInfo::kInitialized,
+            MakeSubtypeCheckInfo(/*path*/{}, /*next*/MakeBitStringChar(1)).GetState());
+  EXPECT_EQ(SubtypeCheckInfo::kOverflowed,
+            MakeSubtypeCheckInfo(/*path*/{},
+                                 /*next*/MakeBitStringChar(1),
+                                 /*overflow*/true,
+                                 /*depth*/1u).GetState());
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned,
+            MakeSubtypeCheckInfo(/*path*/MakeBitString({1u}),
+                                 /*next*/MakeBitStringChar(1),
+                                 /*overflow*/false,
+                                 /*depth*/1u).GetState());
+
+  // Test edge conditions: depth == BitString::kCapacity (No Next value).
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned,
+            MakeSubtypeCheckInfo(/*path*/MakeBitStringMax(),
+                                 /*next*/MakeBitStringChar(0),
+                                 /*overflow*/false,
+                                 /*depth*/BitString::kCapacity).GetState());
+  EXPECT_EQ(SubtypeCheckInfo::kInitialized,
+            MakeSubtypeCheckInfo(/*path*/MakeBitStringMax<BitString::kCapacity - 1u>(),
+                                 /*next*/MakeBitStringChar(0),
+                                 /*overflow*/false,
+                                 /*depth*/BitString::kCapacity).GetState());
+  // Test edge conditions: depth > BitString::kCapacity (Must overflow).
+  EXPECT_EQ(SubtypeCheckInfo::kOverflowed,
+            MakeSubtypeCheckInfo(/*path*/MakeBitStringMax(),
+                                 /*next*/MakeBitStringChar(0),
+                                 /*overflow*/true,
+                                 /*depth*/BitString::kCapacity + 1u).GetState());
+}
+
+TEST_F(SubtypeCheckInfoTest, NextValue) {
+  // Validate "Next" is correctly aliased as the Bitstring[Depth] character.
+  EXPECT_EQ(MakeBitStringChar(1u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
+                                                           /*overflow*/false,
+                                                           /*depth*/0u).GetNext());
+  EXPECT_EQ(MakeBitStringChar(2u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
+                                                           /*overflow*/false,
+                                                           /*depth*/1u).GetNext());
+  EXPECT_EQ(MakeBitStringChar(3u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
+                                                           /*overflow*/false,
+                                                           /*depth*/2u).GetNext());
+  EXPECT_EQ(MakeBitStringChar(1u), MakeSubtypeCheckInfoUnchecked(MakeBitString({0u, 2u, 1u}),
+                                                           /*overflow*/false,
+                                                           /*depth*/2u).GetNext());
+  // Test edge conditions: depth == BitString::kCapacity (No Next value).
+  EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<BitString::kCapacity>(),
+                                                     /*overflow*/false,
+                                                     /*depth*/BitString::kCapacity)));
+  // Anything with depth >= BitString::kCapacity has no next value.
+  EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<BitString::kCapacity>(),
+                                                     /*overflow*/false,
+                                                     /*depth*/BitString::kCapacity + 1u)));
+  EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax(),
+                                                     /*overflow*/false,
+                                                     /*depth*/std::numeric_limits<size_t>::max())));
+}
+
+template <size_t kPos = BitString::kCapacity>
+size_t LenForPos() { return BitString::GetBitLengthTotalAtPosition(kPos); }
+
+TEST_F(SubtypeCheckInfoTest, EncodedPathToRoot) {
+  using StorageType = BitString::StorageType;
+
+  SubtypeCheckInfo io =
+      MakeSubtypeCheckInfo(/*path_to_root*/MakeBitStringMax(),
+                           /*next*/BitStringChar{},  // NOLINT
+                           /*overflow*/false,
+                           /*depth*/BitString::kCapacity);
+  // 0b11111...000 where MSB == 1, and leading 1s = the maximum bitstring representation.
+  EXPECT_EQ(MaxInt<StorageType>(LenForPos()) << (BitSizeOf<StorageType>() - LenForPos()),
+            io.GetEncodedPathToRoot());
+
+  EXPECT_EQ(MaxInt<StorageType>(LenForPos()) << (BitSizeOf<StorageType>() - LenForPos()),
+            io.GetEncodedPathToRootMask());
+
+  // 0b11111...000 where MSB == 1, and leading 1s = the maximum bitstring representation.
+
+  // The rest of this test is written assuming kCapacity == 3 for convenience.
+  // Please update the test if this changes.
+  ASSERT_EQ(3u, BitString::kCapacity);
+  ASSERT_EQ(12u, BitString::kBitSizeAtPosition[0]);
+  ASSERT_EQ(3u, BitString::kBitSizeAtPosition[1]);
+  ASSERT_EQ(8u, BitString::kBitSizeAtPosition[2]);
+
+  SubtypeCheckInfo io2 =
+      MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
+                                   /*overflow*/false,
+                                   /*depth*/BitString::kCapacity);
+
+#define MAKE_ENCODED_PATH(pos0, pos1, pos2) (((pos0) << 3u << 8u << 9u) | ((pos1) << 8u << 9u) | ((pos2) << 9u))
+
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io2.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b11111111), io2.GetEncodedPathToRootMask());
+
+  SubtypeCheckInfo io3 =
+      MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
+                                   /*overflow*/false,
+                                   /*depth*/BitString::kCapacity - 1u);
+
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io3.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b111, 0b0), io3.GetEncodedPathToRootMask());
+
+  SubtypeCheckInfo io4 =
+      MakeSubtypeCheckInfoUnchecked(MakeBitString({0b1010101u}),
+                                   /*overflow*/false,
+                                   /*depth*/BitString::kCapacity - 2u);
+
+  EXPECT_EQ(MAKE_ENCODED_PATH(0b1010101u, 0b000, 0b0), io4.GetEncodedPathToRoot());
+  EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b000, 0b0), io4.GetEncodedPathToRootMask());
+}
+
+TEST_F(SubtypeCheckInfoTest, NewForRoot) {
+  SubtypeCheckInfo io = SubtypeCheckInfo::CreateRoot();
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned, io.GetState());  // Root is always assigned.
+  EXPECT_EQ(0u, GetPathToRoot(io).Length());  // Root's path length is 0.
+  EXPECT_TRUE(HasNext(io));  // Root always has a "Next".
+  EXPECT_EQ(MakeBitStringChar(1u), io.GetNext());  // Next>=1 to disambiguate from Uninitialized.
+}
+
+TEST_F(SubtypeCheckInfoTest, CopyCleared) {
+  SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
+  EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
+
+  SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
+  EXPECT_EQ(MakeBitStringChar(2u), root.GetNext());  // Next incremented for Assign.
+  EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
+
+  SubtypeCheckInfo cleared_copy = CopyCleared(childC);
+  EXPECT_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy.GetState());
+  EXPECT_EQ(MakeBitString({}), GetPathToRoot(cleared_copy));
+
+  // CopyCleared is just a thin wrapper around value-init and providing the depth.
+  SubtypeCheckInfo cleared_copy_value =
+      SubtypeCheckInfo::Create(SubtypeCheckBits{}, /*depth*/1u);  // NOLINT
+  EXPECT_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy_value.GetState());
+  EXPECT_EQ(MakeBitString({}), GetPathToRoot(cleared_copy_value));
+}
+
+TEST_F(SubtypeCheckInfoTest, NewForChild2) {
+  SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
+  EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
+
+  SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
+  EXPECT_EQ(MakeBitStringChar(2u), root.GetNext());  // Next incremented for Assign.
+  EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
+}
+
+TEST_F(SubtypeCheckInfoTest, NewForChild) {
+  SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
+  EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
+
+  SubtypeCheckInfo childA = root.CreateChild(/*assign*/false);
+  EXPECT_EQ(SubtypeCheckInfo::kInitialized, childA.GetState());
+  EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());  // Next unchanged for Initialize.
+  EXPECT_EQ(MakeBitString({}), GetPathToRoot(childA));
+
+  SubtypeCheckInfo childB = root.CreateChild(/*assign*/false);
+  EXPECT_EQ(SubtypeCheckInfo::kInitialized, childB.GetState());
+  EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());  // Next unchanged for Initialize.
+  EXPECT_EQ(MakeBitString({}), GetPathToRoot(childB));
+
+  SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
+  EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
+  EXPECT_EQ(MakeBitStringChar(2u), root.GetNext());  // Next incremented for Assign.
+  EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
+
+  {
+    size_t cur_depth = 1u;
+    SubtypeCheckInfo latest_child = childC;
+    while (cur_depth != BitString::kCapacity) {
+      latest_child = latest_child.CreateChild(/*assign*/true);
+      ASSERT_EQ(SubtypeCheckInfo::kAssigned, latest_child.GetState());
+      ASSERT_EQ(cur_depth + 1u, GetPathToRoot(latest_child).Length());
+      cur_depth++;
+    }
+
+    // Future assignments will result in a too-deep overflow.
+    SubtypeCheckInfo child_of_deep = latest_child.CreateChild(/*assign*/true);
+    EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of_deep.GetState());
+    EXPECT_EQ(GetPathToRoot(latest_child), GetPathToRoot(child_of_deep));
+
+    // Assignment of too-deep overflow also causes overflow.
+    SubtypeCheckInfo child_of_deep_2 = child_of_deep.CreateChild(/*assign*/true);
+    EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of_deep_2.GetState());
+    EXPECT_EQ(GetPathToRoot(child_of_deep), GetPathToRoot(child_of_deep_2));
+  }
+
+  {
+    size_t cur_next = 2u;
+    while (true) {
+      if (cur_next == MaxInt<BitString::StorageType>(BitString::kBitSizeAtPosition[0u])) {
+        break;
+      }
+
+      SubtypeCheckInfo child = root.CreateChild(/*assign*/true);
+      ASSERT_EQ(SubtypeCheckInfo::kAssigned, child.GetState());
+      ASSERT_EQ(MakeBitStringChar(cur_next+1u), root.GetNext());
+      ASSERT_EQ(MakeBitString({cur_next}), GetPathToRoot(child));
+
+      cur_next++;
+    }
+    // Now the root will be in a state that further assigns will be too-wide overflow.
+
+    // Initialization still succeeds.
+    SubtypeCheckInfo child = root.CreateChild(/*assign*/false);
+    EXPECT_EQ(SubtypeCheckInfo::kInitialized, child.GetState());
+    EXPECT_EQ(MakeBitStringChar(cur_next), root.GetNext());
+    EXPECT_EQ(MakeBitString({}), GetPathToRoot(child));
+
+    // Assignment goes to too-wide Overflow.
+    SubtypeCheckInfo child_of = root.CreateChild(/*assign*/true);
+    EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of.GetState());
+    EXPECT_EQ(MakeBitStringChar(cur_next), root.GetNext());
+    EXPECT_EQ(MakeBitString({}), GetPathToRoot(child_of));
+
+    // Assignment of overflowed child still succeeds.
+    // The path to root is the same.
+    SubtypeCheckInfo child_of2 = child_of.CreateChild(/*assign*/true);
+    EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of2.GetState());
+    EXPECT_EQ(GetPathToRoot(child_of), GetPathToRoot(child_of2));
+  }
+}
diff --git a/test/668-aiobe/expected.txt b/test/668-aiobe/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/668-aiobe/expected.txt
diff --git a/test/668-aiobe/info.txt b/test/668-aiobe/info.txt
new file mode 100644
index 0000000..e422601
--- /dev/null
+++ b/test/668-aiobe/info.txt
@@ -0,0 +1,2 @@
+Regression test for the mterp arm interpreter which used to throw
+the wrong exception when accessing out of bounds a long/double array.
diff --git a/test/668-aiobe/smali/TestCase.smali b/test/668-aiobe/smali/TestCase.smali
new file mode 100644
index 0000000..5fa62e9
--- /dev/null
+++ b/test/668-aiobe/smali/TestCase.smali
@@ -0,0 +1,30 @@
+#
+# 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.
+
+
+.class public LTestCase;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+    invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static run([DI)D
+.registers 2
+    aget-wide p0, p0, p1
+    return-wide p0
+.end method
diff --git a/test/668-aiobe/src/Main.java b/test/668-aiobe/src/Main.java
new file mode 100644
index 0000000..2bd30c4
--- /dev/null
+++ b/test/668-aiobe/src/Main.java
@@ -0,0 +1,36 @@
+/*
+ * 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.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    double[] array = new double[5];
+    try {
+      Class<?> c = Class.forName("TestCase");
+      Method m = c.getMethod("run", double[].class, int.class);
+      m.invoke(null, array, 42);
+    } catch (InvocationTargetException e) {
+      // expected
+      if (!(e.getCause() instanceof ArrayIndexOutOfBoundsException)) {
+        throw new Error("Expected ArrayIndexOutOfBoundsException, got " + e.getCause());
+      }
+      return;
+    }
+    throw new Error("Expected InvocationTargetException");
+  }
+}
diff --git a/test/911-get-stack-trace/check b/test/911-get-stack-trace/check
index 8358500..a46ea9e 100644
--- a/test/911-get-stack-trace/check
+++ b/test/911-get-stack-trace/check
@@ -19,4 +19,18 @@
   patch -p0 expected.txt < expected_jack.diff
 fi
 
+if [[ "$DX" == 'd8' ]]; then
+  patch -p0 expected.txt < expected_d8.diff
+fi
+
+./default-check "$@"
+if [[ "$?" == "0" ]]; then
+  exit 0;
+fi
+
+# We cannot always correctly determine if D8 was used because of (b/68406220).
+# So we are just going to try to see it matches the expect output of D8 no
+# matter what.
+patch -p0 expected.txt < expected_d8.diff
+
 ./default-check "$@"
diff --git a/test/911-get-stack-trace/expected_d8.diff b/test/911-get-stack-trace/expected_d8.diff
new file mode 100644
index 0000000..3ce9bed
--- /dev/null
+++ b/test/911-get-stack-trace/expected_d8.diff
@@ -0,0 +1,456 @@
+12c12
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+15c15
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+18c18
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+21c21
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+24c24
+<  doTest ()V 34 25
+---
+>  doTest ()V 33 25
+32c32
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+35c35
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+38c38
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+41c41
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+44c44
+<  doTest ()V 38 26
+---
+>  doTest ()V 37 26
+57c57
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+62c62
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+70c70
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+84c84
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+87c87
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+90c90
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+93c93
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+102c102
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+105c105
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+108c108
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+111c111
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+125c125
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+132c132
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+137c137
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+140c140
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+148c148
+<  printOrWait (IILart/ControlData;)V 44 54
+---
+>  printOrWait (IILart/ControlData;)V 45 54
+152c152
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+155c155
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+158c158
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+161c161
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+169c169
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+172c172
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+175c175
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+178c178
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+183c183
+<  printOrWait (IILart/ControlData;)V 44 54
+---
+>  printOrWait (IILart/ControlData;)V 45 54
+187c187
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+191c191
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+199c199
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+204c204
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+207c207
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+363c363
+<  doTest ()V 122 59
+---
+>  doTest ()V 119 59
+376c376
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+379c379
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+382c382
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+385c385
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+397c397
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+400c400
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+403c403
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+406c406
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+418c418
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+421c421
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+424c424
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+427c427
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+439c439
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+442c442
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+445c445
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+448c448
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+460c460
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+463c463
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+466c466
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+469c469
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+481c481
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+484c484
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+487c487
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+490c490
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+502c502
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+505c505
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+508c508
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+511c511
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+523c523
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+526c526
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+529c529
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+532c532
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+544c544
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+547c547
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+550c550
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+553c553
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+565c565
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+568c568
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+571c571
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+574c574
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+598c598
+<  doTest ()V 127 61
+---
+>  doTest ()V 124 61
+630c630
+<  doTest ()V 112 54
+---
+>  doTest ()V 109 54
+677c677
+<  doTest ()V 117 56
+---
+>  doTest ()V 114 56
+687c687
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+690c690
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+693c693
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+696c696
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+708c708
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+711c711
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+714c714
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+717c717
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+729c729
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+732c732
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+735c735
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+738c738
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+750c750
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+753c753
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+756c756
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+759c759
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+771c771
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+774c774
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+777c777
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+780c780
+<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+---
+>  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
+792c792
+< [public static void art.Frames.doTestSameThread(), 35]
+---
+> [public static void art.Frames.doTestSameThread(), 40]
+807c807
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+810c810
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+813c813
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+816c816
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+827c827
+< [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c]
+---
+> [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d]
+831c831
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+834c834
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+837c837
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
+840c840
+< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+---
+> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index d1ea15e..53b5093 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -35,7 +35,7 @@
 using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK)
 
 java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES
-common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target"
+common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target libjdwp"
 mode="target"
 j_arg="-j$(nproc)"
 showcommands=
diff --git a/tools/cpp-define-generator/offset_codeitem.def b/tools/cpp-define-generator/offset_codeitem.def
deleted file mode 100644
index e5acd1d..0000000
--- a/tools/cpp-define-generator/offset_codeitem.def
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-// Offsets within CodeItem.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include <cstddef>      // offsetof
-#include "dex_file.h"   // art::DexFile
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_CODEITEM_OFFSET(field_name) \
-  DEFINE_OFFSET_EXPR(CodeItem, field_name, int32_t, offsetof(art::DexFile::CodeItem, field_name ## _))
-
-//                     Field Name
-DEFINE_CODEITEM_OFFSET(insns)
-
-#undef DEFINE_CODEITEM_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offsets_all.def b/tools/cpp-define-generator/offsets_all.def
index c2e8c97..31587d8 100644
--- a/tools/cpp-define-generator/offsets_all.def
+++ b/tools/cpp-define-generator/offsets_all.def
@@ -40,7 +40,6 @@
 #include "offset_thread.def"
 // TODO: SHADOW_FRAME depends on __SIZEOF__POINTER__
 // #include "offset_shadow_frame.def"
-#include "offset_codeitem.def"
 // TODO: MIRROR_OBJECT_HEADER_SIZE (depends on #ifdef read barrier)
 #include "offset_mirror_class.def"
 #include "offset_mirror_dex_cache.def"
diff --git a/tools/libjdwp_oj_art_failures.txt b/tools/libjdwp_oj_art_failures.txt
new file mode 100644
index 0000000..e0f243c
--- /dev/null
+++ b/tools/libjdwp_oj_art_failures.txt
@@ -0,0 +1,65 @@
+/*
+ * This file contains expectations for ART's buildbot. The purpose of this file is
+ * to temporarily list failing tests and not break the bots.
+ */
+[
+{
+  description: "Test fails due to unexpectedly getting the thread-groups of zombie threads",
+  result: EXEC_FAILED,
+  bug: 66906414,
+  name: "org.apache.harmony.jpda.tests.jdwp.ThreadReference.ThreadGroup002Test#testThreadGroup002"
+},
+{
+  description: "Test fails due to modifiers not including ACC_SUPER",
+  result: EXEC_FAILED,
+  bug: 66906055,
+  name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.ModifiersTest#testModifiers001"
+},
+{
+  description: "Test fails due to static values not being set correctly.",
+  result: EXEC_FAILED,
+  bug: 66905894,
+  name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues006Test#testGetValues006"
+},
+{
+  description: "Tests fail with assertion error on slot number",
+  result: EXEC_FAILED,
+  bug: 66905468,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableTest#testVariableTableTest001",
+           "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableWithGenericTest#testVariableTableWithGenericTest001" ]
+},
+{
+  description: "Test fails with Error VM_DEAD when trying to resume during VM_DEATH event",
+  result: EXEC_FAILED,
+  bug: 66904725,
+  name: "org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test#testVMDeathRequest"
+},
+/* TODO Categorize these failures more. */
+{
+  description: "Tests that fail on both ART and RI. These tests are likely incorrect",
+  result: EXEC_FAILED,
+  bug: 66906734,
+  names: [ "org.apache.harmony.jpda.tests.jdwp.ArrayReference.SetValues003Test#testSetValues003_InvalidIndex",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethod002Test#testInvokeMethod_wrong_argument_types",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest#testInvokeMethod002",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest#testInvokeMethod003",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceTest#testNewInstance002",
+           "org.apache.harmony.jpda.tests.jdwp.ClassType.SetValues002Test#testSetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.Events.ClassPrepare002Test#testClassPrepareCausedByDebugger",
+           "org.apache.harmony.jpda.tests.jdwp.Events.ExceptionCaughtTest#testExceptionEvent_ThrowLocation_FromNative",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.DisableCollectionTest#testDisableCollection_null",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection_invalid",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection_null",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.GetValues002Test#testGetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.SetValues003Test#testSetValues003",
+           "org.apache.harmony.jpda.tests.jdwp.ObjectReference.SetValuesTest#testSetValues001",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.FieldsWithGenericTest#testFieldsWithGeneric001",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues002Test#testGetValues002",
+           "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues004Test#testGetValues004",
+           "org.apache.harmony.jpda.tests.jdwp.StringReference.ValueTest#testStringReferenceValueTest001_NullString",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ChildrenTest#testChildren_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.NameTest#testName001_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ParentTest#testParent_NullObject",
+           "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ]
+}
+]
diff --git a/tools/run-libjdwp-tests.sh b/tools/run-libjdwp-tests.sh
new file mode 100755
index 0000000..964bb38
--- /dev/null
+++ b/tools/run-libjdwp-tests.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# 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.
+
+if [[ ! -d libcore ]];  then
+  echo "Script needs to be run at the root of the android tree"
+  exit 1
+fi
+
+if [[ `uname` != 'Linux' ]];  then
+  echo "Script cannot be run on $(uname). It is Linux only."
+  exit 2
+fi
+
+args=("$@")
+debug="no"
+has_variant="no"
+has_mode="no"
+mode="target"
+
+while true; do
+  if [[ $1 == "--debug" ]]; then
+    debug="yes"
+    shift
+  elif [[ "$1" == "--mode=jvm" ]]; then
+    has_mode="yes"
+    mode="ri"
+    shift
+  elif [[ "$1" == --mode=host ]]; then
+    has_mode="yes"
+    mode="host"
+    shift
+  elif [[ $1 == --variant=* ]]; then
+    has_variant="yes"
+    shift
+  elif [[ "$1" == "" ]]; then
+    break
+  else
+    shift
+  fi
+done
+
+if [[ "$has_mode" = "no" ]];  then
+  args+=(--mode=device)
+fi
+
+if [[ "$has_variant" = "no" ]];  then
+  args+=(--variant=X32)
+fi
+
+# We don't use full paths since it is difficult to determine them for device
+# tests and not needed due to resolution rules of dlopen.
+if [[ "$debug" = "yes" ]]; then
+  args+=(-Xplugin:libopenjdkjvmtid.so)
+else
+  args+=(-Xplugin:libopenjdkjvmti.so)
+fi
+
+expect_path=$PWD/art/tools/libjdwp_oj_art_failures.txt
+function verbose_run() {
+  echo "$@"
+  env "$@"
+}
+
+verbose_run ./art/tools/run-jdwp-tests.sh \
+            "${args[@]}"                  \
+            --jdwp-path "libjdwp.so"      \
+            --expectations "$expect_path"