Merge "signal_catcher: print errno when tombstoned_notify_completion fails."
diff --git a/build/Android.bp b/build/Android.bp
index ff762dd..2c959d4 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -67,10 +67,6 @@
             cflags: [
                 "-DART_TARGET",
 
-                // Enable missing-noreturn only on non-Mac. As lots of things are not implemented
-                // for Apple, it's a pain.
-                "-Wmissing-noreturn",
-
                 // To use oprofile_android --callgraph, uncomment this and recompile with
                 //    mmma -j art
                 // "-fno-omit-frame-pointer",
@@ -83,7 +79,7 @@
                 "bionic/libc/private",
             ],
         },
-        linux_glibc: {
+        linux: {
             cflags: [
                 // Enable missing-noreturn only on non-Mac. As lots of things are not implemented for
                 // Apple, it's a pain.
diff --git a/compiler/jni/jni_cfi_test.cc b/compiler/jni/jni_cfi_test.cc
index 28709a1..5b57718 100644
--- a/compiler/jni/jni_cfi_test.cc
+++ b/compiler/jni/jni_cfi_test.cc
@@ -62,23 +62,24 @@
     const char* shorty = "IIFII";
 
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     std::unique_ptr<JniCallingConvention> jni_conv(
-        JniCallingConvention::Create(&arena,
+        JniCallingConvention::Create(&allocator,
                                      is_static,
                                      is_synchronized,
                                      /*is_critical_native*/false,
                                      shorty,
                                      isa));
     std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
-        ManagedRuntimeCallingConvention::Create(&arena, is_static, is_synchronized, shorty, isa));
+        ManagedRuntimeCallingConvention::Create(
+            &allocator, is_static, is_synchronized, shorty, isa));
     const int frame_size(jni_conv->FrameSize());
     ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
 
     // Assemble the method.
     std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm(
-        JNIMacroAssembler<kPointerSize>::Create(&arena, isa));
+        JNIMacroAssembler<kPointerSize>::Create(&allocator, isa));
     jni_asm->cfi().SetEnabled(true);
     jni_asm->BuildFrame(frame_size, mr_conv->MethodRegister(),
                         callee_save_regs, mr_conv->EntrySpills());
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 92b5c4d..e32b681 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -179,11 +179,11 @@
   }
 
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
+  ArenaAllocator allocator(&pool);
 
   // Calling conventions used to iterate over parameters to method
   std::unique_ptr<JniCallingConvention> main_jni_conv =
-      JniCallingConvention::Create(&arena,
+      JniCallingConvention::Create(&allocator,
                                    is_static,
                                    is_synchronized,
                                    is_critical_native,
@@ -193,7 +193,7 @@
 
   std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
       ManagedRuntimeCallingConvention::Create(
-          &arena, is_static, is_synchronized, shorty, instruction_set));
+          &allocator, is_static, is_synchronized, shorty, instruction_set));
 
   // Calling conventions to call into JNI method "end" possibly passing a returned reference, the
   //     method and the current thread.
@@ -209,7 +209,7 @@
   }
 
   std::unique_ptr<JniCallingConvention> end_jni_conv(
-      JniCallingConvention::Create(&arena,
+      JniCallingConvention::Create(&allocator,
                                    is_static,
                                    is_synchronized,
                                    is_critical_native,
@@ -218,7 +218,7 @@
 
   // Assembler that holds generated instructions
   std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm =
-      GetMacroAssembler<kPointerSize>(&arena, instruction_set, instruction_set_features);
+      GetMacroAssembler<kPointerSize>(&allocator, instruction_set, instruction_set_features);
   const CompilerOptions& compiler_options = driver->GetCompilerOptions();
   jni_asm->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo());
   jni_asm->SetEmitRunTimeChecksInDebugMode(compiler_options.EmitRunTimeChecksInDebugMode());
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index f84fea3..3d56833 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -354,8 +354,8 @@
 
 std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  arm::ArmVIXLAssembler assembler(&arena);
+  ArenaAllocator allocator(&pool);
+  arm::ArmVIXLAssembler assembler(&allocator);
 
   switch (key.GetType()) {
     case ThunkType::kMethodCall:
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 828c99b..663e43b 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -511,8 +511,8 @@
 
 std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  arm64::Arm64Assembler assembler(&arena);
+  ArenaAllocator allocator(&pool);
+  arm64::Arm64Assembler assembler(&allocator);
 
   switch (key.GetType()) {
     case ThunkType::kMethodCall: {
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index fe7ecd1..d7def77 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -29,7 +29,7 @@
                                                     uint32_t store_dex_pc) {
   HBasicBlock* block = branch_targets_[store_dex_pc];
   if (block == nullptr) {
-    block = new (arena_) HBasicBlock(graph_, semantic_dex_pc);
+    block = new (allocator_) HBasicBlock(graph_, semantic_dex_pc);
     branch_targets_[store_dex_pc] = block;
   }
   DCHECK_EQ(block->GetDexPc(), semantic_dex_pc);
@@ -200,7 +200,7 @@
 // Returns the TryItem stored for `block` or nullptr if there is no info for it.
 static const DexFile::TryItem* GetTryItem(
     HBasicBlock* block,
-    const ArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) {
+    const ScopedArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) {
   auto iterator = try_block_info.find(block->GetBlockId());
   return (iterator == try_block_info.end()) ? nullptr : iterator->second;
 }
@@ -212,7 +212,7 @@
 static void LinkToCatchBlocks(HTryBoundary* try_boundary,
                               const DexFile::CodeItem& code_item,
                               const DexFile::TryItem* try_item,
-                              const ArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) {
+                              const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) {
   for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
     try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress()));
   }
@@ -253,8 +253,8 @@
 
   // Keep a map of all try blocks and their respective TryItems. We do not use
   // the block's pointer but rather its id to ensure deterministic iteration.
-  ArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info(
-      std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info(
+      std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder));
 
   // Obtain TryItem information for blocks with throwing instructions, and split
   // blocks which are both try & catch to simplify the graph.
@@ -278,8 +278,8 @@
   }
 
   // Map from a handler dex_pc to the corresponding catch block.
-  ArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks(
-      std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks(
+      std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder));
 
   // Iterate over catch blocks, create artifical landing pads if necessary to
   // simplify the CFG, and set metadata.
@@ -302,8 +302,8 @@
       HBasicBlock* catch_block = GetBlockAt(address);
       bool is_try_block = (try_block_info.find(catch_block->GetBlockId()) != try_block_info.end());
       if (is_try_block || MightHaveLiveNormalPredecessors(catch_block)) {
-        HBasicBlock* new_catch_block = new (arena_) HBasicBlock(graph_, address);
-        new_catch_block->AddInstruction(new (arena_) HGoto(address));
+        HBasicBlock* new_catch_block = new (allocator_) HBasicBlock(graph_, address);
+        new_catch_block->AddInstruction(new (allocator_) HGoto(address));
         new_catch_block->AddSuccessor(catch_block);
         graph_->AddBlock(new_catch_block);
         catch_block = new_catch_block;
@@ -311,7 +311,7 @@
 
       catch_blocks.Put(address, catch_block);
       catch_block->SetTryCatchInformation(
-        new (arena_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
+        new (allocator_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
     }
     handlers_ptr = iterator.EndDataPointer();
   }
@@ -328,8 +328,8 @@
       if (GetTryItem(predecessor, try_block_info) != try_item) {
         // Found a predecessor not covered by the same TryItem. Insert entering
         // boundary block.
-        HTryBoundary* try_entry =
-            new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());
+        HTryBoundary* try_entry = new (allocator_) HTryBoundary(
+            HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());
         try_block->CreateImmediateDominator()->AddInstruction(try_entry);
         LinkToCatchBlocks(try_entry, code_item_, try_item, catch_blocks);
         break;
@@ -357,7 +357,7 @@
 
       // Insert TryBoundary and link to catch blocks.
       HTryBoundary* try_exit =
-          new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());
+          new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());
       graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit);
       LinkToCatchBlocks(try_exit, code_item_, try_item, catch_blocks);
     }
@@ -367,8 +367,8 @@
 bool HBasicBlockBuilder::Build() {
   DCHECK(graph_->GetBlocks().empty());
 
-  graph_->SetEntryBlock(new (arena_) HBasicBlock(graph_, kNoDexPc));
-  graph_->SetExitBlock(new (arena_) HBasicBlock(graph_, kNoDexPc));
+  graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc));
+  graph_->SetExitBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc));
 
   // TODO(dbrazdil): Do CreateBranchTargets and ConnectBasicBlocks in one pass.
   if (!CreateBranchTargets()) {
diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h
index 4a0f78c..79f7a7b 100644
--- a/compiler/optimizing/block_builder.h
+++ b/compiler/optimizing/block_builder.h
@@ -17,8 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_BLOCK_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_BLOCK_BUILDER_H_
 
-#include "base/arena_containers.h"
-#include "base/arena_object.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "dex_file.h"
 #include "nodes.h"
 
@@ -28,17 +28,21 @@
  public:
   HBasicBlockBuilder(HGraph* graph,
                      const DexFile* const dex_file,
-                     const DexFile::CodeItem& code_item)
-      : arena_(graph->GetAllocator()),
+                     const DexFile::CodeItem& code_item,
+                     ScopedArenaAllocator* local_allocator)
+      : allocator_(graph->GetAllocator()),
         graph_(graph),
         dex_file_(dex_file),
         code_item_(code_item),
+        local_allocator_(local_allocator),
         branch_targets_(code_item.insns_size_in_code_units_,
                         nullptr,
-                        arena_->Adapter(kArenaAllocGraphBuilder)),
-        throwing_blocks_(kDefaultNumberOfThrowingBlocks, arena_->Adapter(kArenaAllocGraphBuilder)),
+                        local_allocator->Adapter(kArenaAllocGraphBuilder)),
+        throwing_blocks_(kDefaultNumberOfThrowingBlocks,
+                         local_allocator->Adapter(kArenaAllocGraphBuilder)),
         number_of_branches_(0u),
-        quicken_index_for_dex_pc_(std::less<uint32_t>(), arena_->Adapter()) {}
+        quicken_index_for_dex_pc_(std::less<uint32_t>(),
+                                  local_allocator->Adapter(kArenaAllocGraphBuilder)) {}
 
   // Creates basic blocks in `graph_` at branch target dex_pc positions of the
   // `code_item_`. Blocks are connected but left unpopulated with instructions.
@@ -71,18 +75,19 @@
   // handler dex_pcs.
   bool MightHaveLiveNormalPredecessors(HBasicBlock* catch_block);
 
-  ArenaAllocator* const arena_;
+  ArenaAllocator* const allocator_;
   HGraph* const graph_;
 
   const DexFile* const dex_file_;
   const DexFile::CodeItem& code_item_;
 
-  ArenaVector<HBasicBlock*> branch_targets_;
-  ArenaVector<HBasicBlock*> throwing_blocks_;
+  ScopedArenaAllocator* const local_allocator_;
+  ScopedArenaVector<HBasicBlock*> branch_targets_;
+  ScopedArenaVector<HBasicBlock*> throwing_blocks_;
   size_t number_of_branches_;
 
   // A table to quickly find the quicken index for the first instruction of a basic block.
-  ArenaSafeMap<uint32_t, uint32_t> quicken_index_for_dex_pc_;
+  ScopedArenaSafeMap<uint32_t, uint32_t> quicken_index_for_dex_pc_;
 
   static constexpr size_t kDefaultNumberOfThrowingBlocks = 2u;
 
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 0255e73..9c2068e 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -18,7 +18,8 @@
 
 #include <limits>
 
-#include "base/arena_containers.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "induction_var_range.h"
 #include "nodes.h"
 #include "side_effects_analysis.h"
@@ -287,7 +288,7 @@
  */
 class ValueRange : public ArenaObject<kArenaAllocBoundsCheckElimination> {
  public:
-  ValueRange(ArenaAllocator* allocator, ValueBound lower, ValueBound upper)
+  ValueRange(ScopedArenaAllocator* allocator, ValueBound lower, ValueBound upper)
       : allocator_(allocator), lower_(lower), upper_(upper) {}
 
   virtual ~ValueRange() {}
@@ -297,7 +298,7 @@
     return AsMonotonicValueRange() != nullptr;
   }
 
-  ArenaAllocator* GetAllocator() const { return allocator_; }
+  ScopedArenaAllocator* GetAllocator() const { return allocator_; }
   ValueBound GetLower() const { return lower_; }
   ValueBound GetUpper() const { return upper_; }
 
@@ -350,7 +351,7 @@
   }
 
  private:
-  ArenaAllocator* const allocator_;
+  ScopedArenaAllocator* const allocator_;
   const ValueBound lower_;  // inclusive
   const ValueBound upper_;  // inclusive
 
@@ -365,7 +366,7 @@
  */
 class MonotonicValueRange : public ValueRange {
  public:
-  MonotonicValueRange(ArenaAllocator* allocator,
+  MonotonicValueRange(ScopedArenaAllocator* allocator,
                       HPhi* induction_variable,
                       HInstruction* initial,
                       int32_t increment,
@@ -510,21 +511,19 @@
              const SideEffectsAnalysis& side_effects,
              HInductionVarAnalysis* induction_analysis)
       : HGraphVisitor(graph),
+        allocator_(graph->GetArenaStack()),
         maps_(graph->GetBlocks().size(),
-              ArenaSafeMap<int, ValueRange*>(
+              ScopedArenaSafeMap<int, ValueRange*>(
                   std::less<int>(),
-                  graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
-              graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
-        first_index_bounds_check_map_(
-            std::less<int>(),
-            graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
-        early_exit_loop_(
-            std::less<uint32_t>(),
-            graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
-        taken_test_loop_(
-            std::less<uint32_t>(),
-            graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
-        finite_loop_(graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)),
+                  allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
+              allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
+        first_index_bounds_check_map_(std::less<int>(),
+                                      allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
+        early_exit_loop_(std::less<uint32_t>(),
+                         allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
+        taken_test_loop_(std::less<uint32_t>(),
+                         allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
+        finite_loop_(allocator_.Adapter(kArenaAllocBoundsCheckElimination)),
         has_dom_based_dynamic_bce_(false),
         initial_block_size_(graph->GetBlocks().size()),
         side_effects_(side_effects),
@@ -569,7 +568,7 @@
 
  private:
   // Return the map of proven value ranges at the beginning of a basic block.
-  ArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) {
+  ScopedArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) {
     if (IsAddedBlock(basic_block)) {
       // Added blocks don't keep value ranges.
       return nullptr;
@@ -580,7 +579,7 @@
   // Traverse up the dominator tree to look for value range info.
   ValueRange* LookupValueRange(HInstruction* instruction, HBasicBlock* basic_block) {
     while (basic_block != nullptr) {
-      ArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block);
+      ScopedArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block);
       if (map != nullptr) {
         if (map->find(instruction->GetId()) != map->end()) {
           return map->Get(instruction->GetId());
@@ -668,8 +667,8 @@
       if (successor != nullptr) {
         bool overflow;
         bool underflow;
-        ValueRange* new_left_range = new (GetGraph()->GetAllocator()) ValueRange(
-            GetGraph()->GetAllocator(),
+        ValueRange* new_left_range = new (&allocator_) ValueRange(
+            &allocator_,
             left_range->GetBound(),
             right_range->GetBound().Add(left_compensation, &overflow, &underflow));
         if (!overflow && !underflow) {
@@ -677,8 +676,8 @@
                                    new_left_range);
         }
 
-        ValueRange* new_right_range = new (GetGraph()->GetAllocator()) ValueRange(
-            GetGraph()->GetAllocator(),
+        ValueRange* new_right_range = new (&allocator_) ValueRange(
+            &allocator_,
             left_range->GetBound().Add(right_compensation, &overflow, &underflow),
             right_range->GetBound());
         if (!overflow && !underflow) {
@@ -750,8 +749,8 @@
         if (overflow || underflow) {
           return;
         }
-        ValueRange* new_range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), ValueBound::Min(), new_upper);
+        ValueRange* new_range = new (&allocator_) ValueRange(
+            &allocator_, ValueBound::Min(), new_upper);
         ApplyRangeFromComparison(left, block, true_successor, new_range);
       }
 
@@ -762,8 +761,8 @@
         if (overflow || underflow) {
           return;
         }
-        ValueRange* new_range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), new_lower, ValueBound::Max());
+        ValueRange* new_range = new (&allocator_) ValueRange(
+            &allocator_, new_lower, ValueBound::Max());
         ApplyRangeFromComparison(left, block, false_successor, new_range);
       }
     } else if (cond == kCondGT || cond == kCondGE) {
@@ -774,8 +773,8 @@
         if (overflow || underflow) {
           return;
         }
-        ValueRange* new_range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), new_lower, ValueBound::Max());
+        ValueRange* new_range = new (&allocator_) ValueRange(
+            &allocator_, new_lower, ValueBound::Max());
         ApplyRangeFromComparison(left, block, true_successor, new_range);
       }
 
@@ -785,8 +784,8 @@
         if (overflow || underflow) {
           return;
         }
-        ValueRange* new_range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), ValueBound::Min(), new_upper);
+        ValueRange* new_range = new (&allocator_) ValueRange(
+            &allocator_, ValueBound::Min(), new_upper);
         ApplyRangeFromComparison(left, block, false_successor, new_range);
       }
     } else if (cond == kCondNE || cond == kCondEQ) {
@@ -795,8 +794,7 @@
         //   length == [c,d] yields [c, d] along true
         //   length != [c,d] yields [c, d] along false
         if (!lower.Equals(ValueBound::Min()) || !upper.Equals(ValueBound::Max())) {
-          ValueRange* new_range = new (GetGraph()->GetAllocator())
-              ValueRange(GetGraph()->GetAllocator(), lower, upper);
+          ValueRange* new_range = new (&allocator_) ValueRange(&allocator_, lower, upper);
           ApplyRangeFromComparison(
               left, block, cond == kCondEQ ? true_successor : false_successor, new_range);
         }
@@ -804,8 +802,8 @@
         //   length == 0 yields [1, max] along false
         //   length != 0 yields [1, max] along true
         if (lower.GetConstant() == 0 && upper.GetConstant() == 0) {
-          ValueRange* new_range = new (GetGraph()->GetAllocator())
-              ValueRange(GetGraph()->GetAllocator(), ValueBound(nullptr, 1), ValueBound::Max());
+          ValueRange* new_range = new (&allocator_) ValueRange(
+              &allocator_, ValueBound(nullptr, 1), ValueBound::Max());
           ApplyRangeFromComparison(
               left, block, cond == kCondEQ ? false_successor : true_successor, new_range);
         }
@@ -826,7 +824,7 @@
       // Non-constant index.
       ValueBound lower = ValueBound(nullptr, 0);        // constant 0
       ValueBound upper = ValueBound(array_length, -1);  // array_length - 1
-      ValueRange array_range(GetGraph()->GetAllocator(), lower, upper);
+      ValueRange array_range(&allocator_, lower, upper);
       // Try index range obtained by dominator-based analysis.
       ValueRange* index_range = LookupValueRange(index, block);
       if (index_range != nullptr && index_range->FitsIn(&array_range)) {
@@ -875,8 +873,7 @@
       } else {
         ValueBound lower = ValueBound(nullptr, constant + 1);
         ValueBound upper = ValueBound::Max();
-        ValueRange* range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), lower, upper);
+        ValueRange* range = new (&allocator_) ValueRange(&allocator_, lower, upper);
         AssignRange(block, array_length, range);
       }
     }
@@ -938,8 +935,8 @@
           ValueRange* range = nullptr;
           if (increment == 0) {
             // Add constant 0. It's really a fixed value.
-            range = new (GetGraph()->GetAllocator()) ValueRange(
-                GetGraph()->GetAllocator(),
+            range = new (&allocator_) ValueRange(
+                &allocator_,
                 ValueBound(initial_value, 0),
                 ValueBound(initial_value, 0));
           } else {
@@ -959,8 +956,8 @@
                 bound = increment > 0 ? ValueBound::Min() : ValueBound::Max();
               }
             }
-            range = new (GetGraph()->GetAllocator()) MonotonicValueRange(
-                GetGraph()->GetAllocator(),
+            range = new (&allocator_) MonotonicValueRange(
+                &allocator_,
                 phi,
                 initial_value,
                 increment,
@@ -1039,8 +1036,8 @@
                 !ValueBound::WouldAddOverflowOrUnderflow(c0, -c1)) {
               if ((c0 - c1) <= 0) {
                 // array.length + (c0 - c1) won't overflow/underflow.
-                ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange(
-                    GetGraph()->GetAllocator(),
+                ValueRange* range = new (&allocator_) ValueRange(
+                    &allocator_,
                     ValueBound(nullptr, right_const - upper.GetConstant()),
                     ValueBound(array_length, right_const - lower.GetConstant()));
                 AssignRange(sub->GetBlock(), sub, range);
@@ -1087,8 +1084,8 @@
         // than array_length.
         return;
       }
-      ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange(
-          GetGraph()->GetAllocator(),
+      ValueRange* range = new (&allocator_) ValueRange(
+          &allocator_,
           ValueBound(nullptr, std::numeric_limits<int32_t>::min()),
           ValueBound(left, 0));
       AssignRange(instruction->GetBlock(), instruction, range);
@@ -1113,8 +1110,8 @@
       if (constant > 0) {
         // constant serves as a mask so any number masked with it
         // gets a [0, constant] value range.
-        ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange(
-            GetGraph()->GetAllocator(),
+        ValueRange* range = new (&allocator_) ValueRange(
+            &allocator_,
             ValueBound(nullptr, 0),
             ValueBound(nullptr, constant));
         AssignRange(instruction->GetBlock(), instruction, range);
@@ -1139,8 +1136,8 @@
       //   array[i % 10];  // index value range [0, 9]
       //   array[i % -10]; // index value range [0, 9]
       // }
-      ValueRange* right_range = new (GetGraph()->GetAllocator()) ValueRange(
-          GetGraph()->GetAllocator(),
+      ValueRange* right_range = new (&allocator_) ValueRange(
+          &allocator_,
           ValueBound(nullptr, 1 - right_const),
           ValueBound(nullptr, right_const - 1));
 
@@ -1169,8 +1166,8 @@
     if (right->IsArrayLength()) {
       ValueBound lower = ValueBound::Min();  // ideally, lower should be '1-array_length'.
       ValueBound upper = ValueBound(right, -1);  // array_length - 1
-      ValueRange* right_range = new (GetGraph()->GetAllocator()) ValueRange(
-          GetGraph()->GetAllocator(),
+      ValueRange* right_range = new (&allocator_) ValueRange(
+          &allocator_,
           lower,
           upper);
       ValueRange* left_range = LookupValueRange(left, instruction->GetBlock());
@@ -1195,8 +1192,7 @@
         // which isn't available as an instruction yet. new_array will
         // be treated the same as new_array.length when it's used in a ValueBound.
         ValueBound upper = ValueBound(new_array, -right_const);
-        ValueRange* range = new (GetGraph()->GetAllocator())
-            ValueRange(GetGraph()->GetAllocator(), lower, upper);
+        ValueRange* range = new (&allocator_) ValueRange(&allocator_, lower, upper);
         ValueRange* existing_range = LookupValueRange(left, new_array->GetBlock());
         if (existing_range != nullptr) {
           range = existing_range->Narrow(range);
@@ -1291,10 +1287,10 @@
       HInstruction* base = value.GetInstruction();
       int32_t min_c = base == nullptr ? 0 : value.GetConstant();
       int32_t max_c = value.GetConstant();
-      ArenaVector<HBoundsCheck*> candidates(
-          GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination));
-      ArenaVector<HBoundsCheck*> standby(
-          GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination));
+      ScopedArenaVector<HBoundsCheck*> candidates(
+          allocator_.Adapter(kArenaAllocBoundsCheckElimination));
+      ScopedArenaVector<HBoundsCheck*> standby(
+          allocator_.Adapter(kArenaAllocBoundsCheckElimination));
       for (const HUseListNode<HInstruction*>& use : array_length->GetUses()) {
         // Another bounds check in same or dominated block?
         HInstruction* user = use.GetUser();
@@ -1378,7 +1374,7 @@
           v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) {
         DCHECK(v1.a_constant == 1 || v1.instruction == nullptr);
         DCHECK(v2.a_constant == 1 || v2.instruction == nullptr);
-        ValueRange index_range(GetGraph()->GetAllocator(),
+        ValueRange index_range(&allocator_,
                                ValueBound(v1.instruction, v1.b_constant),
                                ValueBound(v2.instruction, v2.b_constant));
         // If analysis reveals a certain OOB, disable dynamic BCE. Otherwise,
@@ -1410,10 +1406,10 @@
     HInstruction* base = value.GetInstruction();
     int32_t min_c = base == nullptr ? 0 : value.GetConstant();
     int32_t max_c = value.GetConstant();
-    ArenaVector<HBoundsCheck*> candidates(
-        GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination));
-    ArenaVector<HBoundsCheck*> standby(
-        GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination));
+    ScopedArenaVector<HBoundsCheck*> candidates(
+        allocator_.Adapter(kArenaAllocBoundsCheckElimination));
+    ScopedArenaVector<HBoundsCheck*> standby(
+        allocator_.Adapter(kArenaAllocBoundsCheckElimination));
     for (const HUseListNode<HInstruction*>& use : array_length->GetUses()) {
       HInstruction* user = use.GetUser();
       if (user->IsBoundsCheck() && loop == user->GetBlock()->GetLoopInformation()) {
@@ -1882,21 +1878,24 @@
     instruction->GetBlock()->RemoveInstruction(instruction);
   }
 
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator_;
+
   // A set of maps, one per basic block, from instruction to range.
-  ArenaVector<ArenaSafeMap<int, ValueRange*>> maps_;
+  ScopedArenaVector<ScopedArenaSafeMap<int, ValueRange*>> maps_;
 
   // Map an HArrayLength instruction's id to the first HBoundsCheck instruction
   // in a block that checks an index against that HArrayLength.
-  ArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_;
+  ScopedArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_;
 
   // Early-exit loop bookkeeping.
-  ArenaSafeMap<uint32_t, bool> early_exit_loop_;
+  ScopedArenaSafeMap<uint32_t, bool> early_exit_loop_;
 
   // Taken-test loop bookkeeping.
-  ArenaSafeMap<uint32_t, HBasicBlock*> taken_test_loop_;
+  ScopedArenaSafeMap<uint32_t, HBasicBlock*> taken_test_loop_;
 
   // Finite loop bookkeeping.
-  ArenaSet<uint32_t> finite_loop_;
+  ScopedArenaSet<uint32_t> finite_loop_;
 
   // Flag that denotes whether dominator-based dynamic elimination has occurred.
   bool has_dom_based_dynamic_bce_;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 76350a6..4ed1612 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -20,12 +20,16 @@
 #include "base/arena_bit_vector.h"
 #include "base/bit_vector-inl.h"
 #include "base/logging.h"
+#include "block_builder.h"
 #include "data_type-inl.h"
 #include "dex/verified_method.h"
 #include "driver/compiler_options.h"
+#include "instruction_builder.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache.h"
 #include "nodes.h"
+#include "optimizing_compiler_stats.h"
+#include "ssa_builder.h"
 #include "thread.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 
@@ -43,27 +47,13 @@
       dex_file_(&graph->GetDexFile()),
       code_item_(*dex_compilation_unit->GetCodeItem()),
       dex_compilation_unit_(dex_compilation_unit),
+      outer_compilation_unit_(outer_compilation_unit),
       compiler_driver_(driver),
+      code_generator_(code_generator),
       compilation_stats_(compiler_stats),
-      block_builder_(graph, dex_file_, code_item_),
-      ssa_builder_(graph,
-                   dex_compilation_unit->GetClassLoader(),
-                   dex_compilation_unit->GetDexCache(),
-                   handles),
-      instruction_builder_(graph,
-                           &block_builder_,
-                           &ssa_builder_,
-                           dex_file_,
-                           code_item_,
-                           DataType::FromShorty(dex_compilation_unit_->GetShorty()[0]),
-                           dex_compilation_unit,
-                           outer_compilation_unit,
-                           driver,
-                           code_generator,
-                           interpreter_metadata,
-                           compiler_stats,
-                           dex_compilation_unit->GetDexCache(),
-                           handles) {}
+      interpreter_metadata_(interpreter_metadata),
+      handles_(handles),
+      return_type_(DataType::FromShorty(dex_compilation_unit_->GetShorty()[0])) {}
 
 bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {
   if (compiler_driver_ == nullptr) {
@@ -108,15 +98,38 @@
   graph_->SetMaximumNumberOfOutVRegs(code_item_.outs_size_);
   graph_->SetHasTryCatch(code_item_.tries_size_ != 0);
 
+  // Use ScopedArenaAllocator for all local allocations.
+  ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
+  HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_, &local_allocator);
+  SsaBuilder ssa_builder(graph_,
+                         dex_compilation_unit_->GetClassLoader(),
+                         dex_compilation_unit_->GetDexCache(),
+                         handles_,
+                         &local_allocator);
+  HInstructionBuilder instruction_builder(graph_,
+                                          &block_builder,
+                                          &ssa_builder,
+                                          dex_file_,
+                                          code_item_,
+                                          return_type_,
+                                          dex_compilation_unit_,
+                                          outer_compilation_unit_,
+                                          compiler_driver_,
+                                          code_generator_,
+                                          interpreter_metadata_,
+                                          compilation_stats_,
+                                          handles_,
+                                          &local_allocator);
+
   // 1) Create basic blocks and link them together. Basic blocks are left
   //    unpopulated with the exception of synthetic blocks, e.g. HTryBoundaries.
-  if (!block_builder_.Build()) {
+  if (!block_builder.Build()) {
     return kAnalysisInvalidBytecode;
   }
 
   // 2) Decide whether to skip this method based on its code size and number
   //    of branches.
-  if (SkipCompilation(block_builder_.GetNumberOfBranches())) {
+  if (SkipCompilation(block_builder.GetNumberOfBranches())) {
     return kAnalysisSkipped;
   }
 
@@ -127,12 +140,12 @@
   }
 
   // 4) Populate basic blocks with instructions.
-  if (!instruction_builder_.Build()) {
+  if (!instruction_builder.Build()) {
     return kAnalysisInvalidBytecode;
   }
 
   // 5) Type the graph and eliminate dead/redundant phis.
-  return ssa_builder_.BuildSsa();
+  return ssa_builder.BuildSsa();
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 6c5985a..5a860f1 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -17,21 +17,17 @@
 #ifndef ART_COMPILER_OPTIMIZING_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_BUILDER_H_
 
-#include "base/arena_containers.h"
 #include "base/arena_object.h"
-#include "block_builder.h"
 #include "dex_file-inl.h"
 #include "dex_file.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
-#include "instruction_builder.h"
 #include "nodes.h"
-#include "optimizing_compiler_stats.h"
-#include "ssa_builder.h"
 
 namespace art {
 
 class CodeGenerator;
+class OptimizingCompilerStats;
 
 class HGraphBuilder : public ValueObject {
  public:
@@ -46,34 +42,21 @@
 
   // Only for unit testing.
   HGraphBuilder(HGraph* graph,
+                const DexCompilationUnit* dex_compilation_unit,
                 const DexFile::CodeItem& code_item,
                 VariableSizedHandleScope* handles,
                 DataType::Type return_type = DataType::Type::kInt32)
       : graph_(graph),
-        dex_file_(nullptr),
+        dex_file_(dex_compilation_unit->GetDexFile()),
         code_item_(code_item),
-        dex_compilation_unit_(nullptr),
+        dex_compilation_unit_(dex_compilation_unit),
+        outer_compilation_unit_(nullptr),
         compiler_driver_(nullptr),
+        code_generator_(nullptr),
         compilation_stats_(nullptr),
-        block_builder_(graph, nullptr, code_item),
-        ssa_builder_(graph,
-                     handles->NewHandle<mirror::ClassLoader>(nullptr),
-                     handles->NewHandle<mirror::DexCache>(nullptr),
-                     handles),
-        instruction_builder_(graph,
-                             &block_builder_,
-                             &ssa_builder_,
-                             /* dex_file */ nullptr,
-                             code_item_,
-                             return_type,
-                             /* dex_compilation_unit */ nullptr,
-                             /* outer_compilation_unit */ nullptr,
-                             /* compiler_driver */ nullptr,
-                             /* code_generator */ nullptr,
-                             /* interpreter_metadata */ nullptr,
-                             /* compiler_stats */ nullptr,
-                             handles->NewHandle<mirror::DexCache>(nullptr),
-                             handles) {}
+        interpreter_metadata_(nullptr),
+        handles_(handles),
+        return_type_(return_type) {}
 
   GraphAnalysisResult BuildGraph();
 
@@ -90,13 +73,16 @@
   // it can be an inlined method.
   const DexCompilationUnit* const dex_compilation_unit_;
 
+  // The compilation unit of the enclosing method being compiled.
+  const DexCompilationUnit* const outer_compilation_unit_;
+
   CompilerDriver* const compiler_driver_;
+  CodeGenerator* const code_generator_;
 
-  OptimizingCompilerStats* compilation_stats_;
-
-  HBasicBlockBuilder block_builder_;
-  SsaBuilder ssa_builder_;
-  HInstructionBuilder instruction_builder_;
+  OptimizingCompilerStats* const compilation_stats_;
+  const uint8_t* const interpreter_metadata_;
+  VariableSizedHandleScope* const handles_;
+  const DataType::Type return_type_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index dd8e3d2..84f0182 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -935,7 +935,7 @@
       if (current_phi == nullptr || current_phi->AsPhi()->GetRegNumber() != vreg) {
         stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
       } else {
-        Location location = current_phi->GetLiveInterval()->ToLocation();
+        Location location = current_phi->GetLocations()->Out();
         switch (location.GetKind()) {
           case Location::kStackSlot: {
             stack_map_stream_.AddDexRegisterEntry(
@@ -1202,22 +1202,21 @@
   }
 }
 
-void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const {
+void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check,
+                                                          HParallelMove* spills) const {
   LocationSummary* locations = suspend_check->GetLocations();
   HBasicBlock* block = suspend_check->GetBlock();
   DCHECK(block->GetLoopInformation()->GetSuspendCheck() == suspend_check);
   DCHECK(block->IsLoopHeader());
+  DCHECK(block->GetFirstInstruction() == spills);
 
-  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-    HInstruction* current = it.Current();
-    LiveInterval* interval = current->GetLiveInterval();
-    // We only need to clear bits of loop phis containing objects and allocated in register.
-    // Loop phis allocated on stack already have the object in the stack.
-    if (current->GetType() == DataType::Type::kReference
-        && interval->HasRegister()
-        && interval->HasSpillSlot()) {
-      locations->ClearStackBit(interval->GetSpillSlot() / kVRegSize);
-    }
+  for (size_t i = 0, num_moves = spills->NumMoves(); i != num_moves; ++i) {
+    Location dest = spills->MoveOperandsAt(i)->GetDestination();
+    // All parallel moves in loop headers are spills.
+    DCHECK(dest.IsStackSlot() || dest.IsDoubleStackSlot() || dest.IsSIMDStackSlot()) << dest;
+    // Clear the stack bit marking a reference. Do not bother to check if the spill is
+    // actually a reference spill, clearing bits that are already zero is harmless.
+    locations->ClearStackBit(dest.GetStackIndex() / kVRegSize);
   }
 }
 
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 2c3cf26..2904b71 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -380,7 +380,8 @@
   // for the suspend check at the back edge (instead of where the suspend check
   // is, which is the loop entry). At this point, the spill slots for the phis
   // have not been written to.
-  void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const;
+  void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check,
+                                             HParallelMove* spills) const;
 
   bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; }
   bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; }
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 9be9117..e6e6984 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2209,7 +2209,6 @@
     codegen_->AddSlowPath(slow_path);
     if (successor != nullptr) {
       DCHECK(successor->IsLoopHeader());
-      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
     }
   } else {
     DCHECK_EQ(slow_path->GetSuccessor(), successor);
@@ -3560,7 +3559,6 @@
   HLoopInformation* info = block->GetLoopInformation();
 
   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
-    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
     return;
   }
@@ -5420,6 +5418,13 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index d7137a3..251f390 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -2858,7 +2858,6 @@
   HLoopInformation* info = block->GetLoopInformation();
 
   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
-    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
     return;
   }
@@ -6741,6 +6740,13 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
@@ -6776,7 +6782,6 @@
     codegen_->AddSlowPath(slow_path);
     if (successor != nullptr) {
       DCHECK(successor->IsLoopHeader());
-      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
     }
   } else {
     DCHECK_EQ(slow_path->GetSuccessor(), successor);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 7ea7b9c..e58f43e 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -3967,7 +3967,6 @@
   HLoopInformation* info = block->GetLoopInformation();
 
   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
-    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
     return;
   }
@@ -8359,6 +8358,13 @@
 }
 
 void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index fad0fe7..11120cf 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3488,7 +3488,6 @@
   HLoopInformation* info = block->GetLoopInformation();
 
   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
-    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
     return;
   }
@@ -6490,6 +6489,13 @@
 }
 
 void InstructionCodeGeneratorMIPS64::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
diff --git a/compiler/optimizing/code_generator_vector_arm_vixl.cc b/compiler/optimizing/code_generator_vector_arm_vixl.cc
index f84408d..cc470dd 100644
--- a/compiler/optimizing/code_generator_vector_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_vector_arm_vixl.cc
@@ -28,6 +28,7 @@
 using helpers::InputDRegisterAt;
 using helpers::InputRegisterAt;
 using helpers::OutputDRegister;
+using helpers::OutputRegister;
 using helpers::RegisterFrom;
 
 #define __ GetVIXLAssembler()->
@@ -76,11 +77,30 @@
 }
 
 void LocationsBuilderARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt32:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vmov(OutputRegister(instruction), DRegisterLane(src, 0));
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector unary operations.
@@ -112,7 +132,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecReduce(HVecReduce* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      switch (instruction->GetKind()) {
+        case HVecReduce::kSum:
+          __ Vpadd(DataTypeValue::I32, dst, src, src);
+          break;
+        case HVecReduce::kMin:
+          __ Vpmin(DataTypeValue::S32, dst, src, src);
+          break;
+        case HVecReduce::kMax:
+          __ Vpmax(DataTypeValue::S32, dst, src, src);
+          break;
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecCnv(HVecCnv* instruction) {
@@ -635,11 +676,49 @@
 }
 
 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
+
+  DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
+
+  HInstruction* input = instruction->InputAt(0);
+  bool is_zero = IsZeroBitPattern(input);
+
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt32:
+      locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
+                                    : Location::RequiresRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+
+  DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
+
+  // Zero out all other elements first.
+  __ Vmov(I32, dst, 0);
+
+  // Shorthand for any type of zero.
+  if (IsZeroBitPattern(instruction->InputAt(0))) {
+    return;
+  }
+
+  // Set required elements.
+  switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vmov(Untyped32, DRegisterLane(dst, 0), InputRegisterAt(instruction, 0));
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector accumulations.
@@ -676,7 +755,39 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister acc = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister left = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister right = DRegisterFrom(locations->InAt(2));
+
+  DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+  // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+  HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+  HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+  DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
+  switch (a->GetPackedType()) {
+    case DataType::Type::kInt32:
+      DCHECK_EQ(2u, a->GetVectorLength());
+      switch (instruction->GetPackedType()) {
+        case DataType::Type::kInt32: {
+          DCHECK_EQ(2u, instruction->GetVectorLength());
+          UseScratchRegisterScope temps(GetVIXLAssembler());
+          vixl32::DRegister tmp = temps.AcquireD();
+          __ Vsub(DataTypeValue::I32, tmp, left, right);
+          __ Vabs(DataTypeValue::S32, tmp, tmp);
+          __ Vadd(DataTypeValue::I32, acc, acc, tmp);
+          break;
+        }
+        default:
+          LOG(FATAL) << "Unsupported SIMD type";
+          UNREACHABLE();
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index d8a47fa..828e7ff 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -144,7 +144,8 @@
     InvokeRuntimeCallingConvention calling_convention;
     if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
       // Load the array length into our temporary.
-      uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+      HArrayLength* length = array_length->AsArrayLength();
+      uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
       Location array_loc = array_length->GetLocations()->InAt(0);
       Address array_len(array_loc.AsRegister<Register>(), len_offset);
       length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
@@ -154,7 +155,7 @@
         length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
       }
       __ movl(length_loc.AsRegister<Register>(), array_len);
-      if (mirror::kUseStringCompression) {
+      if (mirror::kUseStringCompression && length->IsStringLength()) {
         __ shrl(length_loc.AsRegister<Register>(), Immediate(1));
       }
     }
@@ -5680,6 +5681,13 @@
 }
 
 void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
@@ -5717,7 +5725,6 @@
     codegen_->AddSlowPath(slow_path);
     if (successor != nullptr) {
       DCHECK(successor->IsLoopHeader());
-      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
     }
   } else {
     DCHECK_EQ(slow_path->GetSuccessor(), successor);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index b6aa110..b07949f 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -195,7 +195,8 @@
     InvokeRuntimeCallingConvention calling_convention;
     if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
       // Load the array length into our temporary.
-      uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+      HArrayLength* length = array_length->AsArrayLength();
+      uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length->AsArrayLength());
       Location array_loc = array_length->GetLocations()->InAt(0);
       Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
       length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
@@ -205,7 +206,7 @@
         length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
       }
       __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
-      if (mirror::kUseStringCompression) {
+      if (mirror::kUseStringCompression && length->IsStringLength()) {
         __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
       }
     }
@@ -5125,6 +5126,13 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
+  if (instruction->GetNext()->IsSuspendCheck() &&
+      instruction->GetBlock()->GetLoopInformation() != nullptr) {
+    HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
+    // The back edge will generate the suspend check.
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
+  }
+
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
@@ -5162,7 +5170,6 @@
     codegen_->AddSlowPath(slow_path);
     if (successor != nullptr) {
       DCHECK(successor->IsLoopHeader());
-      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
     }
   } else {
     DCHECK_EQ(slow_path->GetSuccessor(), successor);
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 5117e07..3cc7b0e 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -18,13 +18,18 @@
 
 #include "base/array_ref.h"
 #include "base/bit_vector-inl.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "base/stl_util.h"
 #include "ssa_phi_elimination.h"
 
 namespace art {
 
 static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) {
-  ArenaVector<HBasicBlock*> worklist(graph->GetAllocator()->Adapter(kArenaAllocDCE));
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator(graph->GetArenaStack());
+
+  ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocDCE));
   constexpr size_t kDefaultWorlistSize = 8;
   worklist.reserve(kDefaultWorlistSize);
   visited->SetBit(graph->GetEntryBlock()->GetBlockId());
@@ -305,9 +310,12 @@
 }
 
 bool HDeadCodeElimination::RemoveDeadBlocks() {
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator(graph_->GetArenaStack());
+
   // Classify blocks as reachable/unreachable.
-  ArenaAllocator* allocator = graph_->GetAllocator();
-  ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
+  ArenaBitVector live_blocks(&allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
+  live_blocks.ClearAllBits();
 
   MarkReachableBlocks(graph_, &live_blocks);
   bool removed_one_or_more_blocks = false;
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 1c7d1a0..b1ac027 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -22,8 +22,9 @@
 
 #include "android-base/stringprintf.h"
 
-#include "base/arena_containers.h"
 #include "base/bit_vector-inl.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 
 namespace art {
 
@@ -47,10 +48,13 @@
 void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
   current_block_ = block;
 
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
+
   // Check consistency with respect to predecessors of `block`.
   // Note: Counting duplicates with a sorted vector uses up to 6x less memory
   // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
-  ArenaVector<HBasicBlock*>& sorted_predecessors = blocks_storage_;
+  ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker));
   sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
   std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
   for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) {
@@ -73,7 +77,7 @@
   // Check consistency with respect to successors of `block`.
   // Note: Counting duplicates with a sorted vector uses up to 6x less memory
   // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
-  ArenaVector<HBasicBlock*>& sorted_successors = blocks_storage_;
+  ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
   sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
   std::sort(sorted_successors.begin(), sorted_successors.end());
   for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) {
@@ -829,10 +833,14 @@
               phi->GetRegNumber(),
               type_str.str().c_str()));
         } else {
+          // Use local allocator for allocating memory.
+          ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
           // If we get here, make sure we allocate all the necessary storage at once
           // because the BitVector reallocation strategy has very bad worst-case behavior.
-          ArenaBitVector& visited = visited_storage_;
-          visited.SetBit(GetGraph()->GetCurrentInstructionId());
+          ArenaBitVector visited(&allocator,
+                                 GetGraph()->GetCurrentInstructionId(),
+                                 /* expandable */ false,
+                                 kArenaAllocGraphChecker);
           visited.ClearAllBits();
           if (!IsConstantEquivalent(phi, other_phi, &visited)) {
             AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 6af7b42..0f0b49d 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -17,10 +17,13 @@
 #ifndef ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
 #define ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
 
-#include "nodes.h"
-
 #include <ostream>
 
+#include "base/arena_bit_vector.h"
+#include "base/bit_vector-inl.h"
+#include "base/scoped_arena_allocator.h"
+#include "nodes.h"
+
 namespace art {
 
 // A control-flow graph visitor performing various checks.
@@ -30,12 +33,10 @@
     : HGraphDelegateVisitor(graph),
       errors_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)),
       dump_prefix_(dump_prefix),
-      seen_ids_(graph->GetAllocator(),
-                graph->GetCurrentInstructionId(),
-                false,
-                kArenaAllocGraphChecker),
-      blocks_storage_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)),
-      visited_storage_(graph->GetAllocator(), 0u, true, kArenaAllocGraphChecker) {}
+      allocator_(graph->GetArenaStack()),
+      seen_ids_(&allocator_, graph->GetCurrentInstructionId(), false, kArenaAllocGraphChecker) {
+    seen_ids_.ClearAllBits();
+  }
 
   // Check the whole graph (in reverse post-order).
   void Run() {
@@ -104,12 +105,9 @@
  private:
   // String displayed before dumped errors.
   const char* const dump_prefix_;
+  ScopedArenaAllocator allocator_;
   ArenaBitVector seen_ids_;
 
-  // To reduce the total arena memory allocation, we reuse the same storage.
-  ArenaVector<HBasicBlock*> blocks_storage_;
-  ArenaBitVector visited_storage_;
-
   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
 };
 
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index eccdccf..3851877 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -21,6 +21,7 @@
 #include <cctype>
 #include <sstream>
 
+#include "art_method.h"
 #include "bounds_check_elimination.h"
 #include "builder.h"
 #include "code_generator.h"
@@ -33,6 +34,7 @@
 #include "optimization.h"
 #include "reference_type_propagation.h"
 #include "register_allocator_linear_scan.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/assembler.h"
 #include "utils/intrusive_forward_list.h"
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index c09e5df..813772e 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -17,7 +17,8 @@
 #include "gvn.h"
 
 #include "base/arena_bit_vector.h"
-#include "base/arena_containers.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "base/bit_vector-inl.h"
 #include "side_effects_analysis.h"
 #include "utils.h"
@@ -36,7 +37,7 @@
 class ValueSet : public ArenaObject<kArenaAllocGvn> {
  public:
   // Constructs an empty ValueSet which owns all its buckets.
-  explicit ValueSet(ArenaAllocator* allocator)
+  explicit ValueSet(ScopedArenaAllocator* allocator)
       : allocator_(allocator),
         num_buckets_(kMinimumNumberOfBuckets),
         buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)),
@@ -44,12 +45,13 @@
         num_entries_(0u) {
     // ArenaAllocator returns zeroed memory, so no need to set buckets to null.
     DCHECK(IsPowerOfTwo(num_buckets_));
+    std::fill_n(buckets_, num_buckets_, nullptr);
     buckets_owned_.SetInitialBits(num_buckets_);
   }
 
   // Copy constructor. Depending on the load factor, it will either make a deep
   // copy (all buckets owned) or a shallow one (buckets pointing to the parent).
-  ValueSet(ArenaAllocator* allocator, const ValueSet& other)
+  ValueSet(ScopedArenaAllocator* allocator, const ValueSet& other)
       : allocator_(allocator),
         num_buckets_(other.IdealBucketCount()),
         buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)),
@@ -58,7 +60,7 @@
     // ArenaAllocator returns zeroed memory, so entries of buckets_ and
     // buckets_owned_ are initialized to null and false, respectively.
     DCHECK(IsPowerOfTwo(num_buckets_));
-    PopulateFromInternal(other, /* is_dirty */ false);
+    PopulateFromInternal(other);
   }
 
   // Erases all values in this set and populates it with values from `other`.
@@ -66,7 +68,7 @@
     if (this == &other) {
       return;
     }
-    PopulateFromInternal(other, /* is_dirty */ true);
+    PopulateFromInternal(other);
   }
 
   // Returns true if `this` has enough buckets so that if `other` is copied into
@@ -159,33 +161,19 @@
 
  private:
   // Copies all entries from `other` to `this`.
-  // If `is_dirty` is set to true, existing data will be wiped first. It is
-  // assumed that `buckets_` and `buckets_owned_` are zero-allocated otherwise.
-  void PopulateFromInternal(const ValueSet& other, bool is_dirty) {
+  void PopulateFromInternal(const ValueSet& other) {
     DCHECK_NE(this, &other);
     DCHECK_GE(num_buckets_, other.IdealBucketCount());
 
     if (num_buckets_ == other.num_buckets_) {
       // Hash table remains the same size. We copy the bucket pointers and leave
       // all buckets_owned_ bits false.
-      if (is_dirty) {
-        buckets_owned_.ClearAllBits();
-      } else {
-        DCHECK_EQ(buckets_owned_.NumSetBits(), 0u);
-      }
+      buckets_owned_.ClearAllBits();
       memcpy(buckets_, other.buckets_, num_buckets_ * sizeof(Node*));
     } else {
       // Hash table size changes. We copy and rehash all entries, and set all
       // buckets_owned_ bits to true.
-      if (is_dirty) {
-        memset(buckets_, 0, num_buckets_ * sizeof(Node*));
-      } else {
-        if (kIsDebugBuild) {
-          for (size_t i = 0; i < num_buckets_; ++i) {
-            DCHECK(buckets_[i] == nullptr) << i;
-          }
-        }
-      }
+      std::fill_n(buckets_, num_buckets_, nullptr);
       for (size_t i = 0; i < other.num_buckets_; ++i) {
         for (Node* node = other.buckets_[i]; node != nullptr; node = node->GetNext()) {
           size_t new_index = BucketIndex(node->GetHashCode());
@@ -208,7 +196,7 @@
     Node* GetNext() const { return next_; }
     void SetNext(Node* node) { next_ = node; }
 
-    Node* Dup(ArenaAllocator* allocator, Node* new_next = nullptr) {
+    Node* Dup(ScopedArenaAllocator* allocator, Node* new_next = nullptr) {
       return new (allocator) Node(instruction_, hash_code_, new_next);
     }
 
@@ -326,7 +314,7 @@
     return hash_code & (num_buckets_ - 1);
   }
 
-  ArenaAllocator* const allocator_;
+  ScopedArenaAllocator* const allocator_;
 
   // The internal bucket implementation of the set.
   size_t const num_buckets_;
@@ -350,15 +338,16 @@
  */
 class GlobalValueNumberer : public ValueObject {
  public:
-  GlobalValueNumberer(ArenaAllocator* allocator,
-                      HGraph* graph,
+  GlobalValueNumberer(HGraph* graph,
                       const SideEffectsAnalysis& side_effects)
       : graph_(graph),
-        allocator_(allocator),
+        allocator_(graph->GetArenaStack()),
         side_effects_(side_effects),
-        sets_(graph->GetBlocks().size(), nullptr, allocator->Adapter(kArenaAllocGvn)),
+        sets_(graph->GetBlocks().size(), nullptr, allocator_.Adapter(kArenaAllocGvn)),
         visited_blocks_(
-            allocator, graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGvn) {}
+            &allocator_, graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGvn) {
+    visited_blocks_.ClearAllBits();
+  }
 
   void Run();
 
@@ -368,7 +357,7 @@
   void VisitBasicBlock(HBasicBlock* block);
 
   HGraph* graph_;
-  ArenaAllocator* const allocator_;
+  ScopedArenaAllocator allocator_;
   const SideEffectsAnalysis& side_effects_;
 
   ValueSet* FindSetFor(HBasicBlock* block) const {
@@ -396,7 +385,7 @@
   // ValueSet for blocks. Initially null, but for an individual block they
   // are allocated and populated by the dominator, and updated by all blocks
   // in the path from the dominator to the block.
-  ArenaVector<ValueSet*> sets_;
+  ScopedArenaVector<ValueSet*> sets_;
 
   // BitVector which serves as a fast-access map from block id to
   // visited/unvisited Boolean.
@@ -407,7 +396,7 @@
 
 void GlobalValueNumberer::Run() {
   DCHECK(side_effects_.HasRun());
-  sets_[graph_->GetEntryBlock()->GetBlockId()] = new (allocator_) ValueSet(allocator_);
+  sets_[graph_->GetEntryBlock()->GetBlockId()] = new (&allocator_) ValueSet(&allocator_);
 
   // Use the reverse post order to ensure the non back-edge predecessors of a block are
   // visited before the block itself.
@@ -424,7 +413,7 @@
     // The entry block should only accumulate constant instructions, and
     // the builder puts constants only in the entry block.
     // Therefore, there is no need to propagate the value set to the next block.
-    set = new (allocator_) ValueSet(allocator_);
+    set = new (&allocator_) ValueSet(&allocator_);
   } else {
     HBasicBlock* dominator = block->GetDominator();
     ValueSet* dominator_set = FindSetFor(dominator);
@@ -443,7 +432,7 @@
       if (recyclable == nullptr) {
         // No block with a suitable ValueSet found. Allocate a new one and
         // copy `dominator_set` into it.
-        set = new (allocator_) ValueSet(allocator_, *dominator_set);
+        set = new (&allocator_) ValueSet(&allocator_, *dominator_set);
       } else {
         // Block with a recyclable ValueSet found. Clone `dominator_set` into it.
         set = FindSetFor(recyclable);
@@ -566,7 +555,7 @@
 }
 
 void GVNOptimization::Run() {
-  GlobalValueNumberer gvn(graph_->GetAllocator(), graph_, side_effects_);
+  GlobalValueNumberer gvn(graph_, side_effects_);
   gvn.Run();
 }
 
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index b06d91c..902985e 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -17,15 +17,23 @@
 #include "instruction_builder.h"
 
 #include "art_method-inl.h"
+#include "base/arena_bit_vector.h"
+#include "base/bit_vector-inl.h"
+#include "block_builder.h"
 #include "bytecode_utils.h"
 #include "class_linker.h"
 #include "data_type-inl.h"
 #include "dex_instruction-inl.h"
+#include "driver/compiler_driver-inl.h"
+#include "driver/dex_compilation_unit.h"
 #include "driver/compiler_options.h"
 #include "imtable-inl.h"
+#include "mirror/dex_cache.h"
+#include "optimizing_compiler_stats.h"
 #include "quicken_info.h"
 #include "scoped_thread_state_change-inl.h"
 #include "sharpening.h"
+#include "ssa_builder.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -34,8 +42,8 @@
   return block_builder_->GetBlockAt(dex_pc);
 }
 
-inline ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsFor(HBasicBlock* block) {
-  ArenaVector<HInstruction*>* locals = &locals_for_[block->GetBlockId()];
+inline ScopedArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsFor(HBasicBlock* block) {
+  ScopedArenaVector<HInstruction*>* locals = &locals_for_[block->GetBlockId()];
   const size_t vregs = graph_->GetNumberOfVRegs();
   if (locals->size() == vregs) {
     return locals;
@@ -43,9 +51,9 @@
   return GetLocalsForWithAllocation(block, locals, vregs);
 }
 
-ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsForWithAllocation(
+ScopedArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsForWithAllocation(
     HBasicBlock* block,
-    ArenaVector<HInstruction*>* locals,
+    ScopedArenaVector<HInstruction*>* locals,
     const size_t vregs) {
   DCHECK_NE(locals->size(), vregs);
   locals->resize(vregs, nullptr);
@@ -73,7 +81,7 @@
 }
 
 inline HInstruction* HInstructionBuilder::ValueOfLocalAt(HBasicBlock* block, size_t local) {
-  ArenaVector<HInstruction*>* locals = GetLocalsFor(block);
+  ScopedArenaVector<HInstruction*>* locals = GetLocalsFor(block);
   return (*locals)[local];
 }
 
@@ -168,7 +176,7 @@
 void HInstructionBuilder::PropagateLocalsToCatchBlocks() {
   const HTryBoundary& try_entry = current_block_->GetTryCatchInformation()->GetTryEntry();
   for (HBasicBlock* catch_block : try_entry.GetExceptionHandlers()) {
-    ArenaVector<HInstruction*>* handler_locals = GetLocalsFor(catch_block);
+    ScopedArenaVector<HInstruction*>* handler_locals = GetLocalsFor(catch_block);
     DCHECK_EQ(handler_locals->size(), current_locals_->size());
     for (size_t vreg = 0, e = current_locals_->size(); vreg < e; ++vreg) {
       HInstruction* handler_value = (*handler_locals)[vreg];
@@ -216,7 +224,7 @@
         graph_->GetArtMethod(),
         instruction->GetDexPc(),
         instruction);
-    environment->CopyFrom(*current_locals_);
+    environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals_));
     instruction->SetRawEnvironment(environment);
   }
 }
@@ -264,8 +272,9 @@
 }
 
 bool HInstructionBuilder::Build() {
-  locals_for_.resize(graph_->GetBlocks().size(),
-                     ArenaVector<HInstruction*>(allocator_->Adapter(kArenaAllocGraphBuilder)));
+  locals_for_.resize(
+      graph_->GetBlocks().size(),
+      ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder)));
 
   // Find locations where we want to generate extra stackmaps for native debugging.
   // This allows us to generate the info only at interesting points (for example,
@@ -274,10 +283,7 @@
                                  compiler_driver_->GetCompilerOptions().GetNativeDebuggable();
   ArenaBitVector* native_debug_info_locations = nullptr;
   if (native_debuggable) {
-    const uint32_t num_instructions = code_item_.insns_size_in_code_units_;
-    native_debug_info_locations =
-        new (allocator_) ArenaBitVector (allocator_, num_instructions, false);
-    FindNativeDebugInfoLocations(native_debug_info_locations);
+    native_debug_info_locations = FindNativeDebugInfoLocations();
   }
 
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
@@ -358,7 +364,7 @@
   return true;
 }
 
-void HInstructionBuilder::FindNativeDebugInfoLocations(ArenaBitVector* locations) {
+ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {
   // The callback gets called when the line number changes.
   // In other words, it marks the start of new java statement.
   struct Callback {
@@ -367,6 +373,12 @@
       return false;
     }
   };
+  const uint32_t num_instructions = code_item_.insns_size_in_code_units_;
+  ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_,
+                                                     num_instructions,
+                                                     /* expandable */ false,
+                                                     kArenaAllocGraphBuilder);
+  locations->ClearAllBits();
   dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations);
   // Instruction-specific tweaks.
   IterationRange<DexInstructionIterator> instructions = code_item_.Instructions();
@@ -387,6 +399,7 @@
         break;
     }
   }
+  return locations;
 }
 
 HInstruction* HInstructionBuilder::LoadLocal(uint32_t reg_number, DataType::Type type) const {
@@ -439,8 +452,8 @@
 void HInstructionBuilder::InitializeParameters() {
   DCHECK(current_block_->IsEntryBlock());
 
-  // dex_compilation_unit_ is null only when unit testing.
-  if (dex_compilation_unit_ == nullptr) {
+  // outer_compilation_unit_ is null only when unit testing.
+  if (outer_compilation_unit_ == nullptr) {
     return;
   }
 
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 79d6ddc..058b711 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -17,23 +17,32 @@
 #ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 
-#include "base/arena_containers.h"
-#include "base/arena_object.h"
-#include "block_builder.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
+#include "data_type.h"
+#include "dex_file.h"
 #include "dex_file_types.h"
-#include "driver/compiler_driver-inl.h"
-#include "driver/compiler_driver.h"
-#include "driver/dex_compilation_unit.h"
-#include "mirror/dex_cache.h"
+#include "handle.h"
 #include "nodes.h"
-#include "optimizing_compiler_stats.h"
 #include "quicken_info.h"
-#include "ssa_builder.h"
 
 namespace art {
 
+class ArenaBitVector;
+class ArtField;
+class ArtMethod;
 class CodeGenerator;
+class CompilerDriver;
+class DexCompilationUnit;
+class HBasicBlockBuilder;
 class Instruction;
+class OptimizingCompilerStats;
+class SsaBuilder;
+class VariableSizedHandleScope;
+
+namespace mirror {
+class Class;
+}  // namespace mirror
 
 class HInstructionBuilder : public ValueObject {
  public:
@@ -45,12 +54,12 @@
                       DataType::Type return_type,
                       const DexCompilationUnit* dex_compilation_unit,
                       const DexCompilationUnit* outer_compilation_unit,
-                      CompilerDriver* driver,
+                      CompilerDriver* compiler_driver,
                       CodeGenerator* code_generator,
                       const uint8_t* interpreter_metadata,
                       OptimizingCompilerStats* compiler_stats,
-                      Handle<mirror::DexCache> dex_cache,
-                      VariableSizedHandleScope* handles)
+                      VariableSizedHandleScope* handles,
+                      ScopedArenaAllocator* local_allocator)
       : allocator_(graph->GetAllocator()),
         graph_(graph),
         handles_(handles),
@@ -59,19 +68,19 @@
         return_type_(return_type),
         block_builder_(block_builder),
         ssa_builder_(ssa_builder),
-        locals_for_(allocator_->Adapter(kArenaAllocGraphBuilder)),
-        current_block_(nullptr),
-        current_locals_(nullptr),
-        latest_result_(nullptr),
-        current_this_parameter_(nullptr),
-        compiler_driver_(driver),
+        compiler_driver_(compiler_driver),
         code_generator_(code_generator),
         dex_compilation_unit_(dex_compilation_unit),
         outer_compilation_unit_(outer_compilation_unit),
         quicken_info_(interpreter_metadata),
         compilation_stats_(compiler_stats),
-        dex_cache_(dex_cache),
-        loop_headers_(allocator_->Adapter(kArenaAllocGraphBuilder)) {
+        local_allocator_(local_allocator),
+        locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
+        current_block_(nullptr),
+        current_locals_(nullptr),
+        latest_result_(nullptr),
+        current_this_parameter_(nullptr),
+        loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) {
     loop_headers_.reserve(kDefaultNumberOfLoops);
   }
 
@@ -83,18 +92,18 @@
   void SetLoopHeaderPhiInputs();
 
   bool ProcessDexInstruction(const Instruction& instruction, uint32_t dex_pc, size_t quicken_index);
-  void FindNativeDebugInfoLocations(ArenaBitVector* locations);
+  ArenaBitVector* FindNativeDebugInfoLocations();
 
   bool CanDecodeQuickenedInfo() const;
   uint16_t LookupQuickenedInfo(uint32_t quicken_index);
 
   HBasicBlock* FindBlockStartingAt(uint32_t dex_pc) const;
 
-  ArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block);
+  ScopedArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block);
   // Out of line version of GetLocalsFor(), which has a fast path that is
   // beneficial to get inlined by callers.
-  ArenaVector<HInstruction*>* GetLocalsForWithAllocation(
-      HBasicBlock* block, ArenaVector<HInstruction*>* locals, const size_t vregs);
+  ScopedArenaVector<HInstruction*>* GetLocalsForWithAllocation(
+      HBasicBlock* block, ScopedArenaVector<HInstruction*>* locals, const size_t vregs);
   HInstruction* ValueOfLocalAt(HBasicBlock* block, size_t local);
   HInstruction* LoadLocal(uint32_t register_index, DataType::Type type) const;
   HInstruction* LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc);
@@ -314,7 +323,7 @@
 
   ArenaAllocator* const allocator_;
   HGraph* const graph_;
-  VariableSizedHandleScope* handles_;
+  VariableSizedHandleScope* const handles_;
 
   // The dex file where the method being compiled is, and the bytecode data.
   const DexFile* const dex_file_;
@@ -323,18 +332,8 @@
   // The return type of the method being compiled.
   const DataType::Type return_type_;
 
-  HBasicBlockBuilder* block_builder_;
-  SsaBuilder* ssa_builder_;
-
-  ArenaVector<ArenaVector<HInstruction*>> locals_for_;
-  HBasicBlock* current_block_;
-  ArenaVector<HInstruction*>* current_locals_;
-  HInstruction* latest_result_;
-  // Current "this" parameter.
-  // Valid only after InitializeParameters() finishes.
-  // * Null for static methods.
-  // * Non-null for instance methods.
-  HParameterValue* current_this_parameter_;
+  HBasicBlockBuilder* const block_builder_;
+  SsaBuilder* const ssa_builder_;
 
   CompilerDriver* const compiler_driver_;
 
@@ -352,10 +351,20 @@
   // Original values kept after instruction quickening.
   QuickenInfoTable quicken_info_;
 
-  OptimizingCompilerStats* compilation_stats_;
-  Handle<mirror::DexCache> dex_cache_;
+  OptimizingCompilerStats* const compilation_stats_;
 
-  ArenaVector<HBasicBlock*> loop_headers_;
+  ScopedArenaAllocator* const local_allocator_;
+  ScopedArenaVector<ScopedArenaVector<HInstruction*>> locals_for_;
+  HBasicBlock* current_block_;
+  ScopedArenaVector<HInstruction*>* current_locals_;
+  HInstruction* latest_result_;
+  // Current "this" parameter.
+  // Valid only after InitializeParameters() finishes.
+  // * Null for static methods.
+  // * Non-null for instance methods.
+  HParameterValue* current_this_parameter_;
+
+  ScopedArenaVector<HBasicBlock*> loop_headers_;
 
   static constexpr int kDefaultNumberOfLoops = 2;
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index f39acab..afe7484 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1284,9 +1284,9 @@
         DCHECK(input_other->IsShr());  // For UShr, we would have taken the branch above.
         // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24".
         HUShr* ushr = new (GetGraph()->GetAllocator()) HUShr(instruction->GetType(),
-                                                         input_other->InputAt(0),
-                                                         input_other->InputAt(1),
-                                                         input_other->GetDexPc());
+                                                             input_other->InputAt(0),
+                                                             input_other->InputAt(1),
+                                                             input_other->GetDexPc());
         instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr);
         input_other->GetBlock()->RemoveInstruction(input_other);
         RecordSimplification();
diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h
index 3533c88c..033a644 100644
--- a/compiler/optimizing/intrinsics_arm64.h
+++ b/compiler/optimizing/intrinsics_arm64.h
@@ -57,8 +57,8 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  ArenaAllocator* allocator_;
-  CodeGeneratorARM64* codegen_;
+  ArenaAllocator* const allocator_;
+  CodeGeneratorARM64* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderARM64);
 };
@@ -81,7 +81,7 @@
 
   ArenaAllocator* GetAllocator();
 
-  CodeGeneratorARM64* codegen_;
+  CodeGeneratorARM64* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorARM64);
 };
diff --git a/compiler/optimizing/intrinsics_arm_vixl.h b/compiler/optimizing/intrinsics_arm_vixl.h
index 4f18ca3..9c02d0a 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.h
+++ b/compiler/optimizing/intrinsics_arm_vixl.h
@@ -46,9 +46,9 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  ArenaAllocator* allocator_;
-  CodeGenerator* codegen_;
-  ArmVIXLAssembler* assembler_;
+  ArenaAllocator* const allocator_;
+  CodeGenerator* const codegen_;
+  ArmVIXLAssembler* const assembler_;
   const ArmInstructionSetFeatures& features_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderARMVIXL);
@@ -71,7 +71,7 @@
   ArenaAllocator* GetAllocator();
   ArmVIXLAssembler* GetAssembler();
 
-  CodeGeneratorARMVIXL* codegen_;
+  CodeGeneratorARMVIXL* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorARMVIXL);
 };
diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h
index afd9548..13397f1 100644
--- a/compiler/optimizing/intrinsics_mips.h
+++ b/compiler/optimizing/intrinsics_mips.h
@@ -49,8 +49,8 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  CodeGeneratorMIPS* codegen_;
-  ArenaAllocator* allocator_;
+  CodeGeneratorMIPS* const codegen_;
+  ArenaAllocator* const allocator_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderMIPS);
 };
@@ -77,7 +77,7 @@
 
   ArenaAllocator* GetAllocator();
 
-  CodeGeneratorMIPS* codegen_;
+  CodeGeneratorMIPS* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorMIPS);
 };
diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h
index 6085c7b..6f40d90 100644
--- a/compiler/optimizing/intrinsics_mips64.h
+++ b/compiler/optimizing/intrinsics_mips64.h
@@ -49,8 +49,8 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  CodeGeneratorMIPS64* codegen_;
-  ArenaAllocator* allocator_;
+  CodeGeneratorMIPS64* const codegen_;
+  ArenaAllocator* const allocator_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderMIPS64);
 };
@@ -73,7 +73,7 @@
 
   ArenaAllocator* GetAllocator();
 
-  CodeGeneratorMIPS64* codegen_;
+  CodeGeneratorMIPS64* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorMIPS64);
 };
diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h
index ba3ca0a..e3555e7 100644
--- a/compiler/optimizing/intrinsics_x86.h
+++ b/compiler/optimizing/intrinsics_x86.h
@@ -49,8 +49,8 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  ArenaAllocator* allocator_;
-  CodeGeneratorX86* codegen_;
+  ArenaAllocator* const allocator_;
+  CodeGeneratorX86* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderX86);
 };
@@ -73,7 +73,7 @@
 
   ArenaAllocator* GetAllocator();
 
-  CodeGeneratorX86* codegen_;
+  CodeGeneratorX86* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorX86);
 };
diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h
index b0fbe91..5cb601e 100644
--- a/compiler/optimizing/intrinsics_x86_64.h
+++ b/compiler/optimizing/intrinsics_x86_64.h
@@ -49,8 +49,8 @@
   bool TryDispatch(HInvoke* invoke);
 
  private:
-  ArenaAllocator* allocator_;
-  CodeGeneratorX86_64* codegen_;
+  ArenaAllocator* const allocator_;
+  CodeGeneratorX86_64* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderX86_64);
 };
@@ -73,7 +73,7 @@
 
   ArenaAllocator* GetAllocator();
 
-  CodeGeneratorX86_64* codegen_;
+  CodeGeneratorX86_64* const codegen_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorX86_64);
 };
diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index 6a25da3..5940ee7 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -25,7 +25,7 @@
 
 // A ReferenceInfo contains additional info about a reference such as
 // whether it's a singleton, returned, etc.
-class ReferenceInfo : public ArenaObject<kArenaAllocMisc> {
+class ReferenceInfo : public ArenaObject<kArenaAllocLSA> {
  public:
   ReferenceInfo(HInstruction* reference, size_t pos)
       : reference_(reference),
@@ -99,7 +99,7 @@
 
 // A heap location is a reference-offset/index pair that a value can be loaded from
 // or stored to.
-class HeapLocation : public ArenaObject<kArenaAllocMisc> {
+class HeapLocation : public ArenaObject<kArenaAllocLSA> {
  public:
   static constexpr size_t kInvalidFieldOffset = -1;
 
@@ -172,12 +172,12 @@
 
   explicit HeapLocationCollector(HGraph* graph)
       : HGraphVisitor(graph),
-        ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
+        ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
+        heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
         aliasing_matrix_(graph->GetAllocator(),
                          kInitialAliasingMatrixBitVectorSize,
                          true,
-                         kArenaAllocLSE),
+                         kArenaAllocLSA),
         has_heap_stores_(false),
         has_volatile_(false),
         has_monitor_operations_(false) {}
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 39bfc86..af5585e 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -16,6 +16,9 @@
 
 #include "load_store_elimination.h"
 
+#include "base/array_ref.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "escape.h"
 #include "load_store_analysis.h"
 #include "side_effects_analysis.h"
@@ -45,17 +48,18 @@
       : HGraphVisitor(graph, stats),
         heap_location_collector_(heap_locations_collector),
         side_effects_(side_effects),
+        allocator_(graph->GetArenaStack()),
         heap_values_for_(graph->GetBlocks().size(),
-                         ArenaVector<HInstruction*>(heap_locations_collector.
-                                                    GetNumberOfHeapLocations(),
-                                                    kUnknownHeapValue,
-                                                    graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-                         graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        removed_loads_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        substitute_instructions_for_loads_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        possibly_removed_stores_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        singleton_new_instances_(graph->GetAllocator()->Adapter(kArenaAllocLSE)),
-        singleton_new_arrays_(graph->GetAllocator()->Adapter(kArenaAllocLSE)) {
+                         ScopedArenaVector<HInstruction*>(heap_locations_collector.
+                                                          GetNumberOfHeapLocations(),
+                                                          kUnknownHeapValue,
+                                                          allocator_.Adapter(kArenaAllocLSE)),
+                         allocator_.Adapter(kArenaAllocLSE)),
+        removed_loads_(allocator_.Adapter(kArenaAllocLSE)),
+        substitute_instructions_for_loads_(allocator_.Adapter(kArenaAllocLSE)),
+        possibly_removed_stores_(allocator_.Adapter(kArenaAllocLSE)),
+        singleton_new_instances_(allocator_.Adapter(kArenaAllocLSE)),
+        singleton_new_arrays_(allocator_.Adapter(kArenaAllocLSE)) {
   }
 
   void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
@@ -146,7 +150,7 @@
   void HandleLoopSideEffects(HBasicBlock* block) {
     DCHECK(block->IsLoopHeader());
     int block_id = block->GetBlockId();
-    ArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id];
+    ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id];
 
     // Don't eliminate loads in irreducible loops. This is safe for singletons, because
     // they are always used by the non-eliminated loop-phi.
@@ -160,7 +164,7 @@
     }
 
     HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
-    ArenaVector<HInstruction*>& pre_header_heap_values =
+    ScopedArenaVector<HInstruction*>& pre_header_heap_values =
         heap_values_for_[pre_header->GetBlockId()];
 
     // Inherit the values from pre-header.
@@ -191,12 +195,12 @@
   }
 
   void MergePredecessorValues(HBasicBlock* block) {
-    const ArenaVector<HBasicBlock*>& predecessors = block->GetPredecessors();
+    ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
     if (predecessors.size() == 0) {
       return;
     }
 
-    ArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()];
+    ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()];
     for (size_t i = 0; i < heap_values.size(); i++) {
       HInstruction* merged_value = nullptr;
       // Whether merged_value is a result that's merged from all predecessors.
@@ -234,7 +238,8 @@
         // or the heap value may be needed after method return or deoptimization.
         // Keep the last store in each predecessor since future loads cannot be eliminated.
         for (HBasicBlock* predecessor : predecessors) {
-          ArenaVector<HInstruction*>& pred_values = heap_values_for_[predecessor->GetBlockId()];
+          ScopedArenaVector<HInstruction*>& pred_values =
+              heap_values_for_[predecessor->GetBlockId()];
           KeepIfIsStore(pred_values[i]);
         }
       }
@@ -303,7 +308,7 @@
     size_t idx = heap_location_collector_.FindHeapLocationIndex(
         ref_info, offset, index, declaring_class_def_index);
     DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
-    ArenaVector<HInstruction*>& heap_values =
+    ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
     HInstruction* heap_value = heap_values[idx];
     if (heap_value == kDefaultHeapValue) {
@@ -369,7 +374,7 @@
     size_t idx = heap_location_collector_.FindHeapLocationIndex(
         ref_info, offset, index, declaring_class_def_index);
     DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
-    ArenaVector<HInstruction*>& heap_values =
+    ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
     HInstruction* heap_value = heap_values[idx];
     bool same_value = false;
@@ -496,7 +501,7 @@
   }
 
   void VisitDeoptimize(HDeoptimize* instruction) {
-    const ArenaVector<HInstruction*>& heap_values =
+    const ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
     for (HInstruction* heap_value : heap_values) {
       // Filter out fake instructions before checking instruction kind below.
@@ -523,7 +528,7 @@
   }
 
   void HandleInvoke(HInstruction* invoke) {
-    ArenaVector<HInstruction*>& heap_values =
+    ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[invoke->GetBlock()->GetBlockId()];
     for (size_t i = 0; i < heap_values.size(); i++) {
       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
@@ -590,7 +595,7 @@
         !new_instance->NeedsChecks()) {
       singleton_new_instances_.push_back(new_instance);
     }
-    ArenaVector<HInstruction*>& heap_values =
+    ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[new_instance->GetBlock()->GetBlockId()];
     for (size_t i = 0; i < heap_values.size(); i++) {
       HInstruction* ref =
@@ -612,7 +617,7 @@
     if (ref_info->IsSingletonAndRemovable()) {
       singleton_new_arrays_.push_back(new_array);
     }
-    ArenaVector<HInstruction*>& heap_values =
+    ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[new_array->GetBlock()->GetBlockId()];
     for (size_t i = 0; i < heap_values.size(); i++) {
       HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
@@ -639,20 +644,23 @@
   const HeapLocationCollector& heap_location_collector_;
   const SideEffectsAnalysis& side_effects_;
 
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator_;
+
   // One array of heap values for each block.
-  ArenaVector<ArenaVector<HInstruction*>> heap_values_for_;
+  ScopedArenaVector<ScopedArenaVector<HInstruction*>> heap_values_for_;
 
   // We record the instructions that should be eliminated but may be
   // used by heap locations. They'll be removed in the end.
-  ArenaVector<HInstruction*> removed_loads_;
-  ArenaVector<HInstruction*> substitute_instructions_for_loads_;
+  ScopedArenaVector<HInstruction*> removed_loads_;
+  ScopedArenaVector<HInstruction*> substitute_instructions_for_loads_;
 
   // Stores in this list may be removed from the list later when it's
   // found that the store cannot be eliminated.
-  ArenaVector<HInstruction*> possibly_removed_stores_;
+  ScopedArenaVector<HInstruction*> possibly_removed_stores_;
 
-  ArenaVector<HInstruction*> singleton_new_instances_;
-  ArenaVector<HInstruction*> singleton_new_arrays_;
+  ScopedArenaVector<HInstruction*> singleton_new_instances_;
+  ScopedArenaVector<HInstruction*> singleton_new_arrays_;
 
   DISALLOW_COPY_AND_ASSIGN(LSEVisitor);
 };
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index d87861b..69c6b94 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1359,7 +1359,7 @@
           *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction;
           return TrySetVectorLength(4);
         case DataType::Type::kInt32:
-          *restrictions |= kNoDiv | kNoReduction;
+          *restrictions |= kNoDiv | kNoWideSAD;
           return TrySetVectorLength(2);
         default:
           break;
@@ -1623,17 +1623,28 @@
   }
   // Prepare the new initialization.
   if (vector_mode_ == kVector) {
-    // Generate a [initial, 0, .., 0] vector.
+    // Generate a [initial, 0, .., 0] vector for add or
+    // a [initial, initial, .., initial] vector for min/max.
     HVecOperation* red_vector = new_red->AsVecOperation();
+    HVecReduce::ReductionKind kind = GetReductionKind(red_vector);
     size_t vector_length = red_vector->GetVectorLength();
     DataType::Type type = red_vector->GetPackedType();
-    new_init = Insert(vector_preheader_,
-                      new (global_allocator_) HVecSetScalars(global_allocator_,
-                                                             &new_init,
-                                                             type,
-                                                             vector_length,
-                                                             1,
-                                                             kNoDexPc));
+    if (kind == HVecReduce::ReductionKind::kSum) {
+      new_init = Insert(vector_preheader_,
+                        new (global_allocator_) HVecSetScalars(global_allocator_,
+                                                               &new_init,
+                                                               type,
+                                                               vector_length,
+                                                               1,
+                                                               kNoDexPc));
+    } else {
+      new_init = Insert(vector_preheader_,
+                        new (global_allocator_) HVecReplicateScalar(global_allocator_,
+                                                                    new_init,
+                                                                    type,
+                                                                    vector_length,
+                                                                    kNoDexPc));
+    }
   } else {
     new_init = ReduceAndExtractIfNeeded(new_init);
   }
@@ -1968,7 +1979,9 @@
     return false;
   }
   // Try same/narrower type and deal with vector restrictions.
-  if (!TrySetVectorType(sub_type, &restrictions) || HasVectorRestrictions(restrictions, kNoSAD)) {
+  if (!TrySetVectorType(sub_type, &restrictions) ||
+      HasVectorRestrictions(restrictions, kNoSAD) ||
+      (reduction_type != sub_type && HasVectorRestrictions(restrictions, kNoWideSAD))) {
     return false;
   }
   // Accept SAD idiom for vectorizable operands. Vectorized code uses the shorthand
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index b1b3d11..768fe55 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -78,6 +78,7 @@
     kNoStringCharAt  = 1 << 9,   // no StringCharAt
     kNoReduction     = 1 << 10,  // no reduction
     kNoSAD           = 1 << 11,  // no sum of absolute differences (SAD)
+    kNoWideSAD       = 1 << 12,  // no sum of absolute differences (SAD) with operand widening
   };
 
   /*
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 1a537ca..f4f6434 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -55,14 +55,18 @@
   // "visited" must be empty on entry, it's an output argument for all visited (i.e. live) blocks.
   DCHECK_EQ(visited->GetHighestBitSet(), -1);
 
+  // Allocate memory from local ScopedArenaAllocator.
+  ScopedArenaAllocator allocator(GetArenaStack());
   // Nodes that we're currently visiting, indexed by block id.
-  ArenaBitVector visiting(allocator_, blocks_.size(), false, kArenaAllocGraphBuilder);
+  ArenaBitVector visiting(
+      &allocator, blocks_.size(), /* expandable */ false, kArenaAllocGraphBuilder);
+  visiting.ClearAllBits();
   // Number of successors visited from a given node, indexed by block id.
-  ArenaVector<size_t> successors_visited(blocks_.size(),
-                                         0u,
-                                         allocator_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<size_t> successors_visited(blocks_.size(),
+                                               0u,
+                                               allocator.Adapter(kArenaAllocGraphBuilder));
   // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
-  ArenaVector<HBasicBlock*> worklist(allocator_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
   constexpr size_t kDefaultWorklistSize = 8;
   worklist.reserve(kDefaultWorklistSize);
   visited->SetBit(entry_block_->GetBlockId());
@@ -173,7 +177,11 @@
 }
 
 GraphAnalysisResult HGraph::BuildDominatorTree() {
-  ArenaBitVector visited(allocator_, blocks_.size(), false, kArenaAllocGraphBuilder);
+  // Allocate memory from local ScopedArenaAllocator.
+  ScopedArenaAllocator allocator(GetArenaStack());
+
+  ArenaBitVector visited(&allocator, blocks_.size(), false, kArenaAllocGraphBuilder);
+  visited.ClearAllBits();
 
   // (1) Find the back edges in the graph doing a DFS traversal.
   FindBackEdges(&visited);
@@ -258,14 +266,16 @@
   reverse_post_order_.reserve(blocks_.size());
   reverse_post_order_.push_back(entry_block_);
 
+  // Allocate memory from local ScopedArenaAllocator.
+  ScopedArenaAllocator allocator(GetArenaStack());
   // Number of visits of a given node, indexed by block id.
-  ArenaVector<size_t> visits(blocks_.size(), 0u, allocator_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<size_t> visits(blocks_.size(), 0u, allocator.Adapter(kArenaAllocGraphBuilder));
   // Number of successors visited from a given node, indexed by block id.
-  ArenaVector<size_t> successors_visited(blocks_.size(),
-                                         0u,
-                                         allocator_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<size_t> successors_visited(blocks_.size(),
+                                               0u,
+                                               allocator.Adapter(kArenaAllocGraphBuilder));
   // Nodes for which we need to visit successors.
-  ArenaVector<HBasicBlock*> worklist(allocator_->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
   constexpr size_t kDefaultWorklistSize = 8;
   worklist.reserve(kDefaultWorklistSize);
   worklist.push_back(entry_block_);
@@ -710,10 +720,13 @@
   bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader();
 
   if (is_irreducible_loop) {
-    ArenaBitVector visited(graph->GetAllocator(),
+    // Allocate memory from local ScopedArenaAllocator.
+    ScopedArenaAllocator allocator(graph->GetArenaStack());
+    ArenaBitVector visited(&allocator,
                            graph->GetBlocks().size(),
                            /* expandable */ false,
                            kArenaAllocGraphBuilder);
+    visited.ClearAllBits();
     // Stop marking blocks at the loop header.
     visited.SetBit(header_->GetBlockId());
 
@@ -942,7 +955,7 @@
   }
 }
 
-void HEnvironment::CopyFrom(const ArenaVector<HInstruction*>& locals) {
+void HEnvironment::CopyFrom(ArrayRef<HInstruction* const> locals) {
   for (size_t i = 0; i < locals.size(); i++) {
     HInstruction* instruction = locals[i];
     SetRawEnvAt(i, instruction);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 99fde75..75cdb3e 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1839,7 +1839,7 @@
     }
   }
 
-  void CopyFrom(const ArenaVector<HInstruction*>& locals);
+  void CopyFrom(ArrayRef<HInstruction* const> locals);
   void CopyFrom(HEnvironment* environment);
 
   // Copy from `env`. If it's a loop phi for `loop_header`, copy the first
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index b2180d9..9bfd250 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -129,10 +129,9 @@
 
   HEnvironment* environment = new (GetAllocator()) HEnvironment(
       GetAllocator(), 1, graph->GetArtMethod(), 0, with_environment);
-  ArenaVector<HInstruction*> array(GetAllocator()->Adapter());
-  array.push_back(parameter1);
+  HInstruction* const array[] = { parameter1 };
 
-  environment->CopyFrom(array);
+  environment->CopyFrom(ArrayRef<HInstruction* const>(array));
   with_environment->SetRawEnvironment(environment);
 
   ASSERT_TRUE(parameter1->HasEnvironmentUses());
@@ -140,13 +139,13 @@
 
   HEnvironment* parent1 = new (GetAllocator()) HEnvironment(
       GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr);
-  parent1->CopyFrom(array);
+  parent1->CopyFrom(ArrayRef<HInstruction* const>(array));
 
   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u);
 
   HEnvironment* parent2 = new (GetAllocator()) HEnvironment(
       GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr);
-  parent2->CopyFrom(array);
+  parent2->CopyFrom(ArrayRef<HInstruction* const>(array));
   parent1->SetAndCopyParentChain(GetAllocator(), parent2);
 
   // One use for parent2, and one other use for the new parent of parent1.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 9bfb7a5..42f32b7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1146,7 +1146,8 @@
         if (total_allocated > kArenaAllocatorMemoryReportThreshold) {
           MemStats mem_stats(allocator.GetMemStats());
           MemStats peak_stats(arena_stack.GetPeakStats());
-          LOG(INFO) << dex_file.PrettyMethod(method_idx)
+          LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling "
+                    << dex_file.PrettyMethod(method_idx)
                     << "\n" << Dumpable<MemStats>(mem_stats)
                     << "\n" << Dumpable<MemStats>(peak_stats);
         }
@@ -1256,7 +1257,8 @@
       if (total_allocated > kArenaAllocatorMemoryReportThreshold) {
         MemStats mem_stats(allocator.GetMemStats());
         MemStats peak_stats(arena_stack.GetPeakStats());
-        LOG(INFO) << dex_file->PrettyMethod(method_idx)
+        LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling "
+                  << dex_file->PrettyMethod(method_idx)
                   << "\n" << Dumpable<MemStats>(mem_stats)
                   << "\n" << Dumpable<MemStats>(peak_stats);
       }
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 5632f9a4..9aba912 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -22,7 +22,9 @@
 #include "common_compiler_test.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
-#include "handle_scope.h"
+#include "handle_scope-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/dex_cache.h"
 #include "nodes.h"
 #include "scoped_thread_state_change.h"
 #include "ssa_builder.h"
@@ -123,8 +125,7 @@
 
   // Create a control-flow graph from Dex instructions.
   HGraph* CreateCFG(const uint16_t* data, DataType::Type return_type = DataType::Type::kInt32) {
-    const DexFile::CodeItem* item =
-      reinterpret_cast<const DexFile::CodeItem*>(data);
+    const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(data);
     HGraph* graph = CreateGraph();
 
     {
@@ -132,7 +133,19 @@
       if (handles_ == nullptr) {
         handles_.reset(new VariableSizedHandleScope(soa.Self()));
       }
-      HGraphBuilder builder(graph, *item, handles_.get(), return_type);
+      const DexFile* dex_file = graph->GetAllocator()->Alloc<DexFile>();
+      const DexCompilationUnit* dex_compilation_unit =
+          new (graph->GetAllocator()) DexCompilationUnit(
+              handles_->NewHandle<mirror::ClassLoader>(nullptr),
+              /* class_linker */ nullptr,
+              *dex_file,
+              code_item,
+              /* class_def_index */ DexFile::kDexNoIndex16,
+              /* method_idx */ dex::kDexNoIndex,
+              /* access_flags */ 0u,
+              /* verified_method */ nullptr,
+              handles_->NewHandle<mirror::DexCache>(nullptr));
+      HGraphBuilder builder(graph, dex_compilation_unit, *code_item, handles_.get(), return_type);
       bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
       return graph_built ? graph : nullptr;
     }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 6d9ebc8..cb9dc42 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -18,8 +18,11 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "base/enums.h"
 #include "class_linker-inl.h"
+#include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
 #include "scoped_thread_state_change-inl.h"
@@ -70,14 +73,16 @@
              Handle<mirror::ClassLoader> class_loader,
              Handle<mirror::DexCache> hint_dex_cache,
              HandleCache* handle_cache,
-             ArenaVector<HInstruction*>* worklist,
              bool is_first_run)
     : HGraphDelegateVisitor(graph),
       class_loader_(class_loader),
       hint_dex_cache_(hint_dex_cache),
       handle_cache_(handle_cache),
-      worklist_(worklist),
-      is_first_run_(is_first_run) {}
+      allocator_(graph->GetArenaStack()),
+      worklist_(allocator_.Adapter(kArenaAllocReferenceTypePropagation)),
+      is_first_run_(is_first_run) {
+    worklist_.reserve(kDefaultWorklistSize);
+  }
 
   void VisitDeoptimize(HDeoptimize* deopt) OVERRIDE;
   void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
@@ -87,9 +92,6 @@
   void VisitLoadException(HLoadException* instr) OVERRIDE;
   void VisitNewArray(HNewArray* instr) OVERRIDE;
   void VisitParameterValue(HParameterValue* instr) OVERRIDE;
-  void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
-  void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact)
-      REQUIRES_SHARED(Locks::mutator_lock_);
   void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
   void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
   void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
@@ -99,16 +101,39 @@
   void VisitCheckCast(HCheckCast* instr) OVERRIDE;
   void VisitBoundType(HBoundType* instr) OVERRIDE;
   void VisitNullCheck(HNullCheck* instr) OVERRIDE;
+  void VisitPhi(HPhi* phi);
+
+  void VisitBasicBlock(HBasicBlock* block);
+  void ProcessWorklist();
+
+ private:
+  void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
+  void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  void BoundTypeForIfNotNull(HBasicBlock* block);
+  static void BoundTypeForIfInstanceOf(HBasicBlock* block);
+  static bool UpdateNullability(HInstruction* instr);
+  static void UpdateBoundType(HBoundType* bound_type) REQUIRES_SHARED(Locks::mutator_lock_);
+  void UpdateArrayGet(HArrayGet* instr) REQUIRES_SHARED(Locks::mutator_lock_);
+  void UpdatePhi(HPhi* phi) REQUIRES_SHARED(Locks::mutator_lock_);
+  bool UpdateReferenceTypeInfo(HInstruction* instr);
   void UpdateReferenceTypeInfo(HInstruction* instr,
                                dex::TypeIndex type_idx,
                                const DexFile& dex_file,
                                bool is_exact);
 
- private:
+  void AddToWorklist(HInstruction* instruction);
+  void AddDependentInstructionsToWorklist(HInstruction* instruction);
+
+  static constexpr size_t kDefaultWorklistSize = 8;
+
   Handle<mirror::ClassLoader> class_loader_;
   Handle<mirror::DexCache> hint_dex_cache_;
-  HandleCache* handle_cache_;
-  ArenaVector<HInstruction*>* worklist_;
+  HandleCache* const handle_cache_;
+
+  // Use local allocator for allocating memory.
+  ScopedArenaAllocator allocator_;
+  ScopedArenaVector<HInstruction*> worklist_;
   const bool is_first_run_;
 };
 
@@ -122,7 +147,6 @@
       class_loader_(class_loader),
       hint_dex_cache_(hint_dex_cache),
       handle_cache_(handles),
-      worklist_(graph->GetAllocator()->Adapter(kArenaAllocReferenceTypePropagation)),
       is_first_run_(is_first_run) {
 }
 
@@ -158,7 +182,6 @@
                      class_loader_,
                      hint_dex_cache_,
                      &handle_cache_,
-                     &worklist_,
                      is_first_run_);
   instruction->Accept(&visitor);
 }
@@ -319,26 +342,20 @@
 }
 
 void ReferenceTypePropagation::Run() {
-  worklist_.reserve(kDefaultWorklistSize);
+  RTPVisitor visitor(graph_, class_loader_, hint_dex_cache_, &handle_cache_, is_first_run_);
 
   // To properly propagate type info we need to visit in the dominator-based order.
   // Reverse post order guarantees a node's dominators are visited first.
   // We take advantage of this order in `VisitBasicBlock`.
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
-    VisitBasicBlock(block);
+    visitor.VisitBasicBlock(block);
   }
 
-  ProcessWorklist();
+  visitor.ProcessWorklist();
   ValidateTypes();
 }
 
-void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
-  RTPVisitor visitor(graph_,
-                     class_loader_,
-                     hint_dex_cache_,
-                     &handle_cache_,
-                     &worklist_,
-                     is_first_run_);
+void ReferenceTypePropagation::RTPVisitor::VisitBasicBlock(HBasicBlock* block) {
   // Handle Phis first as there might be instructions in the same block who depend on them.
   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     VisitPhi(it.Current()->AsPhi());
@@ -348,7 +365,7 @@
   // last visited instruction, use `HInstructionIteratorHandleChanges` iterator.
   for (HInstructionIteratorHandleChanges it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* instr = it.Current();
-    instr->Accept(&visitor);
+    instr->Accept(this);
   }
 
   // Add extra nodes to bound types.
@@ -357,7 +374,7 @@
   BoundTypeForClassCheck(block->GetLastInstruction());
 }
 
-void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
+void ReferenceTypePropagation::RTPVisitor::BoundTypeForIfNotNull(HBasicBlock* block) {
   HIf* ifInstruction = block->GetLastInstruction()->AsIf();
   if (ifInstruction == nullptr) {
     return;
@@ -391,7 +408,7 @@
       : ifInstruction->IfFalseSuccessor();
 
   ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
-      handle_cache_.GetObjectClassHandle(), /* is_exact */ false);
+      handle_cache_->GetObjectClassHandle(), /* is_exact */ false);
 
   BoundTypeIn(obj, notNullBlock, /* start_instruction */ nullptr, object_rti);
 }
@@ -469,7 +486,7 @@
 // `if (x instanceof ClassX) { }`
 // If that's the case insert an HBoundType instruction to bound the type of `x`
 // to `ClassX` in the scope of the dominated blocks.
-void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
+void ReferenceTypePropagation::RTPVisitor::BoundTypeForIfInstanceOf(HBasicBlock* block) {
   HIf* ifInstruction = block->GetLastInstruction()->AsIf();
   if (ifInstruction == nullptr) {
     return;
@@ -728,7 +745,7 @@
   }
 }
 
-void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
+void ReferenceTypePropagation::RTPVisitor::VisitPhi(HPhi* phi) {
   if (phi->IsDead() || phi->GetType() != DataType::Type::kReference) {
     return;
   }
@@ -812,7 +829,7 @@
   return ReferenceTypeInfo::Create(result_type_handle, is_exact);
 }
 
-void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
+void ReferenceTypePropagation::RTPVisitor::UpdateArrayGet(HArrayGet* instr) {
   DCHECK_EQ(DataType::Type::kReference, instr->GetType());
 
   ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
@@ -823,7 +840,7 @@
   Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
   if (handle->IsObjectArrayClass() && IsAdmissible(handle->GetComponentType())) {
     ReferenceTypeInfo::TypeHandle component_handle =
-        handle_cache->NewHandle(handle->GetComponentType());
+        handle_cache_->NewHandle(handle->GetComponentType());
     bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
     instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact));
   } else {
@@ -832,7 +849,7 @@
   }
 }
 
-bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
+bool ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr) {
   ScopedObjectAccess soa(Thread::Current());
 
   ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
@@ -848,7 +865,7 @@
   } else if (instr->IsArrayGet()) {
     // TODO: consider if it's worth "looking back" and binding the input object
     // to an array type.
-    UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
+    UpdateArrayGet(instr->AsArrayGet());
   } else {
     LOG(FATAL) << "Invalid instruction (should not get here)";
   }
@@ -873,13 +890,13 @@
   }
 
   ScopedObjectAccess soa(Thread::Current());
-  UpdateArrayGet(instr, handle_cache_);
+  UpdateArrayGet(instr);
   if (!instr->GetReferenceTypeInfo().IsValid()) {
-    worklist_->push_back(instr);
+    worklist_.push_back(instr);
   }
 }
 
-void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
+void ReferenceTypePropagation::RTPVisitor::UpdateBoundType(HBoundType* instr) {
   ReferenceTypeInfo input_rti = instr->InputAt(0)->GetReferenceTypeInfo();
   if (!input_rti.IsValid()) {
     return;  // No new info yet.
@@ -903,7 +920,7 @@
 
 // NullConstant inputs are ignored during merging as they do not provide any useful information.
 // If all the inputs are NullConstants then the type of the phi will be set to Object.
-void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
+void ReferenceTypePropagation::RTPVisitor::UpdatePhi(HPhi* instr) {
   DCHECK(instr->IsLive());
 
   HInputsRef inputs = instr->GetInputs();
@@ -931,7 +948,7 @@
     if (inputs[i]->IsNullConstant()) {
       continue;
     }
-    new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), &handle_cache_);
+    new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), handle_cache_);
     if (new_rti.IsValid() && new_rti.IsObjectClass()) {
       if (!new_rti.IsExact()) {
         break;
@@ -948,7 +965,7 @@
 
 // Re-computes and updates the nullability of the instruction. Returns whether or
 // not the nullability was changed.
-bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
+bool ReferenceTypePropagation::RTPVisitor::UpdateNullability(HInstruction* instr) {
   DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
       || instr->IsBoundType()
       || instr->IsNullCheck()
@@ -976,7 +993,7 @@
   return existing_can_be_null != instr->CanBeNull();
 }
 
-void ReferenceTypePropagation::ProcessWorklist() {
+void ReferenceTypePropagation::RTPVisitor::ProcessWorklist() {
   while (!worklist_.empty()) {
     HInstruction* instruction = worklist_.back();
     worklist_.pop_back();
@@ -988,13 +1005,14 @@
   }
 }
 
-void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
+void ReferenceTypePropagation::RTPVisitor::AddToWorklist(HInstruction* instruction) {
   DCHECK_EQ(instruction->GetType(), DataType::Type::kReference)
       << instruction->DebugName() << ":" << instruction->GetType();
   worklist_.push_back(instruction);
 }
 
-void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
+void ReferenceTypePropagation::RTPVisitor::AddDependentInstructionsToWorklist(
+    HInstruction* instruction) {
   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
     HInstruction* user = use.GetUser();
     if ((user->IsPhi() && user->AsPhi()->IsLive())
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index c221282..fd4dad2 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -18,12 +18,10 @@
 #define ART_COMPILER_OPTIMIZING_REFERENCE_TYPE_PROPAGATION_H_
 
 #include "base/arena_containers.h"
-#include "driver/dex_compilation_unit.h"
-#include "handle_scope-inl.h"
+#include "mirror/class-inl.h"
 #include "nodes.h"
 #include "obj_ptr.h"
 #include "optimization.h"
-#include "optimizing_compiler_stats.h"
 
 namespace art {
 
@@ -91,22 +89,6 @@
 
   class RTPVisitor;
 
-  void VisitPhi(HPhi* phi);
-  void VisitBasicBlock(HBasicBlock* block);
-  void UpdateBoundType(HBoundType* bound_type) REQUIRES_SHARED(Locks::mutator_lock_);
-  void UpdatePhi(HPhi* phi) REQUIRES_SHARED(Locks::mutator_lock_);
-  void BoundTypeForIfNotNull(HBasicBlock* block);
-  void BoundTypeForIfInstanceOf(HBasicBlock* block);
-  void ProcessWorklist();
-  void AddToWorklist(HInstruction* instr);
-  void AddDependentInstructionsToWorklist(HInstruction* instr);
-
-  bool UpdateNullability(HInstruction* instr);
-  bool UpdateReferenceTypeInfo(HInstruction* instr);
-
-  static void UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   static ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a,
                                       const ReferenceTypeInfo& b,
                                       HandleCache* handle_cache)
@@ -122,13 +104,9 @@
   Handle<mirror::DexCache> hint_dex_cache_;
   HandleCache handle_cache_;
 
-  ArenaVector<HInstruction*> worklist_;
-
   // Whether this reference type propagation is the first run we are doing.
   const bool is_first_run_;
 
-  static constexpr size_t kDefaultWorklistSize = 8;
-
   friend class ReferenceTypePropagationTest;
 
   DISALLOW_COPY_AND_ASSIGN(ReferenceTypePropagation);
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index ece9904..86e9713 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -53,6 +53,21 @@
   }
 }
 
+RegisterAllocator::~RegisterAllocator() {
+  if (kIsDebugBuild) {
+    // Poison live interval pointers with "Error: BAD 71ve1nt3rval."
+    LiveInterval* bad_live_interval = reinterpret_cast<LiveInterval*>(0xebad7113u);
+    for (HBasicBlock* block : codegen_->GetGraph()->GetLinearOrder()) {
+      for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+        it.Current()->SetLiveInterval(bad_live_interval);
+      }
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+        it.Current()->SetLiveInterval(bad_live_interval);
+      }
+    }
+  }
+}
+
 bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph ATTRIBUTE_UNUSED,
                                                 InstructionSet instruction_set) {
   return instruction_set == kArm
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index eaeec3b..18ef69f 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -50,7 +50,7 @@
                                                    const SsaLivenessAnalysis& analysis,
                                                    Strategy strategy = kRegisterAllocatorDefault);
 
-  virtual ~RegisterAllocator() = default;
+  virtual ~RegisterAllocator();
 
   // Main entry point for the register allocator. Given the liveness analysis,
   // allocates registers to live intervals.
@@ -87,7 +87,7 @@
   // to find an optimal split position.
   LiveInterval* SplitBetween(LiveInterval* interval, size_t from, size_t to);
 
-  ScopedArenaAllocator* allocator_;
+  ScopedArenaAllocator* const allocator_;
   CodeGenerator* const codegen_;
   const SsaLivenessAnalysis& liveness_;
 };
diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc
index c673d54..57eb762 100644
--- a/compiler/optimizing/scheduler.cc
+++ b/compiler/optimizing/scheduler.cc
@@ -781,7 +781,7 @@
 #if defined(ART_ENABLE_CODEGEN_arm64) || defined(ART_ENABLE_CODEGEN_arm)
   // Phase-local allocator that allocates scheduler internal data structures like
   // scheduling nodes, internel nodes map, dependencies, etc.
-  ScopedArenaAllocator arena_allocator(graph_->GetArenaStack());
+  ScopedArenaAllocator allocator(graph_->GetArenaStack());
   CriticalPathSchedulingNodeSelector critical_path_selector;
   RandomSchedulingNodeSelector random_selector;
   SchedulingNodeSelector* selector = schedule_randomly
@@ -797,7 +797,7 @@
   switch (instruction_set_) {
 #ifdef ART_ENABLE_CODEGEN_arm64
     case kArm64: {
-      arm64::HSchedulerARM64 scheduler(&arena_allocator, selector);
+      arm64::HSchedulerARM64 scheduler(&allocator, selector);
       scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks);
       scheduler.Schedule(graph_);
       break;
@@ -807,7 +807,7 @@
     case kThumb2:
     case kArm: {
       arm::SchedulingLatencyVisitorARM arm_latency_visitor(codegen_);
-      arm::HSchedulerARM scheduler(&arena_allocator, selector, &arm_latency_visitor);
+      arm::HSchedulerARM scheduler(&allocator, selector, &arm_latency_visitor);
       scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks);
       scheduler.Schedule(graph_);
       break;
diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h
index 3efd26a..afdf6f1 100644
--- a/compiler/optimizing/scheduler.h
+++ b/compiler/optimizing/scheduler.h
@@ -253,14 +253,14 @@
  public:
   SchedulingGraph(const HScheduler* scheduler, ScopedArenaAllocator* allocator)
       : scheduler_(scheduler),
-        arena_(allocator),
+        allocator_(allocator),
         contains_scheduling_barrier_(false),
-        nodes_map_(arena_->Adapter(kArenaAllocScheduler)),
+        nodes_map_(allocator_->Adapter(kArenaAllocScheduler)),
         heap_location_collector_(nullptr) {}
 
   SchedulingNode* AddNode(HInstruction* instr, bool is_scheduling_barrier = false) {
     std::unique_ptr<SchedulingNode> node(
-        new (arena_) SchedulingNode(instr, arena_, is_scheduling_barrier));
+        new (allocator_) SchedulingNode(instr, allocator_, is_scheduling_barrier));
     SchedulingNode* result = node.get();
     nodes_map_.Insert(std::make_pair(instr, std::move(node)));
     contains_scheduling_barrier_ |= is_scheduling_barrier;
@@ -323,7 +323,7 @@
 
   const HScheduler* const scheduler_;
 
-  ScopedArenaAllocator* const arena_;
+  ScopedArenaAllocator* const allocator_;
 
   bool contains_scheduling_barrier_;
 
diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc
index 0e46aec..77ec9a6 100644
--- a/compiler/optimizing/select_generator.cc
+++ b/compiler/optimizing/select_generator.cc
@@ -16,6 +16,8 @@
 
 #include "select_generator.h"
 
+#include "reference_type_propagation.h"
+
 namespace art {
 
 static constexpr size_t kMaxInstructionsInBranch = 1u;
diff --git a/compiler/optimizing/select_generator.h b/compiler/optimizing/select_generator.h
index c060146..f8cf00e 100644
--- a/compiler/optimizing/select_generator.h
+++ b/compiler/optimizing/select_generator.h
@@ -58,7 +58,6 @@
 #define ART_COMPILER_OPTIMIZING_SELECT_GENERATOR_H_
 
 #include "optimization.h"
-#include "reference_type_propagation.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index f4a8a17..e4edbfd 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -105,7 +105,7 @@
 }
 
 static void AddDependentInstructionsToWorklist(HInstruction* instruction,
-                                               ArenaVector<HPhi*>* worklist) {
+                                               ScopedArenaVector<HPhi*>* worklist) {
   // If `instruction` is a dead phi, type conflict was just identified. All its
   // live phi users, and transitively users of those users, therefore need to be
   // marked dead/conflicting too, so we add them to the worklist. Otherwise we
@@ -167,7 +167,7 @@
 }
 
 // Replace inputs of `phi` to match its type. Return false if conflict is identified.
-bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist) {
+bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) {
   DataType::Type common_type = phi->GetType();
   if (DataType::IsIntegralType(common_type)) {
     // We do not need to retype ambiguous inputs because they are always constructed
@@ -213,7 +213,7 @@
 
 // Attempt to set the primitive type of `phi` to match its inputs. Return whether
 // it was changed by the algorithm or not.
-bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist) {
+bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) {
   DCHECK(phi->IsLive());
   DataType::Type original_type = phi->GetType();
 
@@ -233,7 +233,7 @@
 }
 
 void SsaBuilder::RunPrimitiveTypePropagation() {
-  ArenaVector<HPhi*> worklist(graph_->GetAllocator()->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder));
 
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
     if (block->IsLoopHeader()) {
@@ -262,7 +262,7 @@
   EquivalentPhisCleanup();
 }
 
-void SsaBuilder::ProcessPrimitiveTypePropagationWorklist(ArenaVector<HPhi*>* worklist) {
+void SsaBuilder::ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist) {
   // Process worklist
   while (!worklist->empty()) {
     HPhi* phi = worklist->back();
@@ -319,7 +319,7 @@
   // uses (because they are untyped) and environment uses (if --debuggable).
   // After resolving all ambiguous ArrayGets, we will re-run primitive type
   // propagation on the Phis which need to be updated.
-  ArenaVector<HPhi*> worklist(graph_->GetAllocator()->Adapter(kArenaAllocGraphBuilder));
+  ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder));
 
   {
     ScopedObjectAccess soa(Thread::Current());
@@ -623,8 +623,7 @@
       || (next->GetType() != type)) {
     ArenaAllocator* allocator = graph_->GetAllocator();
     HInputsRef inputs = phi->GetInputs();
-    HPhi* new_phi =
-        new (allocator) HPhi(allocator, phi->GetRegNumber(), inputs.size(), type);
+    HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), inputs.size(), type);
     // Copy the inputs. Note that the graph may not be correctly typed
     // by doing this copy, but the type propagation phase will fix it.
     ArrayRef<HUserRecord<HInstruction*>> new_input_records = new_phi->GetInputRecords();
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 509cdc1..60831a9 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -17,7 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_
 
-#include "base/arena_containers.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "nodes.h"
 #include "optimization.h"
 
@@ -50,15 +51,17 @@
   SsaBuilder(HGraph* graph,
              Handle<mirror::ClassLoader> class_loader,
              Handle<mirror::DexCache> dex_cache,
-             VariableSizedHandleScope* handles)
+             VariableSizedHandleScope* handles,
+             ScopedArenaAllocator* local_allocator)
       : graph_(graph),
         class_loader_(class_loader),
         dex_cache_(dex_cache),
         handles_(handles),
         agets_fixed_(false),
-        ambiguous_agets_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)),
-        ambiguous_asets_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)),
-        uninitialized_strings_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)) {
+        local_allocator_(local_allocator),
+        ambiguous_agets_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
+        ambiguous_asets_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
+        uninitialized_strings_(local_allocator->Adapter(kArenaAllocGraphBuilder)) {
     graph_->InitializeInexactObjectRTI(handles);
   }
 
@@ -105,9 +108,9 @@
   // input. Returns false if the type of an array is unknown.
   bool FixAmbiguousArrayOps();
 
-  bool TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist);
-  bool UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist);
-  void ProcessPrimitiveTypePropagationWorklist(ArenaVector<HPhi*>* worklist);
+  bool TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist);
+  bool UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist);
+  void ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist);
 
   HFloatConstant* GetFloatEquivalent(HIntConstant* constant);
   HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant);
@@ -116,7 +119,7 @@
 
   void RemoveRedundantUninitializedStrings();
 
-  HGraph* graph_;
+  HGraph* const graph_;
   Handle<mirror::ClassLoader> class_loader_;
   Handle<mirror::DexCache> dex_cache_;
   VariableSizedHandleScope* const handles_;
@@ -124,9 +127,10 @@
   // True if types of ambiguous ArrayGets have been resolved.
   bool agets_fixed_;
 
-  ArenaVector<HArrayGet*> ambiguous_agets_;
-  ArenaVector<HArraySet*> ambiguous_asets_;
-  ArenaVector<HNewInstance*> uninitialized_strings_;
+  ScopedArenaAllocator* const local_allocator_;
+  ScopedArenaVector<HArrayGet*> ambiguous_agets_;
+  ScopedArenaVector<HArraySet*> ambiguous_asets_;
+  ScopedArenaVector<HNewInstance*> uninitialized_strings_;
 
   DISALLOW_COPY_AND_ASSIGN(SsaBuilder);
 };
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 9800af7..f83bb52 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -1292,7 +1292,7 @@
 
   // Use a local ScopedArenaAllocator for allocating memory.
   // This allocator must remain alive while doing register allocation.
-  ScopedArenaAllocator* allocator_;
+  ScopedArenaAllocator* const allocator_;
 
   ScopedArenaVector<BlockInfo*> block_infos_;
 
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index 9b78e0e..b9bfbaa 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -95,8 +95,7 @@
       graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32);
   HInstruction* extra_arg2 = new (GetAllocator()) HParameterValue(
       graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference);
-  ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 },
-                                  GetAllocator()->Adapter());
+  HInstruction* const args[] = { array, index, value, extra_arg1, extra_arg2 };
   for (HInstruction* insn : args) {
     entry_->AddInstruction(insn);
   }
@@ -109,7 +108,7 @@
                                                                    /* method */ nullptr,
                                                                    /* dex_pc */ 0u,
                                                                    null_check);
-  null_check_env->CopyFrom(args);
+  null_check_env->CopyFrom(ArrayRef<HInstruction* const>(args));
   null_check->SetRawEnvironment(null_check_env);
   HInstruction* length = new (GetAllocator()) HArrayLength(array, 0);
   block->AddInstruction(length);
@@ -120,7 +119,7 @@
                                                                      /* method */ nullptr,
                                                                      /* dex_pc */ 0u,
                                                                      bounds_check);
-  bounds_check_env->CopyFrom(args);
+  bounds_check_env->CopyFrom(ArrayRef<HInstruction* const>(args));
   bounds_check->SetRawEnvironment(bounds_check_env);
   HInstruction* array_set =
       new (GetAllocator()) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0);
@@ -144,7 +143,7 @@
       // Environment uses keep the reference argument alive.
       "ranges: { [10,19) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };
-  ASSERT_EQ(arraysize(expected), args.size());
+  static_assert(arraysize(expected) == arraysize(args), "Array size check.");
   size_t arg_index = 0u;
   for (HInstruction* arg : args) {
     std::ostringstream arg_dump;
@@ -165,8 +164,7 @@
       graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32);
   HInstruction* extra_arg2 = new (GetAllocator()) HParameterValue(
       graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference);
-  ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 },
-                                  GetAllocator()->Adapter());
+  HInstruction* const args[] = { array, index, value, extra_arg1, extra_arg2 };
   for (HInstruction* insn : args) {
     entry_->AddInstruction(insn);
   }
@@ -179,7 +177,7 @@
                                                                    /* method */ nullptr,
                                                                    /* dex_pc */ 0u,
                                                                    null_check);
-  null_check_env->CopyFrom(args);
+  null_check_env->CopyFrom(ArrayRef<HInstruction* const>(args));
   null_check->SetRawEnvironment(null_check_env);
   HInstruction* length = new (GetAllocator()) HArrayLength(array, 0);
   block->AddInstruction(length);
@@ -194,7 +192,7 @@
                                                                    /* method */ nullptr,
                                                                    /* dex_pc */ 0u,
                                                                    deoptimize);
-  deoptimize_env->CopyFrom(args);
+  deoptimize_env->CopyFrom(ArrayRef<HInstruction* const>(args));
   deoptimize->SetRawEnvironment(deoptimize_env);
   HInstruction* array_set =
       new (GetAllocator()) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0);
@@ -217,7 +215,7 @@
       // Environment uses keep the reference argument alive.
       "ranges: { [10,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };
-  ASSERT_EQ(arraysize(expected), args.size());
+  static_assert(arraysize(expected) == arraysize(args), "Array size check.");
   size_t arg_index = 0u;
   for (HInstruction* arg : args) {
     std::ostringstream arg_dump;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index 3b95b86..cb27ded 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -17,7 +17,8 @@
 #include "ssa_phi_elimination.h"
 
 #include "base/arena_bit_vector.h"
-#include "base/arena_containers.h"
+#include "base/scoped_arena_allocator.h"
+#include "base/scoped_arena_containers.h"
 #include "base/bit_vector-inl.h"
 
 namespace art {
@@ -28,10 +29,17 @@
 }
 
 void SsaDeadPhiElimination::MarkDeadPhis() {
+  // Use local allocator for allocating memory used by this optimization.
+  ScopedArenaAllocator allocator(graph_->GetArenaStack());
+
+  static constexpr size_t kDefaultWorklistSize = 8;
+  ScopedArenaVector<HPhi*> worklist(allocator.Adapter(kArenaAllocSsaPhiElimination));
+  worklist.reserve(kDefaultWorklistSize);
+
   // Phis are constructed live and should not be revived if previously marked
   // dead. This algorithm temporarily breaks that invariant but we DCHECK that
   // only phis which were initially live are revived.
-  ArenaSet<HPhi*> initially_live(graph_->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination));
+  ScopedArenaSet<HPhi*> initially_live(allocator.Adapter(kArenaAllocSsaPhiElimination));
 
   // Add to the worklist phis referenced by non-phi instructions.
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
@@ -52,7 +60,7 @@
       }
 
       if (keep_alive) {
-        worklist_.push_back(phi);
+        worklist.push_back(phi);
       } else {
         phi->SetDead();
         if (kIsDebugBuild) {
@@ -63,9 +71,9 @@
   }
 
   // Process the worklist by propagating liveness to phi inputs.
-  while (!worklist_.empty()) {
-    HPhi* phi = worklist_.back();
-    worklist_.pop_back();
+  while (!worklist.empty()) {
+    HPhi* phi = worklist.back();
+    worklist.pop_back();
     for (HInstruction* raw_input : phi->GetInputs()) {
       HPhi* input = raw_input->AsPhi();
       if (input != nullptr && input->IsDead()) {
@@ -73,7 +81,7 @@
         // that the phi was not dead initially (see definition of `initially_live`).
         DCHECK(ContainsElement(initially_live, input));
         input->SetLive();
-        worklist_.push_back(input);
+        worklist.push_back(input);
       }
     }
   }
@@ -115,23 +123,31 @@
 }
 
 void SsaRedundantPhiElimination::Run() {
+  // Use local allocator for allocating memory used by this optimization.
+  ScopedArenaAllocator allocator(graph_->GetArenaStack());
+
+  static constexpr size_t kDefaultWorklistSize = 8;
+  ScopedArenaVector<HPhi*> worklist(allocator.Adapter(kArenaAllocSsaPhiElimination));
+  worklist.reserve(kDefaultWorklistSize);
+
   // Add all phis in the worklist. Order does not matter for correctness, and
   // neither will necessarily converge faster.
   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
     for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
-      worklist_.push_back(inst_it.Current()->AsPhi());
+      worklist.push_back(inst_it.Current()->AsPhi());
     }
   }
 
-  ArenaBitVector visited_phis_in_cycle(graph_->GetAllocator(),
+  ArenaBitVector visited_phis_in_cycle(&allocator,
                                        graph_->GetCurrentInstructionId(),
                                        /* expandable */ false,
                                        kArenaAllocSsaPhiElimination);
-  ArenaVector<HPhi*> cycle_worklist(graph_->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination));
+  visited_phis_in_cycle.ClearAllBits();
+  ScopedArenaVector<HPhi*> cycle_worklist(allocator.Adapter(kArenaAllocSsaPhiElimination));
 
-  while (!worklist_.empty()) {
-    HPhi* phi = worklist_.back();
-    worklist_.pop_back();
+  while (!worklist.empty()) {
+    HPhi* phi = worklist.back();
+    worklist.pop_back();
 
     // If the phi has already been processed, continue.
     if (!phi->IsInBlock()) {
@@ -231,7 +247,7 @@
       for (const HUseListNode<HInstruction*>& use : current->GetUses()) {
         HInstruction* user = use.GetUser();
         if (user->IsPhi() && !visited_phis_in_cycle.IsBitSet(user->GetId())) {
-          worklist_.push_back(user->AsPhi());
+          worklist.push_back(user->AsPhi());
         }
       }
       DCHECK(candidate->StrictlyDominates(current));
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index e0cde07..11d5837 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -17,7 +17,6 @@
 #ifndef ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_
 #define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_
 
-#include "base/arena_containers.h"
 #include "nodes.h"
 #include "optimization.h"
 
@@ -30,10 +29,7 @@
 class SsaDeadPhiElimination : public HOptimization {
  public:
   explicit SsaDeadPhiElimination(HGraph* graph)
-      : HOptimization(graph, kSsaDeadPhiEliminationPassName),
-        worklist_(graph->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)) {
-    worklist_.reserve(kDefaultWorklistSize);
-  }
+      : HOptimization(graph, kSsaDeadPhiEliminationPassName) {}
 
   void Run() OVERRIDE;
 
@@ -43,10 +39,6 @@
   static constexpr const char* kSsaDeadPhiEliminationPassName = "dead_phi_elimination";
 
  private:
-  ArenaVector<HPhi*> worklist_;
-
-  static constexpr size_t kDefaultWorklistSize = 8;
-
   DISALLOW_COPY_AND_ASSIGN(SsaDeadPhiElimination);
 };
 
@@ -59,20 +51,13 @@
 class SsaRedundantPhiElimination : public HOptimization {
  public:
   explicit SsaRedundantPhiElimination(HGraph* graph)
-      : HOptimization(graph, kSsaRedundantPhiEliminationPassName),
-        worklist_(graph->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)) {
-    worklist_.reserve(kDefaultWorklistSize);
-  }
+      : HOptimization(graph, kSsaRedundantPhiEliminationPassName) {}
 
   void Run() OVERRIDE;
 
   static constexpr const char* kSsaRedundantPhiEliminationPassName = "redundant_phi_elimination";
 
  private:
-  ArenaVector<HPhi*> worklist_;
-
-  static constexpr size_t kDefaultWorklistSize = 8;
-
   DISALLOW_COPY_AND_ASSIGN(SsaRedundantPhiElimination);
 };
 
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index a574566..62ed7ee 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -223,7 +223,7 @@
                            size_t dex_register_locations_index) const;
   void CheckCodeInfo(MemoryRegion region) const;
 
-  ArenaAllocator* allocator_;
+  ArenaAllocator* const allocator_;
   const InstructionSet instruction_set_;
   ArenaVector<StackMapEntry> stack_maps_;
 
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index a842c6e..96ac368 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -47,10 +47,10 @@
 
 TEST(StackMapTest, Test1) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector sp_mask(&allocator, 0, false);
   size_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
   stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
@@ -58,7 +58,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -128,11 +128,11 @@
 
 TEST(StackMapTest, Test2) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
   ArtMethod art_method;
 
-  ArenaBitVector sp_mask1(&arena, 0, true);
+  ArenaBitVector sp_mask1(&allocator, 0, true);
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
   size_t number_of_dex_registers = 2;
@@ -146,7 +146,7 @@
   stream.EndInlineInfoEntry();
   stream.EndStackMapEntry();
 
-  ArenaBitVector sp_mask2(&arena, 0, true);
+  ArenaBitVector sp_mask2(&allocator, 0, true);
   sp_mask2.SetBit(3);
   sp_mask2.SetBit(8);
   stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0);
@@ -154,7 +154,7 @@
   stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3);   // Short location.
   stream.EndStackMapEntry();
 
-  ArenaBitVector sp_mask3(&arena, 0, true);
+  ArenaBitVector sp_mask3(&allocator, 0, true);
   sp_mask3.SetBit(1);
   sp_mask3.SetBit(5);
   stream.BeginStackMapEntry(2, 192, 0xAB, &sp_mask3, number_of_dex_registers, 0);
@@ -162,7 +162,7 @@
   stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8);   // Short location.
   stream.EndStackMapEntry();
 
-  ArenaBitVector sp_mask4(&arena, 0, true);
+  ArenaBitVector sp_mask4(&allocator, 0, true);
   sp_mask4.SetBit(6);
   sp_mask4.SetBit(7);
   stream.BeginStackMapEntry(3, 256, 0xCD, &sp_mask4, number_of_dex_registers, 0);
@@ -171,7 +171,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -412,11 +412,11 @@
 
 TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
   ArtMethod art_method;
 
-  ArenaBitVector sp_mask1(&arena, 0, true);
+  ArenaBitVector sp_mask1(&allocator, 0, true);
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
   const size_t number_of_dex_registers = 2;
@@ -431,7 +431,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -506,10 +506,10 @@
 
 TEST(StackMapTest, TestNonLiveDexRegisters) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector sp_mask(&allocator, 0, false);
   uint32_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
   stream.AddDexRegisterEntry(Kind::kNone, 0);            // No location.
@@ -517,7 +517,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -585,10 +585,10 @@
 // not treat it as kNoDexRegisterMap.
 TEST(StackMapTest, DexRegisterMapOffsetOverflow) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector sp_mask(&allocator, 0, false);
   uint32_t number_of_dex_registers = 1024;
   // Create the first stack map (and its Dex register map).
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
@@ -609,7 +609,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -648,10 +648,10 @@
 
 TEST(StackMapTest, TestShareDexRegisterMap) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector sp_mask(&allocator, 0, false);
   uint32_t number_of_dex_registers = 2;
   // First stack map.
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
@@ -670,7 +670,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -706,10 +706,10 @@
 
 TEST(StackMapTest, TestNoDexRegisterMap) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, false);
+  ArenaBitVector sp_mask(&allocator, 0, false);
   uint32_t number_of_dex_registers = 0;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
   stream.EndStackMapEntry();
@@ -719,7 +719,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -755,11 +755,11 @@
 
 TEST(StackMapTest, InlineTest) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
   ArtMethod art_method;
 
-  ArenaBitVector sp_mask1(&arena, 0, true);
+  ArenaBitVector sp_mask1(&allocator, 0, true);
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
 
@@ -821,7 +821,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -936,10 +936,10 @@
 
 TEST(StackMapTest, TestDeduplicateStackMask) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, true);
+  ArenaBitVector sp_mask(&allocator, 0, true);
   sp_mask.SetBit(1);
   sp_mask.SetBit(4);
   stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0);
@@ -948,7 +948,7 @@
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
-  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  void* memory = allocator.Alloc(size, kArenaAllocMisc);
   MemoryRegion region(memory, size);
   stream.FillInCodeInfo(region);
 
@@ -964,10 +964,10 @@
 
 TEST(StackMapTest, TestInvokeInfo) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  StackMapStream stream(&arena, kRuntimeISA);
+  ArenaAllocator allocator(&pool);
+  StackMapStream stream(&allocator, kRuntimeISA);
 
-  ArenaBitVector sp_mask(&arena, 0, true);
+  ArenaBitVector sp_mask(&allocator, 0, true);
   sp_mask.SetBit(1);
   stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0);
   stream.AddInvoke(kSuper, 1);
@@ -980,11 +980,12 @@
   stream.EndStackMapEntry();
 
   const size_t code_info_size = stream.PrepareForFillIn();
-  MemoryRegion code_info_region(arena.Alloc(code_info_size, kArenaAllocMisc), code_info_size);
+  MemoryRegion code_info_region(allocator.Alloc(code_info_size, kArenaAllocMisc), code_info_size);
   stream.FillInCodeInfo(code_info_region);
 
   const size_t method_info_size = stream.ComputeMethodInfoSize();
-  MemoryRegion method_info_region(arena.Alloc(method_info_size, kArenaAllocMisc), method_info_size);
+  MemoryRegion method_info_region(allocator.Alloc(method_info_size, kArenaAllocMisc),
+                                  method_info_size);
   stream.FillInMethodInfo(method_info_region);
 
   CodeInfo code_info(code_info_region);
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index 1e9a521..9527a60 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -244,19 +244,19 @@
                                                                EntryPointCallingConvention abi,
                                                                ThreadOffset64 offset) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
+  ArenaAllocator allocator(&pool);
   switch (isa) {
 #ifdef ART_ENABLE_CODEGEN_arm64
     case kArm64:
-      return arm64::CreateTrampoline(&arena, abi, offset);
+      return arm64::CreateTrampoline(&allocator, abi, offset);
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips64
     case kMips64:
-      return mips64::CreateTrampoline(&arena, abi, offset);
+      return mips64::CreateTrampoline(&allocator, abi, offset);
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86_64
     case kX86_64:
-      return x86_64::CreateTrampoline(&arena, offset);
+      return x86_64::CreateTrampoline(&allocator, offset);
 #endif
     default:
       UNUSED(abi);
@@ -270,21 +270,21 @@
                                                                EntryPointCallingConvention abi,
                                                                ThreadOffset32 offset) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
+  ArenaAllocator allocator(&pool);
   switch (isa) {
 #ifdef ART_ENABLE_CODEGEN_arm
     case kArm:
     case kThumb2:
-      return arm::CreateTrampoline(&arena, abi, offset);
+      return arm::CreateTrampoline(&allocator, abi, offset);
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips
     case kMips:
-      return mips::CreateTrampoline(&arena, abi, offset);
+      return mips::CreateTrampoline(&allocator, abi, offset);
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86
     case kX86:
       UNUSED(abi);
-      return x86::CreateTrampoline(&arena, offset);
+      return x86::CreateTrampoline(&allocator, offset);
 #endif
     default:
       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index dbd35ab..e0cef85 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -252,7 +252,7 @@
   // for a single, fast space check per instruction.
   static const int kMinimumGap = 32;
 
-  ArenaAllocator* allocator_;
+  ArenaAllocator* const allocator_;
   uint8_t* contents_;
   uint8_t* cursor_;
   uint8_t* limit_;
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 11a9b91..ae7636b 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -719,8 +719,8 @@
   explicit AssemblerTest() {}
 
   void SetUp() OVERRIDE {
-    arena_.reset(new ArenaAllocator(&pool_));
-    assembler_.reset(CreateAssembler(arena_.get()));
+    allocator_.reset(new ArenaAllocator(&pool_));
+    assembler_.reset(CreateAssembler(allocator_.get()));
     test_helper_.reset(
         new AssemblerTestInfrastructure(GetArchitectureString(),
                                         GetAssemblerCmdName(),
@@ -737,7 +737,7 @@
   void TearDown() OVERRIDE {
     test_helper_.reset();  // Clean up the helper.
     assembler_.reset();
-    arena_.reset();
+    allocator_.reset();
   }
 
   // Override this to set up any architecture-specific things, e.g., CPU revision.
@@ -1589,7 +1589,7 @@
   static constexpr size_t kWarnManyCombinationsThreshold = 500;
 
   ArenaPool pool_;
-  std::unique_ptr<ArenaAllocator> arena_;
+  std::unique_ptr<ArenaAllocator> allocator_;
   std::unique_ptr<Ass> assembler_;
   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
 
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 5622f89..5307d17 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -167,10 +167,10 @@
 
 class ArmVIXLAssemblerTest : public ::testing::Test {
  public:
-  ArmVIXLAssemblerTest() : pool(), arena(&pool), assembler(&arena) { }
+  ArmVIXLAssemblerTest() : pool(), allocator(&pool), assembler(&allocator) { }
 
   ArenaPool pool;
-  ArenaAllocator arena;
+  ArenaAllocator allocator;
   ArmVIXLJNIMacroAssembler assembler;
 };
 
@@ -209,18 +209,16 @@
   const bool is_critical_native = false;
   const char* shorty = "IIFII";
 
-  ArenaPool pool;
-  ArenaAllocator arena(&pool);
-
   std::unique_ptr<JniCallingConvention> jni_conv(
-      JniCallingConvention::Create(&arena,
+      JniCallingConvention::Create(&allocator,
                                    is_static,
                                    is_synchronized,
                                    is_critical_native,
                                    shorty,
                                    kThumb2));
   std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
-      ManagedRuntimeCallingConvention::Create(&arena, is_static, is_synchronized, shorty, kThumb2));
+      ManagedRuntimeCallingConvention::Create(
+          &allocator, is_static, is_synchronized, shorty, kThumb2));
   const int frame_size(jni_conv->FrameSize());
   ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
 
diff --git a/compiler/utils/jni_macro_assembler_test.h b/compiler/utils/jni_macro_assembler_test.h
index ba95e21..34ab4c3 100644
--- a/compiler/utils/jni_macro_assembler_test.h
+++ b/compiler/utils/jni_macro_assembler_test.h
@@ -58,8 +58,8 @@
   explicit JNIMacroAssemblerTest() {}
 
   void SetUp() OVERRIDE {
-    arena_.reset(new ArenaAllocator(&pool_));
-    assembler_.reset(CreateAssembler(arena_.get()));
+    allocator_.reset(new ArenaAllocator(&pool_));
+    assembler_.reset(CreateAssembler(allocator_.get()));
     test_helper_.reset(
         new AssemblerTestInfrastructure(GetArchitectureString(),
                                         GetAssemblerCmdName(),
@@ -76,7 +76,7 @@
   void TearDown() OVERRIDE {
     test_helper_.reset();  // Clean up the helper.
     assembler_.reset();
-    arena_.reset();
+    allocator_.reset();
   }
 
   // Override this to set up any architecture-specific things, e.g., CPU revision.
@@ -140,7 +140,7 @@
   }
 
   ArenaPool pool_;
-  std::unique_ptr<ArenaAllocator> arena_;
+  std::unique_ptr<ArenaAllocator> allocator_;
   std::unique_ptr<Ass> assembler_;
   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
 
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h
index 9ba3903..0da30fe 100644
--- a/compiler/utils/test_dex_file_builder.h
+++ b/compiler/utils/test_dex_file_builder.h
@@ -26,7 +26,8 @@
 
 #include "base/bit_utils.h"
 #include "base/logging.h"
-#include "dex_file.h"
+#include "dex_file_loader.h"
+#include "standard_dex_file.h"
 
 namespace art {
 
@@ -88,8 +89,8 @@
     } header_data;
     std::memset(header_data.data, 0, sizeof(header_data.data));
     DexFile::Header* header = reinterpret_cast<DexFile::Header*>(&header_data.data);
-    std::copy_n(DexFile::kDexMagic, 4u, header->magic_);
-    std::copy_n(DexFile::kDexMagicVersions[0], 4u, header->magic_ + 4u);
+    std::copy_n(StandardDexFile::kDexMagic, 4u, header->magic_);
+    std::copy_n(StandardDexFile::kDexMagicVersions[0], 4u, header->magic_ + 4u);
     header->header_size_ = sizeof(DexFile::Header);
     header->endian_tag_ = DexFile::kDexEndianConstant;
     header->link_size_ = 0u;  // Unused.
@@ -231,7 +232,7 @@
     static constexpr bool kVerify = false;
     static constexpr bool kVerifyChecksum = false;
     std::string error_msg;
-    std::unique_ptr<const DexFile> dex_file(DexFile::Open(
+    std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(
         &dex_file_data_[0],
         dex_file_data_.size(),
         dex_location,
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index cccde37..e232add 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -24,8 +24,8 @@
 
 TEST(AssemblerX86, CreateBuffer) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  AssemblerBuffer buffer(&arena);
+  ArenaAllocator allocator(&pool);
+  AssemblerBuffer buffer(&allocator);
   AssemblerBuffer::EnsureCapacity ensured(&buffer);
   buffer.Emit<uint8_t>(0x42);
   ASSERT_EQ(static_cast<size_t>(1), buffer.Size());
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index b08ba4a..0cb3ffd 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -30,8 +30,8 @@
 
 TEST(AssemblerX86_64, CreateBuffer) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  AssemblerBuffer buffer(&arena);
+  ArenaAllocator allocator(&pool);
+  AssemblerBuffer buffer(&allocator);
   AssemblerBuffer::EnsureCapacity ensured(&buffer);
   buffer.Emit<uint8_t>(0x42);
   ASSERT_EQ(static_cast<size_t>(1), buffer.Size());
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
index cca9ac4..c1944fb 100644
--- a/dalvikvm/Android.bp
+++ b/dalvikvm/Android.bp
@@ -34,9 +34,8 @@
             shared_libs: [
                 "liblog",
             ],
-            ldflags: ["-Wl,--export-dynamic"],
         },
-        linux_glibc: {
+        linux: {
             ldflags: ["-Wl,--export-dynamic"],
         },
     },
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index f20e934..ae7ebe2 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -28,6 +28,7 @@
 #include "base/macros.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "jit/profile_compilation_info.h"
 #include "method_reference.h"
 #include "runtime.h"
@@ -62,7 +63,11 @@
     for (const std::string& dex : GetLibCoreDexFileNames()) {
       std::vector<std::unique_ptr<const DexFile>> dex_files;
       std::string error_msg;
-      CHECK(DexFile::Open(dex.c_str(), dex, /*verify_checksum*/ false, &error_msg, &dex_files))
+      CHECK(DexFileLoader::Open(dex.c_str(),
+                                dex,
+                                /*verify_checksum*/ false,
+                                &error_msg,
+                                &dex_files))
           << error_msg;
       for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
         for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5bf3513..1b731fc 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -33,6 +33,7 @@
 #include "dex2oat_environment_test.h"
 #include "dex2oat_return_codes.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "jit/profile_compilation_info.h"
 #include "oat.h"
 #include "oat_file.h"
@@ -677,7 +678,7 @@
     const char* location = dex_location.c_str();
     std::string error_msg;
     std::vector<std::unique_ptr<const DexFile>> dex_files;
-    ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+    ASSERT_TRUE(DexFileLoader::Open(location, location, true, &error_msg, &dex_files));
     EXPECT_EQ(dex_files.size(), 1U);
     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
     GenerateProfile(profile_location,
@@ -811,7 +812,7 @@
 
     const char* location = dex_location.c_str();
     std::vector<std::unique_ptr<const DexFile>> dex_files;
-    ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+    ASSERT_TRUE(DexFileLoader::Open(location, location, true, &error_msg, &dex_files));
     EXPECT_EQ(dex_files.size(), 1U);
     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
 
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index dfbe31a..0fd24a8 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -34,6 +34,7 @@
 #include "debug/method_debug_info.h"
 #include "dex/verification_results.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "dexlayout.h"
 #include "driver/compiler_driver-inl.h"
@@ -52,6 +53,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
+#include "standard_dex_file.h"
 #include "oat_quick_method_header.h"
 #include "os.h"
 #include "safe_map.h"
@@ -415,7 +417,7 @@
   if (fd.Fd() == -1) {
     PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
     return false;
-  } else if (IsDexMagic(magic)) {
+  } else if (DexFileLoader::IsValidMagic(magic)) {
     // The file is open for reading, not writing, so it's OK to let the File destructor
     // close it without checking for explicit Close(), so pass checkUsage = false.
     raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
@@ -447,13 +449,13 @@
     return false;
   }
   for (size_t i = 0; ; ++i) {
-    std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
+    std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(i);
     std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
     if (entry == nullptr) {
       break;
     }
     zipped_dex_files_.push_back(std::move(entry));
-    zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+    zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
     const char* full_location = zipped_dex_file_locations_.back().c_str();
     oat_dex_files_.emplace_back(full_location,
                                 DexFileSource(zipped_dex_files_.back().get()),
@@ -478,12 +480,13 @@
       LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
       return false;
     }
-    if (!DexFile::IsMagicValid(current_dex_data)) {
+
+    if (!DexFileLoader::IsValidMagic(current_dex_data)) {
       LOG(ERROR) << "Invalid magic in vdex file created from " << location;
       return false;
     }
     // We used `zipped_dex_file_locations_` to keep the strings in memory.
-    zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+    zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
     const char* full_location = zipped_dex_file_locations_.back().c_str();
     oat_dex_files_.emplace_back(full_location,
                                 DexFileSource(current_dex_data),
@@ -3107,11 +3110,12 @@
 }
 
 bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
-  if (!DexFile::IsMagicValid(raw_header)) {
+  const bool valid_standard_dex_magic = StandardDexFile::IsMagicValid(raw_header);
+  if (!valid_standard_dex_magic) {
     LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
     return false;
   }
-  if (!DexFile::IsVersionValid(raw_header)) {
+  if (!StandardDexFile::IsVersionValid(raw_header)) {
     LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
     return false;
   }
@@ -3242,12 +3246,12 @@
       LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
       return false;
     }
-    dex_file = DexFile::Open(location,
-                             zip_entry->GetCrc32(),
-                             std::move(mem_map),
-                             /* verify */ true,
-                             /* verify_checksum */ true,
-                             &error_msg);
+    dex_file = DexFileLoader::Open(location,
+                                   zip_entry->GetCrc32(),
+                                   std::move(mem_map),
+                                   /* verify */ true,
+                                   /* verify_checksum */ true,
+                                   &error_msg);
   } else if (oat_dex_file->source_.IsRawFile()) {
     File* raw_file = oat_dex_file->source_.GetRawFile();
     int dup_fd = dup(raw_file->Fd());
@@ -3255,7 +3259,7 @@
       PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
       return false;
     }
-    dex_file = DexFile::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
+    dex_file = DexFileLoader::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
   } else {
     // The source data is a vdex file.
     CHECK(oat_dex_file->source_.IsRawData())
@@ -3267,14 +3271,14 @@
     DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
     // Since the source may have had its layout changed, or may be quickened, don't verify it.
-    dex_file = DexFile::Open(raw_dex_file,
-                             header->file_size_,
-                             location,
-                             oat_dex_file->dex_file_location_checksum_,
-                             nullptr,
-                             /* verify */ false,
-                             /* verify_checksum */ false,
-                             &error_msg);
+    dex_file = DexFileLoader::Open(raw_dex_file,
+                                   header->file_size_,
+                                   location,
+                                   oat_dex_file->dex_file_location_checksum_,
+                                   nullptr,
+                                   /* verify */ false,
+                                   /* verify_checksum */ false,
+                                   &error_msg);
   }
   if (dex_file == nullptr) {
     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
@@ -3532,14 +3536,14 @@
     }
 
     // Now, open the dex file.
-    dex_files.emplace_back(DexFile::Open(raw_dex_file,
-                                         oat_dex_file.dex_file_size_,
-                                         oat_dex_file.GetLocation(),
-                                         oat_dex_file.dex_file_location_checksum_,
-                                         /* oat_dex_file */ nullptr,
-                                         verify,
-                                         verify,
-                                         &error_msg));
+    dex_files.emplace_back(DexFileLoader::Open(raw_dex_file,
+                                               oat_dex_file.dex_file_size_,
+                                               oat_dex_file.GetLocation(),
+                                               oat_dex_file.dex_file_location_checksum_,
+                                               /* oat_dex_file */ nullptr,
+                                               verify,
+                                               verify,
+                                               &error_msg));
     if (dex_files.back() == nullptr) {
       LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
                  << " Error: " << error_msg;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 50434ef..a19057a 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -26,6 +26,7 @@
 #include "compiled_method-inl.h"
 #include "compiler.h"
 #include "debug/method_debug_info.h"
+#include "dex_file_loader.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
@@ -745,14 +746,14 @@
       ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
                           &opened_dex_file1->GetHeader(),
                           dex_file1_data->GetHeader().file_size_));
-      ASSERT_EQ(DexFile::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
+      ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
                 opened_dex_file1->GetLocation());
 
       ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
       ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
                           &opened_dex_file2->GetHeader(),
                           dex_file2_data->GetHeader().file_size_));
-      ASSERT_EQ(DexFile::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
+      ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
                 opened_dex_file2->GetLocation());
     }
   }
@@ -794,14 +795,14 @@
       ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
                           &opened_dex_file1->GetHeader(),
                           dex_file1_data->GetHeader().file_size_));
-      ASSERT_EQ(DexFile::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
+      ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
                 opened_dex_file1->GetLocation());
 
       ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
       ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
                           &opened_dex_file2->GetHeader(),
                           dex_file2_data->GetHeader().file_size_));
-      ASSERT_EQ(DexFile::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
+      ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
                 opened_dex_file2->GetLocation());
     }
   }
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 7599d23..3648a3e 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -45,6 +45,7 @@
 #include "android-base/stringprintf.h"
 
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "dex_instruction-inl.h"
 #include "dexdump_cfg.h"
@@ -1825,7 +1826,7 @@
     fputs("Opened '", gOutFile);
     fputs(fileName, gOutFile);
     if (n > 1) {
-      fprintf(gOutFile, ":%s", DexFile::GetMultiDexClassesDexName(i).c_str());
+      fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
     }
     fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
   }
@@ -1882,7 +1883,7 @@
   const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFile::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!DexFileLoader::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
     fputs(error_msg.c_str(), stderr);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 0c944ce..f75eacc 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -39,24 +39,6 @@
   return value;
 }
 
-static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  PositionInfoVector& positions = debug_info->GetPositionInfo();
-  positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
-  return false;
-}
-
-static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  LocalInfoVector& locals = debug_info->GetLocalInfo();
-  const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
-  const char* descriptor = entry.descriptor_ != nullptr ? entry.descriptor_ : "";
-  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
-  locals.push_back(std::unique_ptr<LocalInfo>(
-      new LocalInfo(name, descriptor, signature, entry.start_address_, entry.end_address_,
-                    entry.reg_)));
-}
-
 static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
   const uint8_t* stream = debug_info_stream;
   DecodeUnsignedLeb128(&stream);  // line_start
@@ -694,12 +676,6 @@
     }
     debug_info = code_item->DebugInfo();
   }
-  if (debug_info != nullptr) {
-    bool is_static = (access_flags & kAccStatic) != 0;
-    dex_file.DecodeDebugLocalInfo(
-        disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
-    dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
-  }
   return new MethodItem(access_flags, method_id, code_item);
 }
 
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 5dcc87d..df3484c 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -966,39 +966,6 @@
   DISALLOW_COPY_AND_ASSIGN(CodeItem);
 };
 
-struct PositionInfo {
-  PositionInfo(uint32_t address, uint32_t line) : address_(address), line_(line) { }
-
-  uint32_t address_;
-  uint32_t line_;
-};
-
-using PositionInfoVector = std::vector<std::unique_ptr<PositionInfo>>;
-
-struct LocalInfo {
-  LocalInfo(const char* name,
-            const char* descriptor,
-            const char* signature,
-            uint32_t start_address,
-            uint32_t end_address,
-            uint16_t reg)
-      : name_(name),
-        descriptor_(descriptor),
-        signature_(signature),
-        start_address_(start_address),
-        end_address_(end_address),
-        reg_(reg) { }
-
-  std::string name_;
-  std::string descriptor_;
-  std::string signature_;
-  uint32_t start_address_;
-  uint32_t end_address_;
-  uint16_t reg_;
-};
-
-using LocalInfoVector = std::vector<std::unique_ptr<LocalInfo>>;
-
 class DebugInfoItem : public Item {
  public:
   DebugInfoItem(uint32_t debug_info_size, uint8_t* debug_info)
@@ -1007,16 +974,10 @@
   uint32_t GetDebugInfoSize() const { return debug_info_size_; }
   uint8_t* GetDebugInfo() const { return debug_info_.get(); }
 
-  PositionInfoVector& GetPositionInfo() { return positions_; }
-  LocalInfoVector& GetLocalInfo() { return locals_; }
-
  private:
   uint32_t debug_info_size_;
   std::unique_ptr<uint8_t[]> debug_info_;
 
-  PositionInfoVector positions_;
-  LocalInfoVector locals_;
-
   DISALLOW_COPY_AND_ASSIGN(DebugInfoItem);
 };
 
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index 5458129..18ddc86 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -893,109 +893,24 @@
     }
     return true;
   }
-  if (!VerifyPositionInfo(orig->GetPositionInfo(),
-                          output->GetPositionInfo(),
-                          orig->GetOffset(),
-                          error_msg)) {
+  // TODO: Test for debug equivalence rather than byte array equality.
+  uint32_t orig_size = orig->GetDebugInfoSize();
+  uint32_t output_size = output->GetDebugInfoSize();
+  if (orig_size != output_size) {
+    *error_msg = "DebugInfoSize disagreed.";
     return false;
   }
-  return VerifyLocalInfo(orig->GetLocalInfo(),
-                         output->GetLocalInfo(),
-                         orig->GetOffset(),
-                         error_msg);
-}
-
-bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
-                        dex_ir::PositionInfoVector& output,
-                        uint32_t orig_offset,
-                        std::string* error_msg) {
-  if (orig.size() != output.size()) {
-    *error_msg = StringPrintf(
-        "Mismatched number of positions for debug info at offset %x: %zu vs %zu.",
-        orig_offset,
-        orig.size(),
-        output.size());
+  uint8_t* orig_data = orig->GetDebugInfo();
+  uint8_t* output_data = output->GetDebugInfo();
+  if ((orig_data == nullptr && output_data != nullptr) ||
+      (orig_data != nullptr && output_data == nullptr)) {
+    *error_msg = "DebugInfo null/non-null mismatch.";
     return false;
   }
-  for (size_t i = 0; i < orig.size(); ++i) {
-    if (orig[i]->address_ != output[i]->address_) {
-      *error_msg = StringPrintf(
-          "Mismatched position address for debug info at offset %x: %u vs %u.",
-          orig_offset,
-          orig[i]->address_,
-          output[i]->address_);
-      return false;
-    }
-    if (orig[i]->line_ != output[i]->line_) {
-      *error_msg = StringPrintf("Mismatched position line for debug info at offset %x: %u vs %u.",
-                                orig_offset,
-                                orig[i]->line_,
-                                output[i]->line_);
-      return false;
-    }
-  }
-  return true;
-}
-
-bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
-                     dex_ir::LocalInfoVector& output,
-                     uint32_t orig_offset,
-                     std::string* error_msg) {
-  if (orig.size() != output.size()) {
-    *error_msg = StringPrintf(
-        "Mismatched number of locals for debug info at offset %x: %zu vs %zu.",
-        orig_offset,
-        orig.size(),
-        output.size());
+  if (memcmp(orig_data, output_data, orig_size) != 0) {
+    *error_msg = "DebugInfo bytes mismatch.";
     return false;
   }
-  for (size_t i = 0; i < orig.size(); ++i) {
-    if (orig[i]->name_ != output[i]->name_) {
-      *error_msg = StringPrintf("Mismatched local name for debug info at offset %x: %s vs %s.",
-                                orig_offset,
-                                orig[i]->name_.c_str(),
-                                output[i]->name_.c_str());
-      return false;
-    }
-    if (orig[i]->descriptor_ != output[i]->descriptor_) {
-      *error_msg = StringPrintf(
-          "Mismatched local descriptor for debug info at offset %x: %s vs %s.",
-          orig_offset,
-          orig[i]->descriptor_.c_str(),
-          output[i]->descriptor_.c_str());
-      return false;
-    }
-    if (orig[i]->signature_ != output[i]->signature_) {
-      *error_msg = StringPrintf("Mismatched local signature for debug info at offset %x: %s vs %s.",
-                                orig_offset,
-                                orig[i]->signature_.c_str(),
-                                output[i]->signature_.c_str());
-      return false;
-    }
-    if (orig[i]->start_address_ != output[i]->start_address_) {
-      *error_msg = StringPrintf(
-          "Mismatched local start address for debug info at offset %x: %u vs %u.",
-          orig_offset,
-          orig[i]->start_address_,
-          output[i]->start_address_);
-      return false;
-    }
-    if (orig[i]->end_address_ != output[i]->end_address_) {
-      *error_msg = StringPrintf(
-          "Mismatched local end address for debug info at offset %x: %u vs %u.",
-          orig_offset,
-          orig[i]->end_address_,
-          output[i]->end_address_);
-      return false;
-    }
-    if (orig[i]->reg_ != output[i]->reg_) {
-      *error_msg = StringPrintf("Mismatched local reg for debug info at offset %x: %u vs %u.",
-                                orig_offset,
-                                orig[i]->reg_,
-                                output[i]->reg_);
-      return false;
-    }
-  }
   return true;
 }
 
diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h
index 58c95d6..998939b 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -100,14 +100,6 @@
 bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
                      dex_ir::DebugInfoItem* output,
                      std::string* error_msg);
-bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
-                        dex_ir::PositionInfoVector& output,
-                        uint32_t orig_offset,
-                        std::string* error_msg);
-bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
-                     dex_ir::LocalInfoVector& output,
-                     uint32_t orig_offset,
-                     std::string* error_msg);
 bool VerifyTries(dex_ir::TryItemVector* orig,
                  dex_ir::TryItemVector* output,
                  uint32_t orig_offset,
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 095c960..40449ae 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -35,6 +35,7 @@
 
 #include "dex_file-inl.h"
 #include "dex_file_layout.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "dex_file_verifier.h"
 #include "dex_instruction-inl.h"
@@ -819,37 +820,6 @@
 }
 
 /*
- * Dumps all positions table entries associated with the code.
- */
-void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
-  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
-  if (debug_info == nullptr) {
-    return;
-  }
-  std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
-  for (size_t i = 0; i < positions.size(); ++i) {
-    fprintf(out_file_, "        0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
-  }
-}
-
-/*
- * Dumps all locals table entries associated with the code.
- */
-void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
-  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
-  if (debug_info == nullptr) {
-    return;
-  }
-  std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
-  for (size_t i = 0; i < locals.size(); ++i) {
-    dex_ir::LocalInfo* entry = locals[i].get();
-    fprintf(out_file_, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
-            entry->start_address_, entry->end_address_, entry->reg_,
-            entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
-  }
-}
-
-/*
  * Dumps a single instruction.
  */
 void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
@@ -1092,9 +1062,59 @@
 }
 
 /*
+ * Callback for dumping each positions table entry.
+ */
+static bool DumpPositionsCb(void* context, const DexFile::PositionInfo& entry) {
+  FILE* out_file = reinterpret_cast<FILE*>(context);
+  fprintf(out_file, "        0x%04x line=%d\n", entry.address_, entry.line_);
+  return false;
+}
+
+/*
+ * Callback for dumping locals table entry.
+ */
+static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) {
+  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
+  FILE* out_file = reinterpret_cast<FILE*>(context);
+  fprintf(out_file, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
+          entry.start_address_, entry.end_address_, entry.reg_,
+          entry.name_, entry.descriptor_, signature);
+}
+
+/*
+ * Lookup functions.
+ */
+static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) {
+  dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx);
+  if (string_id == nullptr) {
+    return nullptr;
+  }
+  return string_id->Data();
+}
+
+static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) {
+  dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx);
+  if (type_id == nullptr) {
+    return nullptr;
+  }
+  dex_ir::StringId* string_id = type_id->GetStringId();
+  if (string_id == nullptr) {
+    return nullptr;
+  }
+  return string_id->Data();
+}
+
+
+/*
  * Dumps code of a method.
  */
-void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
+void DexLayout::DumpCode(uint32_t idx,
+                         const dex_ir::CodeItem* code,
+                         uint32_t code_offset,
+                         const char* declaring_class_descriptor,
+                         const char* method_name,
+                         bool is_static,
+                         const dex_ir::ProtoId* proto) {
   fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
   fprintf(out_file_, "      ins           : %d\n", code->InsSize());
   fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
@@ -1110,10 +1130,48 @@
   DumpCatches(code);
 
   // Positions and locals table in the debug info.
+  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
   fprintf(out_file_, "      positions     : \n");
-  DumpPositionInfo(code);
+  if (debug_info != nullptr) {
+    DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
+                                     [this](uint32_t idx) {
+                                       return StringDataByIdx(idx, this->header_->GetCollections());
+                                     },
+                                     DumpPositionsCb,
+                                     out_file_);
+  }
   fprintf(out_file_, "      locals        : \n");
-  DumpLocalInfo(code);
+  if (debug_info != nullptr) {
+    std::vector<const char*> arg_descriptors;
+    const dex_ir::TypeList* parameters = proto->Parameters();
+    if (parameters != nullptr) {
+      const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList();
+      if (parameter_type_vector != nullptr) {
+        for (const dex_ir::TypeId* type_id : *parameter_type_vector) {
+          arg_descriptors.push_back(type_id->GetStringId()->Data());
+        }
+      }
+    }
+    DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(),
+                                  "DexLayout in-memory",
+                                  declaring_class_descriptor,
+                                  arg_descriptors,
+                                  method_name,
+                                  is_static,
+                                  code->RegistersSize(),
+                                  code->InsSize(),
+                                  code->InsnsSize(),
+                                  [this](uint32_t idx) {
+                                    return StringDataByIdx(idx, this->header_->GetCollections());
+                                  },
+                                  [this](uint32_t idx) {
+                                    return
+                                        StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
+                                                            this->header_->GetCollections());
+                                  },
+                                  DumpLocalsCb,
+                                  out_file_);
+  }
 }
 
 /*
@@ -1140,7 +1198,13 @@
       fprintf(out_file_, "      code          : (none)\n");
     } else {
       fprintf(out_file_, "      code          -\n");
-      DumpCode(idx, code, code->GetOffset());
+      DumpCode(idx,
+               code,
+               code->GetOffset(),
+               back_descriptor,
+               name,
+               (flags & kAccStatic) != 0,
+               method_id->Proto());
     }
     if (options_.disassemble_) {
       fputc('\n', out_file_);
@@ -1929,14 +1993,14 @@
   // Verify the output dex file's structure for debug builds.
   if (kIsDebugBuild) {
     std::string location = "memory mapped file for " + dex_file_location;
-    std::unique_ptr<const DexFile> output_dex_file(DexFile::Open(mem_map_->Begin(),
-                                                                 mem_map_->Size(),
-                                                                 location,
-                                                                 header_->Checksum(),
-                                                                 /*oat_dex_file*/ nullptr,
-                                                                 /*verify*/ true,
-                                                                 /*verify_checksum*/ false,
-                                                                 &error_msg));
+    std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
+                                                                       mem_map_->Size(),
+                                                                       location,
+                                                                       header_->Checksum(),
+                                                                       /*oat_dex_file*/ nullptr,
+                                                                       /*verify*/ true,
+                                                                       /*verify_checksum*/ false,
+                                                                       &error_msg));
     DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
   }
   // Do IR-level comparison between input and output. This check ignores potential differences
@@ -1998,7 +2062,7 @@
   const bool verify_checksum = !options_.ignore_bad_checksum_;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
+  if (!DexFileLoader::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
     fputs(error_msg.c_str(), stderr);
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 9f6e8a4..180d9bc 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -96,7 +96,13 @@
   void DumpClass(int idx, char** last_package);
   void DumpClassAnnotations(int idx);
   void DumpClassDef(int idx);
-  void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+  void DumpCode(uint32_t idx,
+                const dex_ir::CodeItem* code,
+                uint32_t code_offset,
+                const char* declaring_class_descriptor,
+                const char* method_name,
+                bool is_static,
+                const dex_ir::ProtoId* proto);
   void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
   void DumpEncodedValue(const dex_ir::EncodedValue* data);
   void DumpFileHeader();
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 336eb5f..f8fa893 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -24,6 +24,7 @@
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "exec_utils.h"
 #include "jit/profile_compilation_info.h"
 #include "utils.h"
@@ -322,11 +323,11 @@
                      const std::string& dex_location) {
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     std::string error_msg;
-    bool result = DexFile::Open(input_dex.c_str(),
-                                input_dex,
-                                false,
-                                &error_msg,
-                                &dex_files);
+    bool result = DexFileLoader::Open(input_dex.c_str(),
+                                      input_dex,
+                                      false,
+                                      &error_msg,
+                                      &dex_files);
 
     ASSERT_TRUE(result) << error_msg;
     ASSERT_GE(dex_files.size(), 1u);
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 6a1e22a..e587052 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "mem_map.h"
 #include "runtime.h"
 
@@ -178,7 +179,7 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!DexFile::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!DexFileLoader::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
     fputs(error_msg.c_str(), stderr);
     fputc('\n', stderr);
     return -1;
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 51a67ca..08d38d5 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -97,6 +97,10 @@
   UsageError("  --android-data=<directory>: optional, the directory which should be used as");
   UsageError("       android-data. By default ANDROID_DATA env variable is used.");
   UsageError("");
+  UsageError("  --oat-fd=number: file descriptor of the oat file which should be analyzed");
+  UsageError("");
+  UsageError("  --vdex-fd=number: file descriptor of the vdex file corresponding to the oat file");
+  UsageError("");
   UsageError("  --downgrade: optional, if the purpose of dexopt is to downgrade the dex file");
   UsageError("       By default, dexopt considers upgrade case.");
   UsageError("");
@@ -167,6 +171,10 @@
         setenv("ANDROID_DATA", new_android_data.c_str(), 1);
       } else if (option.starts_with("--downgrade")) {
         downgrade_ = true;
+      } else if (option.starts_with("--oat-fd")) {
+        oat_fd_ = std::stoi(option.substr(strlen("--oat-fd=")).ToString(), nullptr, 0);
+      } else if (option.starts_with("--vdex-fd")) {
+        vdex_fd_ = std::stoi(option.substr(strlen("--vdex-fd=")).ToString(), nullptr, 0);
       } else { Usage("Unknown argument '%s'", option.data()); }
     }
 
@@ -181,6 +189,12 @@
         Usage("--image unspecified and ANDROID_ROOT not set or image file does not exist.");
       }
     }
+    if (oat_fd_ > 0 && vdex_fd_ < 0) {
+      Usage("A valid --vdex-fd must also be provided with --oat-fd.");
+    }
+    if (oat_fd_ < 0 && vdex_fd_ > 0) {
+      Usage("A valid --oat-fd must also be provided with --vdex-fd.");
+    }
   }
 
   bool CreateRuntime() {
@@ -223,15 +237,26 @@
     }
     std::unique_ptr<Runtime> runtime(Runtime::Current());
 
-    OatFileAssistant oat_file_assistant(dex_file_.c_str(), isa_, /*load_executable*/ false);
+    std::unique_ptr<OatFileAssistant> oat_file_assistant;
+    if (oat_fd_ != -1 && vdex_fd_ != -1) {
+      oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
+                                                              isa_,
+                                                              false /*load_executable*/,
+                                                              vdex_fd_,
+                                                              oat_fd_);
+    } else {
+      oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
+                                                              isa_,
+                                                              false /*load_executable*/);
+    }
     // Always treat elements of the bootclasspath as up-to-date.
     // TODO(calin): this check should be in OatFileAssistant.
-    if (oat_file_assistant.IsInBootClassPath()) {
+    if (oat_file_assistant->IsInBootClassPath()) {
       return kNoDexOptNeeded;
     }
 
     // TODO(calin): Pass the class loader context as an argument to dexoptanalyzer. b/62269291.
-    int dexoptNeeded = oat_file_assistant.GetDexOptNeeded(
+    int dexoptNeeded = oat_file_assistant->GetDexOptNeeded(
         compiler_filter_, assume_profile_changed_, downgrade_);
 
     // Convert OatFileAssitant codes to dexoptanalyzer codes.
@@ -258,6 +283,8 @@
   bool assume_profile_changed_;
   bool downgrade_;
   std::string image_;
+  int oat_fd_ = -1;
+  int vdex_fd_ = -1;
 };
 
 static int dexoptAnalyze(int argc, char** argv) {
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 32dd69e..0282fbc 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -842,6 +842,12 @@
 
     bool operator()(art::ObjPtr<art::mirror::Class> klass)
         OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      if (!klass->IsLoaded()) {
+        // Skip classes that aren't loaded since they might not have fully allocated and initialized
+        // their methods. Furthemore since the jvmti-plugin must have been loaded by this point
+        // these methods will definitately be using debuggable code.
+        return true;
+      }
       for (auto& m : klass->GetMethods(art::kRuntimePointerSize)) {
         const void* code = m.GetEntryPointFromQuickCompiledCode();
         if (m.IsNative() || m.IsProxyMethod()) {
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 5bfa5ca..c498869 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -30,6 +30,7 @@
  */
 
 #include "fixed_up_dex_file.h"
+#include "dex_file_loader.h"
 #include "dex_file-inl.h"
 
 // Runtime includes.
@@ -68,7 +69,7 @@
   data.resize(original.Size());
   memcpy(data.data(), original.Begin(), original.Size());
   std::string error;
-  std::unique_ptr<const art::DexFile> new_dex_file(art::DexFile::Open(
+  std::unique_ptr<const art::DexFile> new_dex_file(art::DexFileLoader::Open(
       data.data(),
       data.size(),
       /*location*/"Unquickening_dexfile.dex",
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index daf4a8b..5f29416 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -43,6 +43,7 @@
 #include "class_table-inl.h"
 #include "common_throws.h"
 #include "dex_file_annotations.h"
+#include "dex_file_loader.h"
 #include "events-inl.h"
 #include "fixed_up_dex_file.h"
 #include "gc/heap-visit-objects-inl.h"
@@ -106,12 +107,12 @@
   }
   uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
   std::string map_name = map->GetName();
-  std::unique_ptr<const art::DexFile> dex_file(art::DexFile::Open(map_name,
-                                                                  checksum,
-                                                                  std::move(map),
-                                                                  /*verify*/true,
-                                                                  /*verify_checksum*/true,
-                                                                  &error_msg));
+  std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map_name,
+                                                                        checksum,
+                                                                        std::move(map),
+                                                                        /*verify*/true,
+                                                                        /*verify_checksum*/true,
+                                                                        &error_msg));
   if (dex_file.get() == nullptr) {
     LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg;
     art::ThrowClassFormatError(nullptr,
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index f05977a..50402a0 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -572,8 +572,9 @@
       return;
     }
     art::ArtMethod* method = visitor.GetMethod();
-    if (method->IsNative()) {
-      // TODO We really should support get/set for non-shadow frames.
+    // Native and 'art' proxy methods don't have registers.
+    if (method->IsNative() || method->IsProxyMethod()) {
+      // TODO It might be useful to fake up support for get at least on proxy frames.
       result_ = ERR(OPAQUE_FRAME);
       return;
     } else if (method->GetCodeItem()->registers_size_ <= slot_) {
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 98fad80..53abfbc 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -44,6 +44,7 @@
 #include "class_linker-inl.h"
 #include "debugger.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "events-inl.h"
 #include "gc/allocation_listener.h"
@@ -425,12 +426,12 @@
     return ERR(INVALID_CLASS_FORMAT);
   }
   uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
-  std::unique_ptr<const art::DexFile> dex_file(art::DexFile::Open(map->GetName(),
-                                                                  checksum,
-                                                                  std::move(map),
-                                                                  /*verify*/true,
-                                                                  /*verify_checksum*/true,
-                                                                  error_msg_));
+  std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map->GetName(),
+                                                                        checksum,
+                                                                        std::move(map),
+                                                                        /*verify*/true,
+                                                                        /*verify_checksum*/true,
+                                                                        error_msg_));
   if (dex_file.get() == nullptr) {
     os << "Unable to load modified dex file for " << def.GetName() << ": " << *error_msg_;
     *error_msg_ = os.str();
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index 25bc5d6..bafc855 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -39,6 +39,7 @@
 #include "base/macros.h"
 #include "class_linker.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
@@ -226,7 +227,7 @@
 
   std::string error_msg;
   std::vector<std::unique_ptr<const art::DexFile>> dex_files;
-  if (!art::DexFile::Open(segment, segment, true, &error_msg, &dex_files)) {
+  if (!art::DexFileLoader::Open(segment, segment, true, &error_msg, &dex_files)) {
     LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg;
     return ERR(ILLEGAL_ARGUMENT);
   }
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index d4cc42a..e0c1399 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -789,7 +789,7 @@
   }
 
   *method_ptr = art::jni::EncodeArtMethod(closure.method);
-  if (closure.method->IsNative()) {
+  if (closure.method->IsNative() || closure.method->IsProxyMethod()) {
     *location_ptr = -1;
   } else {
     if (closure.dex_pc == art::dex::kDexNoIndex) {
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 73724b2..642d26e 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -35,7 +35,7 @@
 class ProfileAssistantTest : public CommonRuntimeTest {
  public:
   void PostRuntimeCreate() OVERRIDE {
-    arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
+    allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
   }
 
  protected:
@@ -108,7 +108,7 @@
   // Creates an inline cache which will be destructed at the end of the test.
   ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
     used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
-        std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
+        std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
     return used_inline_caches.back().get();
   }
 
@@ -122,13 +122,13 @@
 
     // Monomorphic
     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.AddClass(0, dex::TypeIndex(0));
       ic_map->Put(dex_pc, dex_pc_data);
     }
     // Polymorphic
     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.AddClass(0, dex::TypeIndex(0));
       dex_pc_data.AddClass(1, dex::TypeIndex(1));
 
@@ -136,13 +136,13 @@
     }
     // Megamorphic
     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.SetIsMegamorphic();
       ic_map->Put(dex_pc, dex_pc_data);
     }
     // Missing types
     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.SetIsMissingTypes();
       ic_map->Put(dex_pc, dex_pc_data);
     }
@@ -375,7 +375,7 @@
     return ProcessProfiles(profile_fds, reference_profile_fd);
   }
 
-  std::unique_ptr<ArenaAllocator> arena_;
+  std::unique_ptr<ArenaAllocator> allocator_;
 
   // Cache of inline caches generated during tests.
   // This makes it easier to pass data between different utilities and ensure that
diff --git a/profman/profman.cc b/profman/profman.cc
index 9b4f579..8ccf7b4 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -39,6 +39,7 @@
 #include "boot_image_profile.h"
 #include "bytecode_utils.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "jit/profile_compilation_info.h"
 #include "profile_assistant.h"
@@ -328,21 +329,21 @@
       std::string error_msg;
       std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
       if (use_apk_fd_list) {
-        if (DexFile::OpenZip(apks_fd_[i],
-                             dex_locations_[i],
-                             kVerifyChecksum,
-                             &error_msg,
-                             &dex_files_for_location)) {
+        if (DexFileLoader::OpenZip(apks_fd_[i],
+                                   dex_locations_[i],
+                                   kVerifyChecksum,
+                                   &error_msg,
+                                   &dex_files_for_location)) {
         } else {
           LOG(WARNING) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
           continue;
         }
       } else {
-        if (DexFile::Open(apk_files_[i].c_str(),
-                          dex_locations_[i],
-                          kVerifyChecksum,
-                          &error_msg,
-                          &dex_files_for_location)) {
+        if (DexFileLoader::Open(apk_files_[i].c_str(),
+                                dex_locations_[i],
+                                kVerifyChecksum,
+                                &error_msg,
+                                &dex_files_for_location)) {
         } else {
           LOG(WARNING) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
           continue;
@@ -795,7 +796,7 @@
       const DexFile* dex_file = class_ref.dex_file;
       const auto& dex_resolved_classes = resolved_class_set.emplace(
             dex_file->GetLocation(),
-            dex_file->GetBaseLocation(),
+            DexFileLoader::GetBaseLocation(dex_file->GetLocation()),
             dex_file->GetLocationChecksum(),
             dex_file->NumMethodIds());
       dex_resolved_classes.first->AddClass(class_ref.TypeIndex());
diff --git a/runtime/Android.bp b/runtime/Android.bp
index ea776e7..ddfbed4 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -55,6 +55,7 @@
         "compiler_filter.cc",
         "debugger.cc",
         "dex_file.cc",
+        "dex_file_loader.cc",
         "dex_file_annotations.cc",
         "dex_file_layout.cc",
         "dex_file_tracking_registrar.cc",
@@ -206,6 +207,7 @@
         "signal_catcher.cc",
         "stack.cc",
         "stack_map.cc",
+        "standard_dex_file.cc",
         "thread.cc",
         "thread_list.cc",
         "thread_pool.cc",
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index c48e30f..2e35f8a 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -72,6 +72,7 @@
   "InductionVar ",
   "BCE          ",
   "DCE          ",
+  "LSA          ",
   "LSE          ",
   "CFRE         ",
   "LICM         ",
@@ -296,7 +297,7 @@
 
 void ArenaPool::ReclaimMemory() {
   while (free_arenas_ != nullptr) {
-    auto* arena = free_arenas_;
+    Arena* arena = free_arenas_;
     free_arenas_ = free_arenas_->next_;
     delete arena;
   }
@@ -330,7 +331,7 @@
     ScopedTrace trace(__PRETTY_FUNCTION__);
     // Doesn't work for malloc.
     MutexLock lock(Thread::Current(), lock_);
-    for (auto* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
+    for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
       arena->Release();
     }
   }
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
index 212edfb..a327cb0 100644
--- a/runtime/base/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -79,6 +79,7 @@
   kArenaAllocInductionVarAnalysis,
   kArenaAllocBoundsCheckElimination,
   kArenaAllocDCE,
+  kArenaAllocLSA,
   kArenaAllocLSE,
   kArenaAllocCFRE,
   kArenaAllocLICM,
diff --git a/runtime/base/arena_allocator_test.cc b/runtime/base/arena_allocator_test.cc
index 6bf56c8..68e26af 100644
--- a/runtime/base/arena_allocator_test.cc
+++ b/runtime/base/arena_allocator_test.cc
@@ -34,8 +34,8 @@
 
 TEST_F(ArenaAllocatorTest, Test) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  ArenaBitVector bv(&arena, 10, true);
+  ArenaAllocator allocator(&pool);
+  ArenaBitVector bv(&allocator, 10, true);
   bv.SetBit(5);
   EXPECT_EQ(1U, bv.GetStorageSize());
   bv.SetBit(35);
@@ -50,14 +50,14 @@
   uint32_t* small_array;
   {
     // Allocate a small array from an arena and release it.
-    ArenaAllocator arena(&pool);
-    small_array = arena.AllocArray<uint32_t>(kSmallArraySize);
+    ArenaAllocator allocator(&pool);
+    small_array = allocator.AllocArray<uint32_t>(kSmallArraySize);
     ASSERT_EQ(0u, small_array[kSmallArraySize - 1u]);
   }
   {
     // Reuse the previous arena and allocate more than previous allocation including red zone.
-    ArenaAllocator arena(&pool);
-    uint32_t* large_array = arena.AllocArray<uint32_t>(kLargeArraySize);
+    ArenaAllocator allocator(&pool);
+    uint32_t* large_array = allocator.AllocArray<uint32_t>(kLargeArraySize);
     ASSERT_EQ(0u, large_array[kLargeArraySize - 1u]);
     // Verify that the allocation was made on the same arena.
     ASSERT_EQ(small_array, large_array);
@@ -72,70 +72,72 @@
 
   {
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
     // Note: Leaving some space for memory tool red zones.
-    void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 8);
-    void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 2 / 8);
+    void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 8);
+    void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 2 / 8);
     ASSERT_NE(alloc1, alloc2);
-    ASSERT_EQ(1u, NumberOfArenas(&arena));
+    ASSERT_EQ(1u, NumberOfArenas(&allocator));
   }
   {
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
-    void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
-    void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 11 / 16);
+    ArenaAllocator allocator(&pool);
+    void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
+    void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 11 / 16);
     ASSERT_NE(alloc1, alloc2);
-    ASSERT_EQ(2u, NumberOfArenas(&arena));
-    void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 7 / 16);
+    ASSERT_EQ(2u, NumberOfArenas(&allocator));
+    void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 7 / 16);
     ASSERT_NE(alloc1, alloc3);
     ASSERT_NE(alloc2, alloc3);
-    ASSERT_EQ(3u, NumberOfArenas(&arena));
+    ASSERT_EQ(3u, NumberOfArenas(&allocator));
   }
   {
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
-    void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
-    void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
+    ArenaAllocator allocator(&pool);
+    void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
+    void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
     ASSERT_NE(alloc1, alloc2);
-    ASSERT_EQ(2u, NumberOfArenas(&arena));
+    ASSERT_EQ(2u, NumberOfArenas(&allocator));
     // Note: Leaving some space for memory tool red zones.
-    void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
+    void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
     ASSERT_NE(alloc1, alloc3);
     ASSERT_NE(alloc2, alloc3);
-    ASSERT_EQ(2u, NumberOfArenas(&arena));
+    ASSERT_EQ(2u, NumberOfArenas(&allocator));
   }
   {
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
-    void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
-    void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
+    ArenaAllocator allocator(&pool);
+    void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
+    void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
     ASSERT_NE(alloc1, alloc2);
-    ASSERT_EQ(2u, NumberOfArenas(&arena));
+    ASSERT_EQ(2u, NumberOfArenas(&allocator));
     // Note: Leaving some space for memory tool red zones.
-    void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
+    void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
     ASSERT_NE(alloc1, alloc3);
     ASSERT_NE(alloc2, alloc3);
-    ASSERT_EQ(2u, NumberOfArenas(&arena));
+    ASSERT_EQ(2u, NumberOfArenas(&allocator));
   }
   {
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
     // Note: Leaving some space for memory tool red zones.
     for (size_t i = 0; i != 15; ++i) {
-      arena.Alloc(arena_allocator::kArenaDefaultSize * 1 / 16);    // Allocate 15 times from the same arena.
-      ASSERT_EQ(i + 1u, NumberOfArenas(&arena));
-      arena.Alloc(arena_allocator::kArenaDefaultSize * 17 / 16);   // Allocate a separate arena.
-      ASSERT_EQ(i + 2u, NumberOfArenas(&arena));
+      // Allocate 15 times from the same arena.
+      allocator.Alloc(arena_allocator::kArenaDefaultSize * 1 / 16);
+      ASSERT_EQ(i + 1u, NumberOfArenas(&allocator));
+      // Allocate a separate arena.
+      allocator.Alloc(arena_allocator::kArenaDefaultSize * 17 / 16);
+      ASSERT_EQ(i + 2u, NumberOfArenas(&allocator));
     }
   }
 }
 
 TEST_F(ArenaAllocatorTest, AllocAlignment) {
   ArenaPool pool;
-  ArenaAllocator arena(&pool);
+  ArenaAllocator allocator(&pool);
   for (size_t iterations = 0; iterations <= 10; ++iterations) {
     for (size_t size = 1; size <= ArenaAllocator::kAlignment + 1; ++size) {
-      void* allocation = arena.Alloc(size);
+      void* allocation = allocator.Alloc(size);
       EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(allocation))
           << reinterpret_cast<uintptr_t>(allocation);
     }
@@ -152,52 +154,52 @@
   {
     // Case 1: small aligned allocation, aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = ArenaAllocator::kAlignment * 3;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_EQ(original_allocation, realloc_allocation);
   }
 
   {
     // Case 2: small aligned allocation, non-aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_EQ(original_allocation, realloc_allocation);
   }
 
   {
     // Case 3: small non-aligned allocation, aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = ArenaAllocator::kAlignment * 4;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_EQ(original_allocation, realloc_allocation);
   }
 
   {
     // Case 4: small non-aligned allocation, aligned non-extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = ArenaAllocator::kAlignment * 3;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_EQ(original_allocation, realloc_allocation);
   }
 
@@ -207,31 +209,31 @@
   {
     // Case 5: large allocation, aligned extend into next arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = arena_allocator::kArenaDefaultSize -
         ArenaAllocator::kAlignment * 5;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_NE(original_allocation, realloc_allocation);
   }
 
   {
     // Case 6: large allocation, non-aligned extend into next arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = arena_allocator::kArenaDefaultSize -
         ArenaAllocator::kAlignment * 4 -
         ArenaAllocator::kAlignment / 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
 
     const size_t new_size = arena_allocator::kArenaDefaultSize +
         ArenaAllocator::kAlignment * 2 +
         ArenaAllocator::kAlignment / 2;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_NE(original_allocation, realloc_allocation);
   }
 }
@@ -240,68 +242,68 @@
   {
     // Case 1: small aligned allocation, aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = ArenaAllocator::kAlignment * 3;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 
   {
     // Case 2: small aligned allocation, non-aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 
   {
     // Case 3: small non-aligned allocation, aligned extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = ArenaAllocator::kAlignment * 4;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 
   {
     // Case 4: small non-aligned allocation, aligned non-extend inside arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2);
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = ArenaAllocator::kAlignment * 3;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 
@@ -311,39 +313,39 @@
   {
     // Case 5: large allocation, aligned extend into next arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = arena_allocator::kArenaDefaultSize -
         ArenaAllocator::kAlignment * 5;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 
   {
     // Case 6: large allocation, non-aligned extend into next arena.
     ArenaPool pool;
-    ArenaAllocator arena(&pool);
+    ArenaAllocator allocator(&pool);
 
     const size_t original_size = arena_allocator::kArenaDefaultSize -
         ArenaAllocator::kAlignment * 4 -
         ArenaAllocator::kAlignment / 2;
-    void* original_allocation = arena.Alloc(original_size);
+    void* original_allocation = allocator.Alloc(original_size);
     ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
 
     const size_t new_size = arena_allocator::kArenaDefaultSize +
         ArenaAllocator::kAlignment * 2 +
         ArenaAllocator::kAlignment / 2;
-    void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
+    void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
 
-    void* after_alloc = arena.Alloc(1);
+    void* after_alloc = allocator.Alloc(1);
     EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc));
   }
 }
diff --git a/runtime/base/arena_bit_vector.cc b/runtime/base/arena_bit_vector.cc
index 5f8f5d2..1542e9d 100644
--- a/runtime/base/arena_bit_vector.cc
+++ b/runtime/base/arena_bit_vector.cc
@@ -52,9 +52,9 @@
 template <typename ArenaAlloc>
 class ArenaBitVectorAllocator FINAL : public Allocator, private ArenaBitVectorAllocatorKind {
  public:
-  static ArenaBitVectorAllocator* Create(ArenaAlloc* arena, ArenaAllocKind kind) {
-    void* storage = arena->template Alloc<ArenaBitVectorAllocator>(kind);
-    return new (storage) ArenaBitVectorAllocator(arena, kind);
+  static ArenaBitVectorAllocator* Create(ArenaAlloc* allocator, ArenaAllocKind kind) {
+    void* storage = allocator->template Alloc<ArenaBitVectorAllocator>(kind);
+    return new (storage) ArenaBitVectorAllocator(allocator, kind);
   }
 
   ~ArenaBitVectorAllocator() {
@@ -63,36 +63,36 @@
   }
 
   virtual void* Alloc(size_t size) {
-    return arena_->Alloc(size, this->Kind());
+    return allocator_->Alloc(size, this->Kind());
   }
 
   virtual void Free(void*) {}  // Nop.
 
  private:
-  ArenaBitVectorAllocator(ArenaAlloc* arena, ArenaAllocKind kind)
-      : ArenaBitVectorAllocatorKind(kind), arena_(arena) { }
+  ArenaBitVectorAllocator(ArenaAlloc* allocator, ArenaAllocKind kind)
+      : ArenaBitVectorAllocatorKind(kind), allocator_(allocator) { }
 
-  ArenaAlloc* const arena_;
+  ArenaAlloc* const allocator_;
 
   DISALLOW_COPY_AND_ASSIGN(ArenaBitVectorAllocator);
 };
 
-ArenaBitVector::ArenaBitVector(ArenaAllocator* arena,
+ArenaBitVector::ArenaBitVector(ArenaAllocator* allocator,
                                unsigned int start_bits,
                                bool expandable,
                                ArenaAllocKind kind)
   :  BitVector(start_bits,
                expandable,
-               ArenaBitVectorAllocator<ArenaAllocator>::Create(arena, kind)) {
+               ArenaBitVectorAllocator<ArenaAllocator>::Create(allocator, kind)) {
 }
 
-ArenaBitVector::ArenaBitVector(ScopedArenaAllocator* arena,
+ArenaBitVector::ArenaBitVector(ScopedArenaAllocator* allocator,
                                unsigned int start_bits,
                                bool expandable,
                                ArenaAllocKind kind)
   :  BitVector(start_bits,
                expandable,
-               ArenaBitVectorAllocator<ScopedArenaAllocator>::Create(arena, kind)) {
+               ArenaBitVectorAllocator<ScopedArenaAllocator>::Create(allocator, kind)) {
 }
 
 }  // namespace art
diff --git a/runtime/base/arena_bit_vector.h b/runtime/base/arena_bit_vector.h
index d86d622..ca1d5b1 100644
--- a/runtime/base/arena_bit_vector.h
+++ b/runtime/base/arena_bit_vector.h
@@ -31,19 +31,19 @@
 class ArenaBitVector : public BitVector, public ArenaObject<kArenaAllocGrowableBitMap> {
  public:
   template <typename Allocator>
-  static ArenaBitVector* Create(Allocator* arena,
+  static ArenaBitVector* Create(Allocator* allocator,
                                 uint32_t start_bits,
                                 bool expandable,
                                 ArenaAllocKind kind = kArenaAllocGrowableBitMap) {
-    void* storage = arena->template Alloc<ArenaBitVector>(kind);
-    return new (storage) ArenaBitVector(arena, start_bits, expandable, kind);
+    void* storage = allocator->template Alloc<ArenaBitVector>(kind);
+    return new (storage) ArenaBitVector(allocator, start_bits, expandable, kind);
   }
 
-  ArenaBitVector(ArenaAllocator* arena,
+  ArenaBitVector(ArenaAllocator* allocator,
                  uint32_t start_bits,
                  bool expandable,
                  ArenaAllocKind kind = kArenaAllocGrowableBitMap);
-  ArenaBitVector(ScopedArenaAllocator* arena,
+  ArenaBitVector(ScopedArenaAllocator* allocator,
                  uint32_t start_bits,
                  bool expandable,
                  ArenaAllocKind kind = kArenaAllocGrowableBitMap);
diff --git a/runtime/base/file_magic.cc b/runtime/base/file_magic.cc
index 568a7ae..30b4f05 100644
--- a/runtime/base/file_magic.cc
+++ b/runtime/base/file_magic.cc
@@ -55,8 +55,4 @@
           ('K' == ((magic >> 8) & 0xff)));
 }
 
-bool IsDexMagic(uint32_t magic) {
-  return DexFile::IsMagicValid(reinterpret_cast<const uint8_t*>(&magic));
-}
-
 }  // namespace art
diff --git a/runtime/base/file_magic.h b/runtime/base/file_magic.h
index 4b5d2f5..1c9effd 100644
--- a/runtime/base/file_magic.h
+++ b/runtime/base/file_magic.h
@@ -29,7 +29,6 @@
 
 // Check whether the given magic matches a known file type.
 bool IsZipMagic(uint32_t magic);
-bool IsDexMagic(uint32_t magic);
 
 }  // namespace art
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0cc2622..fe91272 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -51,6 +51,7 @@
 #include "compiler_callbacks.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "experimental_flags.h"
@@ -8714,10 +8715,11 @@
       const DexFile& dex_file = klass->GetDexFile();
       if (&dex_file != last_dex_file_) {
         last_dex_file_ = &dex_file;
-        DexCacheResolvedClasses resolved_classes(dex_file.GetLocation(),
-                                                 dex_file.GetBaseLocation(),
-                                                 dex_file.GetLocationChecksum(),
-                                                 dex_file.NumMethodIds());
+        DexCacheResolvedClasses resolved_classes(
+            dex_file.GetLocation(),
+            DexFileLoader::GetBaseLocation(dex_file.GetLocation()),
+            dex_file.GetLocationChecksum(),
+            dex_file.NumMethodIds());
         last_resolved_classes_ = result_->find(resolved_classes);
         if (last_resolved_classes_ == result_->end()) {
           last_resolved_classes_ = result_->insert(resolved_classes).first;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index f887b8e..6ea1fbe 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -26,7 +26,6 @@
 #include "base/enums.h"
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
-#include "dex_file.h"
 #include "dex_file_types.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "experimental_flags.h"
@@ -50,6 +49,7 @@
 #include "mirror/stack_trace_element.h"
 #include "mirror/string-inl.h"
 #include "scoped_thread_state_change-inl.h"
+#include "standard_dex_file.h"
 #include "thread-current-inl.h"
 
 namespace art {
@@ -1462,11 +1462,11 @@
   dex_cache->SetLocation(location.Get());
   const DexFile* old_dex_file = dex_cache->GetDexFile();
 
-  std::unique_ptr<DexFile> dex_file(new DexFile(old_dex_file->Begin(),
-                                                old_dex_file->Size(),
-                                                location->ToModifiedUtf8(),
-                                                0u,
-                                                nullptr));
+  std::unique_ptr<DexFile> dex_file(new StandardDexFile(old_dex_file->Begin(),
+                                                        old_dex_file->Size(),
+                                                        location->ToModifiedUtf8(),
+                                                        0u,
+                                                        nullptr));
   {
     WriterMutexLock mu(soa.Self(), *Locks::dex_lock_);
     // Check that inserting with a UTF16 name works.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 2282da0..167533d 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -25,6 +25,7 @@
 #include "class_linker.h"
 #include "class_loader_utils.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
 #include "oat_file_assistant.h"
@@ -227,11 +228,11 @@
       std::string error_msg;
       // When opening the dex files from the context we expect their checksum to match their
       // contents. So pass true to verify_checksum.
-      if (!DexFile::Open(location.c_str(),
-                         location.c_str(),
-                         /*verify_checksum*/ true,
-                         &error_msg,
-                         &info.opened_dex_files)) {
+      if (!DexFileLoader::Open(location.c_str(),
+                               location.c_str(),
+                               /*verify_checksum*/ true,
+                               &error_msg,
+                               &info.opened_dex_files)) {
         // If we fail to open the dex file because it's been stripped, try to open the dex file
         // from its corresponding oat file.
         // This could happen when we need to recompile a pre-build whose dex code has been stripped.
@@ -282,7 +283,7 @@
 
   std::set<std::string> canonical_locations;
   for (const std::string& location : locations) {
-    canonical_locations.insert(DexFile::GetDexCanonicalLocation(location.c_str()));
+    canonical_locations.insert(DexFileLoader::GetDexCanonicalLocation(location.c_str()));
   }
   bool removed_locations = false;
   for (ClassLoaderInfo& info : class_loader_chain_) {
@@ -292,7 +293,7 @@
         info.classpath.end(),
         [canonical_locations](const std::string& location) {
             return ContainsElement(canonical_locations,
-                                   DexFile::GetDexCanonicalLocation(location.c_str()));
+                                   DexFileLoader::GetDexCanonicalLocation(location.c_str()));
         });
     info.classpath.erase(kept_it, info.classpath.end());
     if (initial_size != info.classpath.size()) {
@@ -340,7 +341,8 @@
       if (for_dex2oat) {
         // dex2oat only needs the base location. It cannot accept multidex locations.
         // So ensure we only add each file once.
-        bool new_insert = seen_locations.insert(dex_file->GetBaseLocation()).second;
+        bool new_insert = seen_locations.insert(
+            DexFileLoader::GetBaseLocation(dex_file->GetLocation())).second;
         if (!new_insert) {
           continue;
         }
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index ae3dcec..be6acde 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -100,12 +100,13 @@
             info.opened_dex_files[cur_open_dex_index++];
       std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k];
 
-      std::string expected_location = expected_dex_file->GetBaseLocation();
+      std::string expected_location =
+          DexFileLoader::GetBaseLocation(expected_dex_file->GetLocation());
       UniqueCPtr<const char[]> expected_real_location(
           realpath(expected_location.c_str(), nullptr));
       ASSERT_TRUE(expected_real_location != nullptr) << expected_location;
       expected_location.assign(expected_real_location.get());
-      expected_location += DexFile::GetMultiDexSuffix(expected_dex_file->GetLocation());
+      expected_location += DexFileLoader::GetMultiDexSuffix(expected_dex_file->GetLocation());
 
       ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
       ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 29b376a..0c2e490 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -34,6 +34,7 @@
 #include "class_linker.h"
 #include "compiler_callbacks.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "gc/heap.h"
 #include "gc_root-inl.h"
 #include "gtest/gtest.h"
@@ -372,7 +373,7 @@
   std::string error_msg;
   MemMap::Init();
   static constexpr bool kVerifyChecksum = true;
-  if (!DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files)) {
     LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
     UNREACHABLE();
   } else {
@@ -571,7 +572,7 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  bool success = DexFile::Open(
+  bool success = DexFileLoader::Open(
       filename.c_str(), filename.c_str(), kVerifyChecksum, &error_msg, &dex_files);
   CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
   for (auto& dex_file : dex_files) {
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 93daa45..a9bb954 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -26,6 +26,7 @@
 #include "base/stl_util.h"
 #include "common_runtime_test.h"
 #include "compiler_callbacks.h"
+#include "dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
@@ -71,7 +72,8 @@
       << "Expected dex file to be at: " << GetDexSrc1();
     ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
       << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
-    ASSERT_FALSE(DexFile::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
+    ASSERT_FALSE(
+        DexFileLoader::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
       << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
     ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
       << "Expected dex file to be at: " << GetDexSrc2();
@@ -80,13 +82,19 @@
     // GetMultiDexSrc1, but a different secondary dex checksum.
     static constexpr bool kVerifyChecksum = true;
     std::vector<std::unique_ptr<const DexFile>> multi1;
-    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
-          GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
+    ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc1().c_str(),
+                                    GetMultiDexSrc1().c_str(),
+                                    kVerifyChecksum,
+                                    &error_msg,
+                                    &multi1)) << error_msg;
     ASSERT_GT(multi1.size(), 1u);
 
     std::vector<std::unique_ptr<const DexFile>> multi2;
-    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
-          GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
+    ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc2().c_str(),
+                                    GetMultiDexSrc2().c_str(),
+                                    kVerifyChecksum,
+                                    &error_msg,
+                                    &multi2)) << error_msg;
     ASSERT_GT(multi2.size(), 1u);
 
     ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 1b7c318..5dfbd9b 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_DEX_FILE_INL_H_
 
 #include "base/bit_utils.h"
+#include "base/casts.h"
 #include "base/logging.h"
 #include "base/stringpiece.h"
 #include "dex_file.h"
@@ -220,6 +221,280 @@
   }
 }
 
+template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
+bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
+                                   const std::string& location,
+                                   const char* declaring_class_descriptor,
+                                   const std::vector<const char*>& arg_descriptors,
+                                   const std::string& method_name,
+                                   bool is_static,
+                                   uint16_t registers_size,
+                                   uint16_t ins_size,
+                                   uint16_t insns_size_in_code_units,
+                                   IndexToStringData index_to_string_data,
+                                   TypeIndexToStringData type_index_to_string_data,
+                                   NewLocalCallback new_local_callback,
+                                   void* context) {
+  if (stream == nullptr) {
+    return false;
+  }
+  std::vector<LocalInfo> local_in_reg(registers_size);
+
+  uint16_t arg_reg = registers_size - ins_size;
+  if (!is_static) {
+    const char* descriptor = declaring_class_descriptor;
+    local_in_reg[arg_reg].name_ = "this";
+    local_in_reg[arg_reg].descriptor_ = descriptor;
+    local_in_reg[arg_reg].signature_ = nullptr;
+    local_in_reg[arg_reg].start_address_ = 0;
+    local_in_reg[arg_reg].reg_ = arg_reg;
+    local_in_reg[arg_reg].is_live_ = true;
+    arg_reg++;
+  }
+
+  DecodeUnsignedLeb128(&stream);  // Line.
+  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+  uint32_t i;
+  if (parameters_size != arg_descriptors.size()) {
+    LOG(ERROR) << "invalid stream - problem with parameter iterator in " << location
+               << " for method " << method_name;
+    return false;
+  }
+  for (i = 0; i < parameters_size && i < arg_descriptors.size(); ++i) {
+    if (arg_reg >= registers_size) {
+      LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
+                 << " >= " << registers_size << ") in " << location;
+      return false;
+    }
+    uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
+    const char* descriptor = arg_descriptors[i];
+    local_in_reg[arg_reg].name_ = index_to_string_data(name_idx);
+    local_in_reg[arg_reg].descriptor_ = descriptor;
+    local_in_reg[arg_reg].signature_ = nullptr;
+    local_in_reg[arg_reg].start_address_ = 0;
+    local_in_reg[arg_reg].reg_ = arg_reg;
+    local_in_reg[arg_reg].is_live_ = true;
+    switch (*descriptor) {
+      case 'D':
+      case 'J':
+        arg_reg += 2;
+        break;
+      default:
+        arg_reg += 1;
+        break;
+    }
+  }
+
+  uint32_t address = 0;
+  for (;;)  {
+    uint8_t opcode = *stream++;
+    switch (opcode) {
+      case DBG_END_SEQUENCE:
+        // Emit all variables which are still alive at the end of the method.
+        for (uint16_t reg = 0; reg < registers_size; reg++) {
+          if (local_in_reg[reg].is_live_) {
+            local_in_reg[reg].end_address_ = insns_size_in_code_units;
+            new_local_callback(context, local_in_reg[reg]);
+          }
+        }
+        return true;
+      case DBG_ADVANCE_PC:
+        address += DecodeUnsignedLeb128(&stream);
+        break;
+      case DBG_ADVANCE_LINE:
+        DecodeSignedLeb128(&stream);  // Line.
+        break;
+      case DBG_START_LOCAL:
+      case DBG_START_LOCAL_EXTENDED: {
+        uint16_t reg = DecodeUnsignedLeb128(&stream);
+        if (reg >= registers_size) {
+          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
+                     << registers_size << ") in " << location;
+          return false;
+        }
+
+        uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
+        uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
+        uint32_t signature_idx = dex::kDexNoIndex;
+        if (opcode == DBG_START_LOCAL_EXTENDED) {
+          signature_idx = DecodeUnsignedLeb128P1(&stream);
+        }
+
+        // Emit what was previously there, if anything
+        if (local_in_reg[reg].is_live_) {
+          local_in_reg[reg].end_address_ = address;
+          new_local_callback(context, local_in_reg[reg]);
+        }
+
+        local_in_reg[reg].name_ = index_to_string_data(name_idx);
+        local_in_reg[reg].descriptor_ = type_index_to_string_data(descriptor_idx);;
+        local_in_reg[reg].signature_ = index_to_string_data(signature_idx);
+        local_in_reg[reg].start_address_ = address;
+        local_in_reg[reg].reg_ = reg;
+        local_in_reg[reg].is_live_ = true;
+        break;
+      }
+      case DBG_END_LOCAL: {
+        uint16_t reg = DecodeUnsignedLeb128(&stream);
+        if (reg >= registers_size) {
+          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
+                     << registers_size << ") in " << location;
+          return false;
+        }
+        // If the register is live, close it properly. Otherwise, closing an already
+        // closed register is sloppy, but harmless if no further action is taken.
+        if (local_in_reg[reg].is_live_) {
+          local_in_reg[reg].end_address_ = address;
+          new_local_callback(context, local_in_reg[reg]);
+          local_in_reg[reg].is_live_ = false;
+        }
+        break;
+      }
+      case DBG_RESTART_LOCAL: {
+        uint16_t reg = DecodeUnsignedLeb128(&stream);
+        if (reg >= registers_size) {
+          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
+                     << registers_size << ") in " << location;
+          return false;
+        }
+        // If the register is live, the "restart" is superfluous,
+        // and we don't want to mess with the existing start address.
+        if (!local_in_reg[reg].is_live_) {
+          local_in_reg[reg].start_address_ = address;
+          local_in_reg[reg].is_live_ = true;
+        }
+        break;
+      }
+      case DBG_SET_PROLOGUE_END:
+      case DBG_SET_EPILOGUE_BEGIN:
+        break;
+      case DBG_SET_FILE:
+        DecodeUnsignedLeb128P1(&stream);  // name.
+        break;
+      default:
+        address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE;
+        break;
+    }
+  }
+}
+
+template<typename NewLocalCallback>
+bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
+                                   bool is_static,
+                                   uint32_t method_idx,
+                                   NewLocalCallback new_local_callback,
+                                   void* context) const {
+  if (code_item == nullptr) {
+    return false;
+  }
+  std::vector<const char*> arg_descriptors;
+  DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
+  for (; it.HasNext(); it.Next()) {
+    arg_descriptors.push_back(it.GetDescriptor());
+  }
+  return DecodeDebugLocalInfo(GetDebugInfoStream(code_item),
+                              GetLocation(),
+                              GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
+                              arg_descriptors,
+                              this->PrettyMethod(method_idx),
+                              is_static,
+                              code_item->registers_size_,
+                              code_item->ins_size_,
+                              code_item->insns_size_in_code_units_,
+                              [this](uint32_t idx) {
+                                return StringDataByIdx(dex::StringIndex(idx));
+                              },
+                              [this](uint32_t idx) {
+                                return StringByTypeIdx(dex::TypeIndex(
+                                    dchecked_integral_cast<uint16_t>(idx)));
+                              },
+                              new_local_callback,
+                              context);
+}
+
+template<typename DexDebugNewPosition, typename IndexToStringData>
+bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
+                                      IndexToStringData index_to_string_data,
+                                      DexDebugNewPosition position_functor,
+                                      void* context) {
+  if (stream == nullptr) {
+    return false;
+  }
+
+  PositionInfo entry = PositionInfo();
+  entry.line_ = DecodeUnsignedLeb128(&stream);
+  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+  for (uint32_t i = 0; i < parameters_size; ++i) {
+    DecodeUnsignedLeb128P1(&stream);  // Parameter name.
+  }
+
+  for (;;)  {
+    uint8_t opcode = *stream++;
+    switch (opcode) {
+      case DBG_END_SEQUENCE:
+        return true;  // end of stream.
+      case DBG_ADVANCE_PC:
+        entry.address_ += DecodeUnsignedLeb128(&stream);
+        break;
+      case DBG_ADVANCE_LINE:
+        entry.line_ += DecodeSignedLeb128(&stream);
+        break;
+      case DBG_START_LOCAL:
+        DecodeUnsignedLeb128(&stream);  // reg.
+        DecodeUnsignedLeb128P1(&stream);  // name.
+        DecodeUnsignedLeb128P1(&stream);  // descriptor.
+        break;
+      case DBG_START_LOCAL_EXTENDED:
+        DecodeUnsignedLeb128(&stream);  // reg.
+        DecodeUnsignedLeb128P1(&stream);  // name.
+        DecodeUnsignedLeb128P1(&stream);  // descriptor.
+        DecodeUnsignedLeb128P1(&stream);  // signature.
+        break;
+      case DBG_END_LOCAL:
+      case DBG_RESTART_LOCAL:
+        DecodeUnsignedLeb128(&stream);  // reg.
+        break;
+      case DBG_SET_PROLOGUE_END:
+        entry.prologue_end_ = true;
+        break;
+      case DBG_SET_EPILOGUE_BEGIN:
+        entry.epilogue_begin_ = true;
+        break;
+      case DBG_SET_FILE: {
+        uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
+        entry.source_file_ = index_to_string_data(name_idx);
+        break;
+      }
+      default: {
+        int adjopcode = opcode - DBG_FIRST_SPECIAL;
+        entry.address_ += adjopcode / DBG_LINE_RANGE;
+        entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+        if (position_functor(context, entry)) {
+          return true;  // early exit.
+        }
+        entry.prologue_end_ = false;
+        entry.epilogue_begin_ = false;
+        break;
+      }
+    }
+  }
+}
+
+template<typename DexDebugNewPosition>
+bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item,
+                                      DexDebugNewPosition position_functor,
+                                      void* context) const {
+  if (code_item == nullptr) {
+    return false;
+  }
+  return DecodeDebugPositionInfo(GetDebugInfoStream(code_item),
+                                 [this](uint32_t idx) {
+                                   return StringDataByIdx(dex::StringIndex(idx));
+                                 },
+                                 position_functor,
+                                 context);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_DEX_FILE_INL_H_
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 2e776b0..f2c43f7 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -23,7 +23,6 @@
 #include <string.h>
 #include <sys/file.h>
 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
-#include <sys/stat.h>
 #include <zlib.h>
 
 #include <memory>
@@ -33,19 +32,17 @@
 #include "android-base/stringprintf.h"
 
 #include "base/enums.h"
-#include "base/file_magic.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/systrace.h"
-#include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
-#include "dex_file_verifier.h"
+#include "dex_file_loader.h"
 #include "jvalue.h"
 #include "leb128.h"
+#include "mem_map.h"
 #include "os.h"
+#include "standard_dex_file.h"
 #include "utf-inl.h"
 #include "utils.h"
-#include "zip_archive.h"
 
 namespace art {
 
@@ -56,22 +53,6 @@
 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
 static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
 
-static constexpr OatDexFile* kNoOatDexFile = nullptr;
-
-const char* DexFile::kClassesDex = "classes.dex";
-
-const uint8_t DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
-const uint8_t DexFile::kDexMagicVersions[DexFile::kNumDexVersions][DexFile::kDexVersionLen] = {
-  {'0', '3', '5', '\0'},
-  // Dex version 036 skipped because of an old dalvik bug on some versions of android where dex
-  // files with that version number would erroneously be accepted and run.
-  {'0', '3', '7', '\0'},
-  // Dex version 038: Android "O".
-  {'0', '3', '8', '\0'},
-  // Dex verion 039: Beyond Android "O".
-  {'0', '3', '9', '\0'},
-};
-
 uint32_t DexFile::CalculateChecksum() const {
   const uint32_t non_sum = OFFSETOF_MEMBER(DexFile::Header, signature_);
   const uint8_t* non_sum_ptr = Begin() + non_sum;
@@ -83,55 +64,6 @@
   uint8_t type_;
 };
 
-bool DexFile::GetMultiDexChecksums(const char* filename,
-                                   std::vector<uint32_t>* checksums,
-                                   std::string* error_msg) {
-  CHECK(checksums != nullptr);
-  uint32_t magic;
-
-  File fd = OpenAndReadMagic(filename, &magic, error_msg);
-  if (fd.Fd() == -1) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  if (IsZipMagic(magic)) {
-    std::unique_ptr<ZipArchive> zip_archive(
-        ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
-    if (zip_archive.get() == nullptr) {
-      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
-                                error_msg->c_str());
-      return false;
-    }
-
-    uint32_t i = 0;
-    std::string zip_entry_name = GetMultiDexClassesDexName(i++);
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
-    if (zip_entry.get() == nullptr) {
-      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
-          zip_entry_name.c_str(), error_msg->c_str());
-      return false;
-    }
-
-    do {
-      checksums->push_back(zip_entry->GetCrc32());
-      zip_entry_name = DexFile::GetMultiDexClassesDexName(i++);
-      zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
-    } while (zip_entry.get() != nullptr);
-    return true;
-  }
-  if (IsDexMagic(magic)) {
-    std::unique_ptr<const DexFile> dex_file(
-        DexFile::OpenFile(fd.Release(), filename, false, false, error_msg));
-    if (dex_file.get() == nullptr) {
-      return false;
-    }
-    checksums->push_back(dex_file->GetHeader().checksum_);
-    return true;
-  }
-  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
-  return false;
-}
-
 int DexFile::GetPermissions() const {
   if (mem_map_.get() == nullptr) {
     return 0;
@@ -162,367 +94,6 @@
   }
 }
 
-
-std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base,
-                                             size_t size,
-                                             const std::string& location,
-                                             uint32_t location_checksum,
-                                             const OatDexFile* oat_dex_file,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file from RAM ") + location);
-  return OpenCommon(base,
-                    size,
-                    location,
-                    location_checksum,
-                    oat_dex_file,
-                    verify,
-                    verify_checksum,
-                    error_msg);
-}
-
-std::unique_ptr<const DexFile> DexFile::Open(const std::string& location,
-                                             uint32_t location_checksum,
-                                             std::unique_ptr<MemMap> map,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
-  CHECK(map.get() != nullptr);
-
-  if (map->Size() < sizeof(DexFile::Header)) {
-    *error_msg = StringPrintf(
-        "DexFile: failed to open dex file '%s' that is too short to have a header",
-        location.c_str());
-    return nullptr;
-  }
-
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 location_checksum,
-                                                 kNoOatDexFile,
-                                                 verify,
-                                                 verify_checksum,
-                                                 error_msg);
-  if (dex_file != nullptr) {
-    dex_file->mem_map_ = std::move(map);
-  }
-  return dex_file;
-}
-
-bool DexFile::Open(const char* filename,
-                   const std::string& location,
-                   bool verify_checksum,
-                   std::string* error_msg,
-                   std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
-  uint32_t magic;
-  File fd = OpenAndReadMagic(filename, &magic, error_msg);
-  if (fd.Fd() == -1) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  if (IsZipMagic(magic)) {
-    return DexFile::OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
-  }
-  if (IsDexMagic(magic)) {
-    std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.Release(),
-                                                              location,
-                                                              /* verify */ true,
-                                                              verify_checksum,
-                                                              error_msg));
-    if (dex_file.get() != nullptr) {
-      dex_files->push_back(std::move(dex_file));
-      return true;
-    } else {
-      return false;
-    }
-  }
-  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
-  return false;
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenDex(int fd,
-                                                const std::string& location,
-                                                bool verify_checksum,
-                                                std::string* error_msg) {
-  ScopedTrace trace("Open dex file " + std::string(location));
-  return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
-}
-
-bool DexFile::OpenZip(int fd,
-                      const std::string& location,
-                      bool verify_checksum,
-                      std::string* error_msg,
-                      std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace("Dex file open Zip " + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
-  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
-  if (zip_archive.get() == nullptr) {
-    DCHECK(!error_msg->empty());
-    return false;
-  }
-  return DexFile::OpenAllDexFilesFromZip(*zip_archive,
-                                         location,
-                                         verify_checksum,
-                                         error_msg,
-                                         dex_files);
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenFile(int fd,
-                                                 const std::string& location,
-                                                 bool verify,
-                                                 bool verify_checksum,
-                                                 std::string* error_msg) {
-  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
-  CHECK(!location.empty());
-  std::unique_ptr<MemMap> map;
-  {
-    File delayed_close(fd, /* check_usage */ false);
-    struct stat sbuf;
-    memset(&sbuf, 0, sizeof(sbuf));
-    if (fstat(fd, &sbuf) == -1) {
-      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
-                                strerror(errno));
-      return nullptr;
-    }
-    if (S_ISDIR(sbuf.st_mode)) {
-      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
-      return nullptr;
-    }
-    size_t length = sbuf.st_size;
-    map.reset(MemMap::MapFile(length,
-                              PROT_READ,
-                              MAP_PRIVATE,
-                              fd,
-                              0,
-                              /*low_4gb*/false,
-                              location.c_str(),
-                              error_msg));
-    if (map == nullptr) {
-      DCHECK(!error_msg->empty());
-      return nullptr;
-    }
-  }
-
-  if (map->Size() < sizeof(DexFile::Header)) {
-    *error_msg = StringPrintf(
-        "DexFile: failed to open dex file '%s' that is too short to have a header",
-        location.c_str());
-    return nullptr;
-  }
-
-  const Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
-
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 dex_header->checksum_,
-                                                 kNoOatDexFile,
-                                                 verify,
-                                                 verify_checksum,
-                                                 error_msg);
-  if (dex_file != nullptr) {
-    dex_file->mem_map_ = std::move(map);
-  }
-
-  return dex_file;
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenOneDexFileFromZip(const ZipArchive& zip_archive,
-                                                              const char* entry_name,
-                                                              const std::string& location,
-                                                              bool verify_checksum,
-                                                              std::string* error_msg,
-                                                              ZipOpenErrorCode* error_code) {
-  ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
-  CHECK(!location.empty());
-  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
-  if (zip_entry == nullptr) {
-    *error_code = ZipOpenErrorCode::kEntryNotFound;
-    return nullptr;
-  }
-  if (zip_entry->GetUncompressedLength() == 0) {
-    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
-    *error_code = ZipOpenErrorCode::kDexFileError;
-    return nullptr;
-  }
-
-  std::unique_ptr<MemMap> map;
-  if (zip_entry->IsUncompressed()) {
-    if (!zip_entry->IsAlignedTo(alignof(Header))) {
-      // Do not mmap unaligned ZIP entries because
-      // doing so would fail dex verification which requires 4 byte alignment.
-      LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
-                   << "please zipalign to " << alignof(Header) << " bytes. "
-                   << "Falling back to extracting file.";
-    } else {
-      // Map uncompressed files within zip as file-backed to avoid a dirty copy.
-      map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
-      if (map == nullptr) {
-        LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
-                     << "is your ZIP file corrupted? Falling back to extraction.";
-        // Try again with Extraction which still has a chance of recovery.
-      }
-    }
-  }
-
-  if (map == nullptr) {
-    // Default path for compressed ZIP entries,
-    // and fallback for stored ZIP entries.
-    map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
-  }
-
-  if (map == nullptr) {
-    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
-                              error_msg->c_str());
-    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
-    return nullptr;
-  }
-  VerifyResult verify_result;
-  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
-                                                 map->Size(),
-                                                 location,
-                                                 zip_entry->GetCrc32(),
-                                                 kNoOatDexFile,
-                                                 /* verify */ true,
-                                                 verify_checksum,
-                                                 error_msg,
-                                                 &verify_result);
-  if (dex_file == nullptr) {
-    if (verify_result == VerifyResult::kVerifyNotAttempted) {
-      *error_code = ZipOpenErrorCode::kDexFileError;
-    } else {
-      *error_code = ZipOpenErrorCode::kVerifyError;
-    }
-    return nullptr;
-  }
-  dex_file->mem_map_ = std::move(map);
-  if (!dex_file->DisableWrite()) {
-    *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
-    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
-    return nullptr;
-  }
-  CHECK(dex_file->IsReadOnly()) << location;
-  if (verify_result != VerifyResult::kVerifySucceeded) {
-    *error_code = ZipOpenErrorCode::kVerifyError;
-    return nullptr;
-  }
-  *error_code = ZipOpenErrorCode::kNoError;
-  return dex_file;
-}
-
-// Technically we do not have a limitation with respect to the number of dex files that can be in a
-// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
-// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
-// seems an excessive number.
-static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
-
-bool DexFile::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
-                                     const std::string& location,
-                                     bool verify_checksum,
-                                     std::string* error_msg,
-                                     std::vector<std::unique_ptr<const DexFile>>* dex_files) {
-  ScopedTrace trace("Dex file open from Zip " + std::string(location));
-  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
-  ZipOpenErrorCode error_code;
-  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
-                                                                kClassesDex,
-                                                                location,
-                                                                verify_checksum,
-                                                                error_msg,
-                                                                &error_code));
-  if (dex_file.get() == nullptr) {
-    return false;
-  } else {
-    // Had at least classes.dex.
-    dex_files->push_back(std::move(dex_file));
-
-    // Now try some more.
-
-    // We could try to avoid std::string allocations by working on a char array directly. As we
-    // do not expect a lot of iterations, this seems too involved and brittle.
-
-    for (size_t i = 1; ; ++i) {
-      std::string name = GetMultiDexClassesDexName(i);
-      std::string fake_location = GetMultiDexLocation(i, location.c_str());
-      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
-                                                                         name.c_str(),
-                                                                         fake_location,
-                                                                         verify_checksum,
-                                                                         error_msg,
-                                                                         &error_code));
-      if (next_dex_file.get() == nullptr) {
-        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
-          LOG(WARNING) << "Zip open failed: " << *error_msg;
-        }
-        break;
-      } else {
-        dex_files->push_back(std::move(next_dex_file));
-      }
-
-      if (i == kWarnOnManyDexFilesThreshold) {
-        LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
-                     << " dex files. Please consider coalescing and shrinking the number to "
-                        " avoid runtime overhead.";
-      }
-
-      if (i == std::numeric_limits<size_t>::max()) {
-        LOG(ERROR) << "Overflow in number of dex files!";
-        break;
-      }
-    }
-
-    return true;
-  }
-}
-
-std::unique_ptr<DexFile> DexFile::OpenCommon(const uint8_t* base,
-                                             size_t size,
-                                             const std::string& location,
-                                             uint32_t location_checksum,
-                                             const OatDexFile* oat_dex_file,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg,
-                                             VerifyResult* verify_result) {
-  if (verify_result != nullptr) {
-    *verify_result = VerifyResult::kVerifyNotAttempted;
-  }
-  std::unique_ptr<DexFile> dex_file(new DexFile(base,
-                                                size,
-                                                location,
-                                                location_checksum,
-                                                oat_dex_file));
-  if (dex_file == nullptr) {
-    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
-                              error_msg->c_str());
-    return nullptr;
-  }
-  if (!dex_file->Init(error_msg)) {
-    dex_file.reset();
-    return nullptr;
-  }
-  if (verify && !DexFileVerifier::Verify(dex_file.get(),
-                                         dex_file->Begin(),
-                                         dex_file->Size(),
-                                         location.c_str(),
-                                         verify_checksum,
-                                         error_msg)) {
-    if (verify_result != nullptr) {
-      *verify_result = VerifyResult::kVerifyFailed;
-    }
-    return nullptr;
-  }
-  if (verify_result != nullptr) {
-    *verify_result = VerifyResult::kVerifySucceeded;
-  }
-  return dex_file;
-}
-
 DexFile::DexFile(const uint8_t* base,
                  size_t size,
                  const std::string& location,
@@ -569,7 +140,7 @@
 }
 
 bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
-  if (!IsMagicValid(header_->magic_)) {
+  if (!IsMagicValid()) {
     std::ostringstream oss;
     oss << "Unrecognized magic number in "  << GetLocation() << ":"
             << " " << header_->magic_[0]
@@ -579,7 +150,7 @@
     *error_msg = oss.str();
     return false;
   }
-  if (!IsVersionValid(header_->magic_)) {
+  if (!IsVersionValid()) {
     std::ostringstream oss;
     oss << "Unrecognized version number in "  << GetLocation() << ":"
             << " " << header_->magic_[4]
@@ -619,22 +190,8 @@
   }
 }
 
-bool DexFile::IsMagicValid(const uint8_t* magic) {
-  return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
-}
-
-bool DexFile::IsVersionValid(const uint8_t* magic) {
-  const uint8_t* version = &magic[sizeof(kDexMagic)];
-  for (uint32_t i = 0; i < kNumDexVersions; i++) {
-    if (memcmp(version, kDexMagicVersions[i], kDexVersionLen) == 0) {
-      return true;
-    }
-  }
-  return false;
-}
-
 uint32_t DexFile::Header::GetVersion() const {
-  const char* version = reinterpret_cast<const char*>(&magic_[sizeof(kDexMagic)]);
+  const char* version = reinterpret_cast<const char*>(&magic_[kDexMagicSize]);
   return atoi(version);
 }
 
@@ -980,228 +537,6 @@
   }
 }
 
-bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
-                                   DexDebugNewLocalCb local_cb, void* context) const {
-  DCHECK(local_cb != nullptr);
-  if (code_item == nullptr) {
-    return false;
-  }
-  const uint8_t* stream = GetDebugInfoStream(code_item);
-  if (stream == nullptr) {
-    return false;
-  }
-  std::vector<LocalInfo> local_in_reg(code_item->registers_size_);
-
-  uint16_t arg_reg = code_item->registers_size_ - code_item->ins_size_;
-  if (!is_static) {
-    const char* descriptor = GetMethodDeclaringClassDescriptor(GetMethodId(method_idx));
-    local_in_reg[arg_reg].name_ = "this";
-    local_in_reg[arg_reg].descriptor_ = descriptor;
-    local_in_reg[arg_reg].signature_ = nullptr;
-    local_in_reg[arg_reg].start_address_ = 0;
-    local_in_reg[arg_reg].reg_ = arg_reg;
-    local_in_reg[arg_reg].is_live_ = true;
-    arg_reg++;
-  }
-
-  DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
-  DecodeUnsignedLeb128(&stream);  // Line.
-  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
-  uint32_t i;
-  for (i = 0; i < parameters_size && it.HasNext(); ++i, it.Next()) {
-    if (arg_reg >= code_item->registers_size_) {
-      LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
-                 << " >= " << code_item->registers_size_ << ") in " << GetLocation();
-      return false;
-    }
-    uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
-    const char* descriptor = it.GetDescriptor();
-    local_in_reg[arg_reg].name_ = StringDataByIdx(dex::StringIndex(name_idx));
-    local_in_reg[arg_reg].descriptor_ = descriptor;
-    local_in_reg[arg_reg].signature_ = nullptr;
-    local_in_reg[arg_reg].start_address_ = 0;
-    local_in_reg[arg_reg].reg_ = arg_reg;
-    local_in_reg[arg_reg].is_live_ = true;
-    switch (*descriptor) {
-      case 'D':
-      case 'J':
-        arg_reg += 2;
-        break;
-      default:
-        arg_reg += 1;
-        break;
-    }
-  }
-  if (i != parameters_size || it.HasNext()) {
-    LOG(ERROR) << "invalid stream - problem with parameter iterator in " << GetLocation()
-               << " for method " << this->PrettyMethod(method_idx);
-    return false;
-  }
-
-  uint32_t address = 0;
-  for (;;)  {
-    uint8_t opcode = *stream++;
-    switch (opcode) {
-      case DBG_END_SEQUENCE:
-        // Emit all variables which are still alive at the end of the method.
-        for (uint16_t reg = 0; reg < code_item->registers_size_; reg++) {
-          if (local_in_reg[reg].is_live_) {
-            local_in_reg[reg].end_address_ = code_item->insns_size_in_code_units_;
-            local_cb(context, local_in_reg[reg]);
-          }
-        }
-        return true;
-      case DBG_ADVANCE_PC:
-        address += DecodeUnsignedLeb128(&stream);
-        break;
-      case DBG_ADVANCE_LINE:
-        DecodeSignedLeb128(&stream);  // Line.
-        break;
-      case DBG_START_LOCAL:
-      case DBG_START_LOCAL_EXTENDED: {
-        uint16_t reg = DecodeUnsignedLeb128(&stream);
-        if (reg >= code_item->registers_size_) {
-          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
-                     << code_item->registers_size_ << ") in " << GetLocation();
-          return false;
-        }
-
-        uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
-        uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
-        uint32_t signature_idx = dex::kDexNoIndex;
-        if (opcode == DBG_START_LOCAL_EXTENDED) {
-          signature_idx = DecodeUnsignedLeb128P1(&stream);
-        }
-
-        // Emit what was previously there, if anything
-        if (local_in_reg[reg].is_live_) {
-          local_in_reg[reg].end_address_ = address;
-          local_cb(context, local_in_reg[reg]);
-        }
-
-        local_in_reg[reg].name_ = StringDataByIdx(dex::StringIndex(name_idx));
-        local_in_reg[reg].descriptor_ =
-            StringByTypeIdx(dex::TypeIndex(dchecked_integral_cast<uint16_t>(descriptor_idx)));;
-        local_in_reg[reg].signature_ = StringDataByIdx(dex::StringIndex(signature_idx));
-        local_in_reg[reg].start_address_ = address;
-        local_in_reg[reg].reg_ = reg;
-        local_in_reg[reg].is_live_ = true;
-        break;
-      }
-      case DBG_END_LOCAL: {
-        uint16_t reg = DecodeUnsignedLeb128(&stream);
-        if (reg >= code_item->registers_size_) {
-          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
-                     << code_item->registers_size_ << ") in " << GetLocation();
-          return false;
-        }
-        // If the register is live, close it properly. Otherwise, closing an already
-        // closed register is sloppy, but harmless if no further action is taken.
-        if (local_in_reg[reg].is_live_) {
-          local_in_reg[reg].end_address_ = address;
-          local_cb(context, local_in_reg[reg]);
-          local_in_reg[reg].is_live_ = false;
-        }
-        break;
-      }
-      case DBG_RESTART_LOCAL: {
-        uint16_t reg = DecodeUnsignedLeb128(&stream);
-        if (reg >= code_item->registers_size_) {
-          LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
-                     << code_item->registers_size_ << ") in " << GetLocation();
-          return false;
-        }
-        // If the register is live, the "restart" is superfluous,
-        // and we don't want to mess with the existing start address.
-        if (!local_in_reg[reg].is_live_) {
-          local_in_reg[reg].start_address_ = address;
-          local_in_reg[reg].is_live_ = true;
-        }
-        break;
-      }
-      case DBG_SET_PROLOGUE_END:
-      case DBG_SET_EPILOGUE_BEGIN:
-        break;
-      case DBG_SET_FILE:
-        DecodeUnsignedLeb128P1(&stream);  // name.
-        break;
-      default:
-        address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE;
-        break;
-    }
-  }
-}
-
-bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item, DexDebugNewPositionCb position_cb,
-                                      void* context) const {
-  DCHECK(position_cb != nullptr);
-  if (code_item == nullptr) {
-    return false;
-  }
-  const uint8_t* stream = GetDebugInfoStream(code_item);
-  if (stream == nullptr) {
-    return false;
-  }
-
-  PositionInfo entry = PositionInfo();
-  entry.line_ = DecodeUnsignedLeb128(&stream);
-  uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
-  for (uint32_t i = 0; i < parameters_size; ++i) {
-    DecodeUnsignedLeb128P1(&stream);  // Parameter name.
-  }
-
-  for (;;)  {
-    uint8_t opcode = *stream++;
-    switch (opcode) {
-      case DBG_END_SEQUENCE:
-        return true;  // end of stream.
-      case DBG_ADVANCE_PC:
-        entry.address_ += DecodeUnsignedLeb128(&stream);
-        break;
-      case DBG_ADVANCE_LINE:
-        entry.line_ += DecodeSignedLeb128(&stream);
-        break;
-      case DBG_START_LOCAL:
-        DecodeUnsignedLeb128(&stream);  // reg.
-        DecodeUnsignedLeb128P1(&stream);  // name.
-        DecodeUnsignedLeb128P1(&stream);  // descriptor.
-        break;
-      case DBG_START_LOCAL_EXTENDED:
-        DecodeUnsignedLeb128(&stream);  // reg.
-        DecodeUnsignedLeb128P1(&stream);  // name.
-        DecodeUnsignedLeb128P1(&stream);  // descriptor.
-        DecodeUnsignedLeb128P1(&stream);  // signature.
-        break;
-      case DBG_END_LOCAL:
-      case DBG_RESTART_LOCAL:
-        DecodeUnsignedLeb128(&stream);  // reg.
-        break;
-      case DBG_SET_PROLOGUE_END:
-        entry.prologue_end_ = true;
-        break;
-      case DBG_SET_EPILOGUE_BEGIN:
-        entry.epilogue_begin_ = true;
-        break;
-      case DBG_SET_FILE: {
-        uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
-        entry.source_file_ = StringDataByIdx(dex::StringIndex(name_idx));
-        break;
-      }
-      default: {
-        int adjopcode = opcode - DBG_FIRST_SPECIAL;
-        entry.address_ += adjopcode / DBG_LINE_RANGE;
-        entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
-        if (position_cb(context, entry)) {
-          return true;  // early exit.
-        }
-        entry.prologue_end_ = false;
-        entry.epilogue_begin_ = false;
-        break;
-      }
-    }
-  }
-}
-
 bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
   LineNumFromPcContext* context = reinterpret_cast<LineNumFromPcContext*>(raw_context);
 
@@ -1218,41 +553,6 @@
   }
 }
 
-bool DexFile::IsMultiDexLocation(const char* location) {
-  return strrchr(location, kMultiDexSeparator) != nullptr;
-}
-
-std::string DexFile::GetMultiDexClassesDexName(size_t index) {
-  if (index == 0) {
-    return "classes.dex";
-  } else {
-    return StringPrintf("classes%zu.dex", index + 1);
-  }
-}
-
-std::string DexFile::GetMultiDexLocation(size_t index, const char* dex_location) {
-  if (index == 0) {
-    return dex_location;
-  } else {
-    return StringPrintf("%s" kMultiDexSeparatorString "classes%zu.dex", dex_location, index + 1);
-  }
-}
-
-std::string DexFile::GetDexCanonicalLocation(const char* dex_location) {
-  CHECK_NE(dex_location, static_cast<const char*>(nullptr));
-  std::string base_location = GetBaseLocation(dex_location);
-  const char* suffix = dex_location + base_location.size();
-  DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
-  UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
-  if (path != nullptr && path.get() != base_location) {
-    return std::string(path.get()) + suffix;
-  } else if (suffix[0] == 0) {
-    return base_location;
-  } else {
-    return dex_location;
-  }
-}
-
 // Read a signed integer.  "zwidth" is the zero-based byte count.
 int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
   int32_t val = 0;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 516b379..6868d52 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -39,34 +39,28 @@
 class StringPiece;
 class ZipArchive;
 
+// Dex file is the API that exposes native dex files (ordinary dex files) and CompactDex.
+// Originally, the dex file format used by ART was mostly the same as APKs. The only change was
+// quickened opcodes and layout optimizations.
+// Since ART needs to support both native dex files and CompactDex files, the DexFile interface
+// provides an abstraction to facilitate this.
 class DexFile {
  public:
+  // Number of bytes in the dex file magic.
+  static constexpr size_t kDexMagicSize = 4;
+  static constexpr size_t kDexVersionLen = 4;
+
   // First Dex format version supporting default methods.
   static const uint32_t kDefaultMethodsVersion = 37;
   // First Dex format version enforcing class definition ordering rules.
   static const uint32_t kClassDefinitionOrderEnforcedVersion = 37;
 
-  static const uint8_t kDexMagic[];
-  static constexpr size_t kNumDexVersions = 4;
-  static constexpr size_t kDexVersionLen = 4;
-  static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
-
   static constexpr size_t kSha1DigestSize = 20;
   static constexpr uint32_t kDexEndianConstant = 0x12345678;
 
-  // name of the DexFile entry within a zip archive
-  static const char* kClassesDex;
-
   // The value of an invalid index.
   static const uint16_t kDexNoIndex16 = 0xFFFF;
 
-  // The separator character in MultiDex locations.
-  static constexpr char kMultiDexSeparator = '!';
-
-  // A string version of the previous. This is a define so that we can merge string literals in the
-  // preprocessor.
-  #define kMultiDexSeparatorString "!"
-
   // Raw header_item.
   struct Header {
     uint8_t magic_[8];
@@ -433,57 +427,6 @@
 
   struct AnnotationValue;
 
-  // Returns the checksums of a file for comparison with GetLocationChecksum().
-  // For .dex files, this is the single header checksum.
-  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
-  // each additional multidex entry classes2.dex, classes3.dex, etc.
-  // Return true if the checksums could be found, false otherwise.
-  static bool GetMultiDexChecksums(const char* filename,
-                                   std::vector<uint32_t>* checksums,
-                                   std::string* error_msg);
-
-  // Check whether a location denotes a multidex dex file. This is a very simple check: returns
-  // whether the string contains the separator character.
-  static bool IsMultiDexLocation(const char* location);
-
-  // Opens .dex file, backed by existing memory
-  static std::unique_ptr<const DexFile> Open(const uint8_t* base,
-                                             size_t size,
-                                             const std::string& location,
-                                             uint32_t location_checksum,
-                                             const OatDexFile* oat_dex_file,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg);
-
-  // Opens .dex file that has been memory-mapped by the caller.
-  static std::unique_ptr<const DexFile> Open(const std::string& location,
-                                             uint32_t location_checkum,
-                                             std::unique_ptr<MemMap> mem_map,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg);
-
-  // Opens all .dex files found in the file, guessing the container format based on file extension.
-  static bool Open(const char* filename,
-                   const std::string& location,
-                   bool verify_checksum,
-                   std::string* error_msg,
-                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
-  // Open a single dex file from an fd. This function closes the fd.
-  static std::unique_ptr<const DexFile> OpenDex(int fd,
-                                                const std::string& location,
-                                                bool verify_checksum,
-                                                std::string* error_msg);
-
-  // Opens dex files from within a .jar, .zip, or .apk file
-  static bool OpenZip(int fd,
-                      const std::string& location,
-                      bool verify_checksum,
-                      std::string* error_msg,
-                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
   // Closes a .dex file.
   virtual ~DexFile();
 
@@ -491,30 +434,6 @@
     return location_;
   }
 
-  // For normal dex files, location and base location coincide. If a dex file is part of a multidex
-  // archive, the base location is the name of the originating jar/apk, stripped of any internal
-  // classes*.dex path.
-  static std::string GetBaseLocation(const char* location) {
-    const char* pos = strrchr(location, kMultiDexSeparator);
-    return (pos == nullptr) ? location : std::string(location, pos - location);
-  }
-
-  static std::string GetBaseLocation(const std::string& location) {
-    return GetBaseLocation(location.c_str());
-  }
-
-  // Returns the '!classes*.dex' part of the dex location. Returns an empty
-  // string if there is no multidex suffix for the given location.
-  // The kMultiDexSeparator is included in the returned suffix.
-  static std::string GetMultiDexSuffix(const std::string& location) {
-    size_t pos = location.rfind(kMultiDexSeparator);
-    return (pos == std::string::npos) ? std::string() : location.substr(pos);
-  }
-
-  std::string GetBaseLocation() const {
-    return GetBaseLocation(location_);
-  }
-
   // For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
   // For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
   uint32_t GetLocationChecksum() const {
@@ -532,10 +451,10 @@
   }
 
   // Returns true if the byte string points to the magic value.
-  static bool IsMagicValid(const uint8_t* magic);
+  virtual bool IsMagicValid() const = 0;
 
   // Returns true if the byte string after the magic is the correct value.
-  static bool IsVersionValid(const uint8_t* magic);
+  virtual bool IsVersionValid() const = 0;
 
   // Returns the number of string identifiers in the .dex file.
   size_t NumStringIds() const {
@@ -853,10 +772,6 @@
     bool epilogue_begin_ = false;
   };
 
-  // Callback for "new position table entry".
-  // Returning true causes the decoder to stop early.
-  typedef bool (*DexDebugNewPositionCb)(void* context, const PositionInfo& entry);
-
   struct LocalInfo {
     LocalInfo() = default;
 
@@ -980,11 +895,36 @@
   };
 
   // Returns false if there is no debugging information or if it cannot be decoded.
-  bool DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
-                            DexDebugNewLocalCb local_cb, void* context) const;
+  template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
+  static bool DecodeDebugLocalInfo(const uint8_t* stream,
+                                   const std::string& location,
+                                   const char* declaring_class_descriptor,
+                                   const std::vector<const char*>& arg_descriptors,
+                                   const std::string& method_name,
+                                   bool is_static,
+                                   uint16_t registers_size,
+                                   uint16_t ins_size,
+                                   uint16_t insns_size_in_code_units,
+                                   IndexToStringData index_to_string_data,
+                                   TypeIndexToStringData type_index_to_string_data,
+                                   NewLocalCallback new_local,
+                                   void* context);
+  template<typename NewLocalCallback>
+  bool DecodeDebugLocalInfo(const CodeItem* code_item,
+                            bool is_static,
+                            uint32_t method_idx,
+                            NewLocalCallback new_local,
+                            void* context) const;
 
   // Returns false if there is no debugging information or if it cannot be decoded.
-  bool DecodeDebugPositionInfo(const CodeItem* code_item, DexDebugNewPositionCb position_cb,
+  template<typename DexDebugNewPosition, typename IndexToStringData>
+  static bool DecodeDebugPositionInfo(const uint8_t* stream,
+                                      IndexToStringData index_to_string_data,
+                                      DexDebugNewPosition position_functor,
+                                      void* context);
+  template<typename DexDebugNewPosition>
+  bool DecodeDebugPositionInfo(const CodeItem* code_item,
+                               DexDebugNewPosition position_functor,
                                void* context) const;
 
   const char* GetSourceFile(const ClassDef& class_def) const {
@@ -1011,29 +951,6 @@
     return size_;
   }
 
-  // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
-  // index == 0, and classes{index + 1}.dex else.
-  static std::string GetMultiDexClassesDexName(size_t index);
-
-  // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
-  // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
-  static std::string GetMultiDexLocation(size_t index, const char* dex_location);
-
-  // Returns the canonical form of the given dex location.
-  //
-  // There are different flavors of "dex locations" as follows:
-  // the file name of a dex file:
-  //     The actual file path that the dex file has on disk.
-  // dex_location:
-  //     This acts as a key for the class linker to know which dex file to load.
-  //     It may correspond to either an old odex file or a particular dex file
-  //     inside an oat file. In the first case it will also match the file name
-  //     of the dex file. In the second case (oat) it will include the file name
-  //     and possibly some multidex annotation to uniquely identify it.
-  // canonical_dex_location:
-  //     the dex_location where it's file name part has been made canonical.
-  static std::string GetDexCanonicalLocation(const char* dex_location);
-
   const OatDexFile* GetOatDexFile() const {
     return oat_dex_file_;
   }
@@ -1059,64 +976,7 @@
   // Returns a human-readable form of the type at an index.
   std::string PrettyType(dex::TypeIndex type_idx) const;
 
- private:
-  static std::unique_ptr<const DexFile> OpenFile(int fd,
-                                                 const std::string& location,
-                                                 bool verify,
-                                                 bool verify_checksum,
-                                                 std::string* error_msg);
-
-  enum class ZipOpenErrorCode {  // private
-    kNoError,
-    kEntryNotFound,
-    kExtractToMemoryError,
-    kDexFileError,
-    kMakeReadOnlyError,
-    kVerifyError
-  };
-
-  // Open all classesXXX.dex files from a zip archive.
-  static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
-                                     const std::string& location,
-                                     bool verify_checksum,
-                                     std::string* error_msg,
-                                     std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
-  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
-  // return.
-  static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
-                                                              const char* entry_name,
-                                                              const std::string& location,
-                                                              bool verify_checksum,
-                                                              std::string* error_msg,
-                                                              ZipOpenErrorCode* error_code);
-
-  enum class VerifyResult {  // private
-    kVerifyNotAttempted,
-    kVerifySucceeded,
-    kVerifyFailed
-  };
-
-  static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
-                                             size_t size,
-                                             const std::string& location,
-                                             uint32_t location_checksum,
-                                             const OatDexFile* oat_dex_file,
-                                             bool verify,
-                                             bool verify_checksum,
-                                             std::string* error_msg,
-                                             VerifyResult* verify_result = nullptr);
-
-
-  // Opens a .dex file at the given address, optionally backed by a MemMap
-  static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
-                                                   size_t size,
-                                                   const std::string& location,
-                                                   uint32_t location_checksum,
-                                                   std::unique_ptr<MemMap> mem_map,
-                                                   const OatDexFile* oat_dex_file,
-                                                   std::string* error_msg);
-
+ protected:
   DexFile(const uint8_t* base,
           size_t size,
           const std::string& location,
@@ -1187,9 +1047,9 @@
   // null.
   mutable const OatDexFile* oat_dex_file_;
 
+  friend class DexFileLoader;
   friend class DexFileVerifierTest;
   friend class OatWriter;
-  ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for constructor
 };
 
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
diff --git a/runtime/dex_file_loader.cc b/runtime/dex_file_loader.cc
new file mode 100644
index 0000000..8cab1a5
--- /dev/null
+++ b/runtime/dex_file_loader.cc
@@ -0,0 +1,484 @@
+/*
+ * 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 "dex_file_loader.h"
+
+#include <sys/mman.h>  // For the PROT_* and MAP_* constants.
+#include <sys/stat.h>
+
+#include "android-base/stringprintf.h"
+
+#include "base/file_magic.h"
+#include "base/stl_util.h"
+#include "base/systrace.h"
+#include "base/unix_file/fd_file.h"
+#include "dex_file.h"
+#include "dex_file_verifier.h"
+#include "standard_dex_file.h"
+#include "zip_archive.h"
+
+namespace art {
+
+using android::base::StringPrintf;
+
+static constexpr OatDexFile* kNoOatDexFile = nullptr;
+
+
+bool DexFileLoader::IsValidMagic(uint32_t magic) {
+  return IsValidMagic(reinterpret_cast<uint8_t*>(&magic));
+}
+
+bool DexFileLoader::IsValidMagic(const uint8_t* magic) {
+  return StandardDexFile::IsMagicValid(magic);
+}
+
+bool DexFileLoader::GetMultiDexChecksums(const char* filename,
+                                         std::vector<uint32_t>* checksums,
+                                         std::string* error_msg) {
+  CHECK(checksums != nullptr);
+  uint32_t magic;
+
+  File fd = OpenAndReadMagic(filename, &magic, error_msg);
+  if (fd.Fd() == -1) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  if (IsZipMagic(magic)) {
+    std::unique_ptr<ZipArchive> zip_archive(
+        ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
+    if (zip_archive.get() == nullptr) {
+      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
+                                error_msg->c_str());
+      return false;
+    }
+
+    uint32_t i = 0;
+    std::string zip_entry_name = GetMultiDexClassesDexName(i++);
+    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+    if (zip_entry.get() == nullptr) {
+      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+          zip_entry_name.c_str(), error_msg->c_str());
+      return false;
+    }
+
+    do {
+      checksums->push_back(zip_entry->GetCrc32());
+      zip_entry_name = GetMultiDexClassesDexName(i++);
+      zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+    } while (zip_entry.get() != nullptr);
+    return true;
+  }
+  if (IsValidMagic(magic)) {
+    std::unique_ptr<const DexFile> dex_file(
+        OpenFile(fd.Release(), filename, false, false, error_msg));
+    if (dex_file == nullptr) {
+      return false;
+    }
+    checksums->push_back(dex_file->GetHeader().checksum_);
+    return true;
+  }
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return false;
+}
+
+bool DexFileLoader::IsMultiDexLocation(const char* location) {
+  return strrchr(location, kMultiDexSeparator) != nullptr;
+}
+
+std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) {
+  return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1);
+}
+
+std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) {
+  return (index == 0)
+      ? dex_location
+      : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1);
+}
+
+std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
+  CHECK_NE(dex_location, static_cast<const char*>(nullptr));
+  std::string base_location = GetBaseLocation(dex_location);
+  const char* suffix = dex_location + base_location.size();
+  DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+  UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
+  if (path != nullptr && path.get() != base_location) {
+    return std::string(path.get()) + suffix;
+  } else if (suffix[0] == 0) {
+    return base_location;
+  } else {
+    return dex_location;
+  }
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
+                                                   size_t size,
+                                                   const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   const OatDexFile* oat_dex_file,
+                                                   bool verify,
+                                                   bool verify_checksum,
+                                                   std::string* error_msg) {
+  ScopedTrace trace(std::string("Open dex file from RAM ") + location);
+  return OpenCommon(base,
+                    size,
+                    location,
+                    location_checksum,
+                    oat_dex_file,
+                    verify,
+                    verify_checksum,
+                    error_msg);
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   std::unique_ptr<MemMap> map,
+                                                   bool verify,
+                                                   bool verify_checksum,
+                                                   std::string* error_msg) {
+  ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
+  CHECK(map.get() != nullptr);
+
+  if (map->Size() < sizeof(DexFile::Header)) {
+    *error_msg = StringPrintf(
+        "DexFile: failed to open dex file '%s' that is too short to have a header",
+        location.c_str());
+    return nullptr;
+  }
+
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 location_checksum,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg);
+  if (dex_file != nullptr) {
+    dex_file->mem_map_ = std::move(map);
+  }
+  return dex_file;
+}
+
+bool DexFileLoader::Open(const char* filename,
+                         const std::string& location,
+                         bool verify_checksum,
+                         std::string* error_msg,
+                         std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
+  uint32_t magic;
+  File fd = OpenAndReadMagic(filename, &magic, error_msg);
+  if (fd.Fd() == -1) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  if (IsZipMagic(magic)) {
+    return OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
+  }
+  if (IsValidMagic(magic)) {
+    std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
+                                                     location,
+                                                     /* verify */ true,
+                                                     verify_checksum,
+                                                     error_msg));
+    if (dex_file.get() != nullptr) {
+      dex_files->push_back(std::move(dex_file));
+      return true;
+    } else {
+      return false;
+    }
+  }
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return false;
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd,
+                                                      const std::string& location,
+                                                      bool verify_checksum,
+                                                      std::string* error_msg) {
+  ScopedTrace trace("Open dex file " + std::string(location));
+  return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
+}
+
+bool DexFileLoader::OpenZip(int fd,
+                            const std::string& location,
+                            bool verify_checksum,
+                            std::string* error_msg,
+                            std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  ScopedTrace trace("Dex file open Zip " + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
+  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
+  if (zip_archive.get() == nullptr) {
+    DCHECK(!error_msg->empty());
+    return false;
+  }
+  return OpenAllDexFilesFromZip(*zip_archive, location, verify_checksum, error_msg, dex_files);
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd,
+                                                       const std::string& location,
+                                                       bool verify,
+                                                       bool verify_checksum,
+                                                       std::string* error_msg) {
+  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+  CHECK(!location.empty());
+  std::unique_ptr<MemMap> map;
+  {
+    File delayed_close(fd, /* check_usage */ false);
+    struct stat sbuf;
+    memset(&sbuf, 0, sizeof(sbuf));
+    if (fstat(fd, &sbuf) == -1) {
+      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
+                                strerror(errno));
+      return nullptr;
+    }
+    if (S_ISDIR(sbuf.st_mode)) {
+      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+      return nullptr;
+    }
+    size_t length = sbuf.st_size;
+    map.reset(MemMap::MapFile(length,
+                              PROT_READ,
+                              MAP_PRIVATE,
+                              fd,
+                              0,
+                              /*low_4gb*/false,
+                              location.c_str(),
+                              error_msg));
+    if (map == nullptr) {
+      DCHECK(!error_msg->empty());
+      return nullptr;
+    }
+  }
+
+  if (map->Size() < sizeof(DexFile::Header)) {
+    *error_msg = StringPrintf(
+        "DexFile: failed to open dex file '%s' that is too short to have a header",
+        location.c_str());
+    return nullptr;
+  }
+
+  const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
+
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 dex_header->checksum_,
+                                                 kNoOatDexFile,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg);
+  if (dex_file != nullptr) {
+    dex_file->mem_map_ = std::move(map);
+  }
+
+  return dex_file;
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
+    const ZipArchive& zip_archive,
+    const char* entry_name,
+    const std::string& location,
+    bool verify_checksum,
+    std::string* error_msg,
+    ZipOpenErrorCode* error_code) {
+  ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
+  CHECK(!location.empty());
+  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
+  if (zip_entry == nullptr) {
+    *error_code = ZipOpenErrorCode::kEntryNotFound;
+    return nullptr;
+  }
+  if (zip_entry->GetUncompressedLength() == 0) {
+    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
+    *error_code = ZipOpenErrorCode::kDexFileError;
+    return nullptr;
+  }
+
+  std::unique_ptr<MemMap> map;
+  if (zip_entry->IsUncompressed()) {
+    if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
+      // Do not mmap unaligned ZIP entries because
+      // doing so would fail dex verification which requires 4 byte alignment.
+      LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+                   << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
+                   << "Falling back to extracting file.";
+    } else {
+      // Map uncompressed files within zip as file-backed to avoid a dirty copy.
+      map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
+      if (map == nullptr) {
+        LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+                     << "is your ZIP file corrupted? Falling back to extraction.";
+        // Try again with Extraction which still has a chance of recovery.
+      }
+    }
+  }
+
+  if (map == nullptr) {
+    // Default path for compressed ZIP entries,
+    // and fallback for stored ZIP entries.
+    map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
+  }
+
+  if (map == nullptr) {
+    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
+                              error_msg->c_str());
+    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+    return nullptr;
+  }
+  VerifyResult verify_result;
+  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+                                                 map->Size(),
+                                                 location,
+                                                 zip_entry->GetCrc32(),
+                                                 kNoOatDexFile,
+                                                 /* verify */ true,
+                                                 verify_checksum,
+                                                 error_msg,
+                                                 &verify_result);
+  if (dex_file == nullptr) {
+    if (verify_result == VerifyResult::kVerifyNotAttempted) {
+      *error_code = ZipOpenErrorCode::kDexFileError;
+    } else {
+      *error_code = ZipOpenErrorCode::kVerifyError;
+    }
+    return nullptr;
+  }
+  dex_file->mem_map_ = std::move(map);
+  if (!dex_file->DisableWrite()) {
+    *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
+    return nullptr;
+  }
+  CHECK(dex_file->IsReadOnly()) << location;
+  if (verify_result != VerifyResult::kVerifySucceeded) {
+    *error_code = ZipOpenErrorCode::kVerifyError;
+    return nullptr;
+  }
+  *error_code = ZipOpenErrorCode::kNoError;
+  return dex_file;
+}
+
+// Technically we do not have a limitation with respect to the number of dex files that can be in a
+// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
+// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
+// seems an excessive number.
+static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
+
+bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                                          const std::string& location,
+                                          bool verify_checksum,
+                                          std::string* error_msg,
+                                          std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  ScopedTrace trace("Dex file open from Zip " + std::string(location));
+  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
+  ZipOpenErrorCode error_code;
+  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                kClassesDex,
+                                                                location,
+                                                                verify_checksum,
+                                                                error_msg,
+                                                                &error_code));
+  if (dex_file.get() == nullptr) {
+    return false;
+  } else {
+    // Had at least classes.dex.
+    dex_files->push_back(std::move(dex_file));
+
+    // Now try some more.
+
+    // We could try to avoid std::string allocations by working on a char array directly. As we
+    // do not expect a lot of iterations, this seems too involved and brittle.
+
+    for (size_t i = 1; ; ++i) {
+      std::string name = GetMultiDexClassesDexName(i);
+      std::string fake_location = GetMultiDexLocation(i, location.c_str());
+      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                         name.c_str(),
+                                                                         fake_location,
+                                                                         verify_checksum,
+                                                                         error_msg,
+                                                                         &error_code));
+      if (next_dex_file.get() == nullptr) {
+        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+          LOG(WARNING) << "Zip open failed: " << *error_msg;
+        }
+        break;
+      } else {
+        dex_files->push_back(std::move(next_dex_file));
+      }
+
+      if (i == kWarnOnManyDexFilesThreshold) {
+        LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
+                     << " dex files. Please consider coalescing and shrinking the number to "
+                        " avoid runtime overhead.";
+      }
+
+      if (i == std::numeric_limits<size_t>::max()) {
+        LOG(ERROR) << "Overflow in number of dex files!";
+        break;
+      }
+    }
+
+    return true;
+  }
+}
+
+std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
+                                                   size_t size,
+                                                   const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   const OatDexFile* oat_dex_file,
+                                                   bool verify,
+                                                   bool verify_checksum,
+                                                   std::string* error_msg,
+                                                   VerifyResult* verify_result) {
+  if (verify_result != nullptr) {
+    *verify_result = VerifyResult::kVerifyNotAttempted;
+  }
+  std::unique_ptr<DexFile> dex_file;
+  if (StandardDexFile::IsMagicValid(base)) {
+    dex_file.reset(new StandardDexFile(base, size, location, location_checksum, oat_dex_file));
+  } else {
+    return nullptr;
+  }
+  if (dex_file == nullptr) {
+    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
+                              error_msg->c_str());
+    return nullptr;
+  }
+  if (!dex_file->Init(error_msg)) {
+    dex_file.reset();
+    return nullptr;
+  }
+  if (verify && !DexFileVerifier::Verify(dex_file.get(),
+                                         dex_file->Begin(),
+                                         dex_file->Size(),
+                                         location.c_str(),
+                                         verify_checksum,
+                                         error_msg)) {
+    if (verify_result != nullptr) {
+      *verify_result = VerifyResult::kVerifyFailed;
+    }
+    return nullptr;
+  }
+  if (verify_result != nullptr) {
+    *verify_result = VerifyResult::kVerifySucceeded;
+  }
+  return dex_file;
+}
+
+}  // namespace art
diff --git a/runtime/dex_file_loader.h b/runtime/dex_file_loader.h
new file mode 100644
index 0000000..61b5c71
--- /dev/null
+++ b/runtime/dex_file_loader.h
@@ -0,0 +1,200 @@
+/*
+ * 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_DEX_FILE_LOADER_H_
+#define ART_RUNTIME_DEX_FILE_LOADER_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace art {
+
+class DexFile;
+class MemMap;
+class OatDexFile;
+class ZipArchive;
+
+// Class that is used to open dex files and deal with corresponding multidex and location logic.
+class DexFileLoader {
+ public:
+  // name of the DexFile entry within a zip archive
+  static constexpr const char* kClassesDex = "classes.dex";
+
+  // The separator character in MultiDex locations.
+  static constexpr char kMultiDexSeparator = '!';
+
+  // Return true if the magic is valid for dex or cdex.
+  static bool IsValidMagic(uint32_t magic);
+  static bool IsValidMagic(const uint8_t* magic);
+
+  // Returns the checksums of a file for comparison with GetLocationChecksum().
+  // For .dex files, this is the single header checksum.
+  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+  // each additional multidex entry classes2.dex, classes3.dex, etc.
+  // Return true if the checksums could be found, false otherwise.
+  static bool GetMultiDexChecksums(const char* filename,
+                                   std::vector<uint32_t>* checksums,
+                                   std::string* error_msg);
+
+  // Check whether a location denotes a multidex dex file. This is a very simple check: returns
+  // whether the string contains the separator character.
+  static bool IsMultiDexLocation(const char* location);
+
+  // Opens .dex file, backed by existing memory
+  static std::unique_ptr<const DexFile> Open(const uint8_t* base,
+                                             size_t size,
+                                             const std::string& location,
+                                             uint32_t location_checksum,
+                                             const OatDexFile* oat_dex_file,
+                                             bool verify,
+                                             bool verify_checksum,
+                                             std::string* error_msg);
+
+  // Opens .dex file that has been memory-mapped by the caller.
+  static std::unique_ptr<const DexFile> Open(const std::string& location,
+                                             uint32_t location_checkum,
+                                             std::unique_ptr<MemMap> mem_map,
+                                             bool verify,
+                                             bool verify_checksum,
+                                             std::string* error_msg);
+
+  // Opens all .dex files found in the file, guessing the container format based on file extension.
+  static bool Open(const char* filename,
+                   const std::string& location,
+                   bool verify_checksum,
+                   std::string* error_msg,
+                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+  // Open a single dex file from an fd. This function closes the fd.
+  static std::unique_ptr<const DexFile> OpenDex(int fd,
+                                                const std::string& location,
+                                                bool verify_checksum,
+                                                std::string* error_msg);
+
+  // Opens dex files from within a .jar, .zip, or .apk file
+  static bool OpenZip(int fd,
+                      const std::string& location,
+                      bool verify_checksum,
+                      std::string* error_msg,
+                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+  // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
+  // index == 0, and classes{index + 1}.dex else.
+  static std::string GetMultiDexClassesDexName(size_t index);
+
+  // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
+  // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
+  static std::string GetMultiDexLocation(size_t index, const char* dex_location);
+
+  // Returns the canonical form of the given dex location.
+  //
+  // There are different flavors of "dex locations" as follows:
+  // the file name of a dex file:
+  //     The actual file path that the dex file has on disk.
+  // dex_location:
+  //     This acts as a key for the class linker to know which dex file to load.
+  //     It may correspond to either an old odex file or a particular dex file
+  //     inside an oat file. In the first case it will also match the file name
+  //     of the dex file. In the second case (oat) it will include the file name
+  //     and possibly some multidex annotation to uniquely identify it.
+  // canonical_dex_location:
+  //     the dex_location where it's file name part has been made canonical.
+  static std::string GetDexCanonicalLocation(const char* dex_location);
+
+  // For normal dex files, location and base location coincide. If a dex file is part of a multidex
+  // archive, the base location is the name of the originating jar/apk, stripped of any internal
+  // classes*.dex path.
+  static std::string GetBaseLocation(const char* location) {
+    const char* pos = strrchr(location, kMultiDexSeparator);
+    return (pos == nullptr) ? location : std::string(location, pos - location);
+  }
+
+  static std::string GetBaseLocation(const std::string& location) {
+    return GetBaseLocation(location.c_str());
+  }
+
+  // Returns the '!classes*.dex' part of the dex location. Returns an empty
+  // string if there is no multidex suffix for the given location.
+  // The kMultiDexSeparator is included in the returned suffix.
+  static std::string GetMultiDexSuffix(const std::string& location) {
+    size_t pos = location.rfind(kMultiDexSeparator);
+    return (pos == std::string::npos) ? std::string() : location.substr(pos);
+  }
+
+ private:
+  static std::unique_ptr<const DexFile> OpenFile(int fd,
+                                                 const std::string& location,
+                                                 bool verify,
+                                                 bool verify_checksum,
+                                                 std::string* error_msg);
+
+  enum class ZipOpenErrorCode {
+    kNoError,
+    kEntryNotFound,
+    kExtractToMemoryError,
+    kDexFileError,
+    kMakeReadOnlyError,
+    kVerifyError
+  };
+
+  // Open all classesXXX.dex files from a zip archive.
+  static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+                                     const std::string& location,
+                                     bool verify_checksum,
+                                     std::string* error_msg,
+                                     std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+  // return.
+  static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+                                                              const char* entry_name,
+                                                              const std::string& location,
+                                                              bool verify_checksum,
+                                                              std::string* error_msg,
+                                                              ZipOpenErrorCode* error_code);
+
+  enum class VerifyResult {  // private
+    kVerifyNotAttempted,
+    kVerifySucceeded,
+    kVerifyFailed
+  };
+
+  static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
+                                             size_t size,
+                                             const std::string& location,
+                                             uint32_t location_checksum,
+                                             const OatDexFile* oat_dex_file,
+                                             bool verify,
+                                             bool verify_checksum,
+                                             std::string* error_msg,
+                                             VerifyResult* verify_result = nullptr);
+
+
+  // Opens a .dex file at the given address, optionally backed by a MemMap
+  static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
+                                                   size_t size,
+                                                   const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   std::unique_ptr<MemMap> mem_map,
+                                                   const OatDexFile* oat_dex_file,
+                                                   std::string* error_msg);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_FILE_LOADER_H_
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 67cd428..b301137 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -24,6 +24,7 @@
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "mem_map.h"
 #include "os.h"
 #include "scoped_thread_state_change-inl.h"
@@ -235,7 +236,7 @@
   ScopedObjectAccess soa(Thread::Current());
   static constexpr bool kVerifyChecksum = true;
   std::vector<std::unique_ptr<const DexFile>> tmp;
-  bool success = DexFile::Open(location, location, kVerifyChecksum, error_msg, &tmp);
+  bool success = DexFileLoader::Open(location, location, kVerifyChecksum, error_msg, &tmp);
   if (success) {
     for (std::unique_ptr<const DexFile>& dex_file : tmp) {
       EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
@@ -274,12 +275,12 @@
                                                       /* reuse */ false,
                                                       &error_message));
   memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
-  std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
-                                                        location_checksum,
-                                                        std::move(region),
-                                                        /* verify */ true,
-                                                        /* verify_checksum */ true,
-                                                        &error_message));
+  std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
+                                                              location_checksum,
+                                                              std::move(region),
+                                                              /* verify */ true,
+                                                              /* verify_checksum */ true,
+                                                              &error_message));
   if (expect_success) {
     CHECK(dex_file != nullptr) << error_message;
   } else {
@@ -365,7 +366,7 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+  ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
 }
 
 TEST_F(DexFileTest, Version41Rejected) {
@@ -377,7 +378,7 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+  ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
 }
 
 TEST_F(DexFileTest, ZeroLengthDexRejected) {
@@ -389,7 +390,7 @@
   static constexpr bool kVerifyChecksum = true;
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+  ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
 }
 
 TEST_F(DexFileTest, GetLocationChecksum) {
@@ -402,7 +403,9 @@
   std::vector<uint32_t> checksums;
   ScopedObjectAccess soa(Thread::Current());
   std::string error_msg;
-  EXPECT_TRUE(DexFile::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), &checksums, &error_msg))
+  EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
+                                                  &checksums,
+                                                  &error_msg))
       << error_msg;
   ASSERT_EQ(1U, checksums.size());
   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
@@ -412,18 +415,18 @@
   std::string error_msg;
   std::vector<uint32_t> checksums;
   std::string multidex_file = GetTestDexFileName("MultiDex");
-  EXPECT_TRUE(DexFile::GetMultiDexChecksums(multidex_file.c_str(),
-                                            &checksums,
-                                            &error_msg)) << error_msg;
+  EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(multidex_file.c_str(),
+                                                  &checksums,
+                                                  &error_msg)) << error_msg;
 
   std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
   ASSERT_EQ(2U, dexes.size());
   ASSERT_EQ(2U, checksums.size());
 
-  EXPECT_EQ(dexes[0]->GetLocation(), DexFile::GetMultiDexLocation(0, multidex_file.c_str()));
+  EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str()));
   EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]);
 
-  EXPECT_EQ(dexes[1]->GetLocation(), DexFile::GetMultiDexLocation(1, multidex_file.c_str()));
+  EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str()));
   EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]);
 }
 
@@ -625,20 +628,20 @@
 }
 
 TEST_F(DexFileTest, GetMultiDexClassesDexName) {
-  ASSERT_EQ("classes.dex", DexFile::GetMultiDexClassesDexName(0));
-  ASSERT_EQ("classes2.dex", DexFile::GetMultiDexClassesDexName(1));
-  ASSERT_EQ("classes3.dex", DexFile::GetMultiDexClassesDexName(2));
-  ASSERT_EQ("classes100.dex", DexFile::GetMultiDexClassesDexName(99));
+  ASSERT_EQ("classes.dex", DexFileLoader::GetMultiDexClassesDexName(0));
+  ASSERT_EQ("classes2.dex", DexFileLoader::GetMultiDexClassesDexName(1));
+  ASSERT_EQ("classes3.dex", DexFileLoader::GetMultiDexClassesDexName(2));
+  ASSERT_EQ("classes100.dex", DexFileLoader::GetMultiDexClassesDexName(99));
 }
 
 TEST_F(DexFileTest, GetMultiDexLocation) {
   std::string dex_location_str = "/system/app/framework.jar";
   const char* dex_location = dex_location_str.c_str();
-  ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
+  ASSERT_EQ("/system/app/framework.jar", DexFileLoader::GetMultiDexLocation(0, dex_location));
   ASSERT_EQ("/system/app/framework.jar!classes2.dex",
-            DexFile::GetMultiDexLocation(1, dex_location));
+            DexFileLoader::GetMultiDexLocation(1, dex_location));
   ASSERT_EQ("/system/app/framework.jar!classes101.dex",
-            DexFile::GetMultiDexLocation(100, dex_location));
+            DexFileLoader::GetMultiDexLocation(100, dex_location));
 }
 
 TEST_F(DexFileTest, GetDexCanonicalLocation) {
@@ -646,28 +649,30 @@
   UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
   std::string dex_location(dex_location_real.get());
 
-  ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
-  std::string multidex_location = DexFile::GetMultiDexLocation(1, dex_location.c_str());
-  ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
+  ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str()));
+  std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str());
+  ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str()));
 
   std::string dex_location_sym = dex_location + "symlink";
   ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
 
-  ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
+  ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str()));
 
-  std::string multidex_location_sym = DexFile::GetMultiDexLocation(1, dex_location_sym.c_str());
-  ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
+  std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation(
+      1, dex_location_sym.c_str());
+  ASSERT_EQ(multidex_location,
+            DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str()));
 
   ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
 }
 
 TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
-  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
-  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
-  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
-  EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
-  EXPECT_EQ("!classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
-  EXPECT_EQ("!classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
+  EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar"));
+  EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
+  EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
+  EXPECT_EQ("", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar"));
+  EXPECT_EQ("!classes2.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
+  EXPECT_EQ("!classes8.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
 }
 
 TEST_F(DexFileTest, ZipOpenClassesPresent) {
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 21de059..9f3505d 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -27,9 +27,11 @@
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "dex_file_types.h"
 #include "leb128.h"
 #include "scoped_thread_state_change-inl.h"
+#include "standard_dex_file.h"
 #include "thread-current-inl.h"
 #include "utils.h"
 
@@ -55,7 +57,7 @@
 class DexFileVerifierTest : public CommonRuntimeTest {
  protected:
   DexFile* GetDexFile(const uint8_t* dex_bytes, size_t length) {
-    return new DexFile(dex_bytes, length, "tmp", 0, nullptr);
+    return new StandardDexFile(dex_bytes, length, "tmp", 0, nullptr);
   }
 
   void VerifyModification(const char* dex_file_base64_content,
@@ -112,7 +114,7 @@
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
   std::vector<std::unique_ptr<const DexFile>> tmp;
-  bool success = DexFile::Open(location, location, true, error_msg, &tmp);
+  bool success = DexFileLoader::Open(location, location, true, error_msg, &tmp);
   CHECK(success) << *error_msg;
   EXPECT_EQ(1U, tmp.size());
   std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 158c1d6..6bb67a3 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -16,6 +16,7 @@
 
 #include "art_method-inl.h"
 #include "base/casts.h"
+#include "base/logging.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "indirect_reference_table.h"
 #include "mirror/object-inl.h"
@@ -27,6 +28,8 @@
 static_assert(sizeof(IRTSegmentState) == sizeof(uint32_t), "IRTSegmentState size unexpected");
 static_assert(std::is_trivial<IRTSegmentState>::value, "IRTSegmentState not trivial");
 
+static bool kEnableAnnotationChecks = RegisterRuntimeDebugFlag(&kEnableAnnotationChecks);
+
 template <bool kDynamicFast>
 static inline void GoToRunnableFast(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
 
@@ -53,7 +56,7 @@
   uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->local_ref_cookie);
   env->local_ref_cookie = env->locals.GetSegmentState();
 
-  if (kIsDebugBuild) {
+  if (kIsDebugBuild && kEnableAnnotationChecks) {
     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
     CHECK(native_method->IsAnnotatedWithFastNative()) << native_method->PrettyMethod();
   }
@@ -94,7 +97,7 @@
 // TODO: NO_THREAD_SAFETY_ANALYSIS due to different control paths depending on fast JNI.
 template <bool kDynamicFast>
 ALWAYS_INLINE static inline void GoToRunnableFast(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
-  if (kIsDebugBuild) {
+  if (kIsDebugBuild && kEnableAnnotationChecks) {
     // Should only enter here if the method is !Fast JNI or @FastNative.
     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4004af2..67e8a0d 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -132,10 +132,6 @@
 // Dump the rosalloc stats on SIGQUIT.
 static constexpr bool kDumpRosAllocStatsOnSigQuit = false;
 
-// Extra added to the heap growth multiplier. Used to adjust the GC ergonomics for the read barrier
-// config.
-static constexpr double kExtraHeapGrowthMultiplier = kUseReadBarrier ? 1.0 : 0.0;
-
 static const char* kRegionSpaceName = "main space (region space)";
 
 // If true, we log all GCs in the both the foreground and background. Used for debugging.
@@ -255,8 +251,7 @@
       min_free_(min_free),
       max_free_(max_free),
       target_utilization_(target_utilization),
-      foreground_heap_growth_multiplier_(
-          foreground_heap_growth_multiplier + kExtraHeapGrowthMultiplier),
+      foreground_heap_growth_multiplier_(foreground_heap_growth_multiplier),
       total_wait_time_(0),
       verify_object_mode_(kVerifyObjectModeDisabled),
       disable_moving_gc_count_(0),
@@ -3428,7 +3423,7 @@
 
 double Heap::HeapGrowthMultiplier() const {
   // If we don't care about pause times we are background, so return 1.0.
-  if (!CareAboutPauseTimes() || IsLowMemoryMode()) {
+  if (!CareAboutPauseTimes()) {
     return 1.0;
   }
   return foreground_heap_growth_multiplier_;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 732c707..f0eada3 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -35,6 +35,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
+#include "dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "image-inl.h"
@@ -1829,12 +1830,12 @@
 
     // Skip multidex locations - These will be checked when we visit their
     // corresponding primary non-multidex location.
-    if (DexFile::IsMultiDexLocation(dex_file_location.c_str())) {
+    if (DexFileLoader::IsMultiDexLocation(dex_file_location.c_str())) {
       continue;
     }
 
     std::vector<uint32_t> checksums;
-    if (!DexFile::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
+    if (!DexFileLoader::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
       *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
                                 "referenced by oat file %s: %s",
                                 dex_file_location.c_str(),
@@ -1855,7 +1856,9 @@
 
     // Verify checksums for any related multidex entries.
     for (size_t i = 1; i < checksums.size(); i++) {
-      std::string multi_dex_location = DexFile::GetMultiDexLocation(i, dex_file_location.c_str());
+      std::string multi_dex_location = DexFileLoader::GetMultiDexLocation(
+          i,
+          dex_file_location.c_str());
       const OatFile::OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(),
                                                                     nullptr,
                                                                     error_msg);
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 2dd4db3..2c8ec47 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -511,7 +511,7 @@
   return true;
 }
 
-size_t IndirectReferenceTable::FreeCapacity() {
+size_t IndirectReferenceTable::FreeCapacity() const {
   return max_entries_ - segment_state_.top_index;
 }
 
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 7daf01c..6675099 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -293,7 +293,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
   // See implementation of EnsureFreeCapacity. We'll only state here how much is trivially free,
   // without recovering holes. Thus this is a conservative estimate.
-  size_t FreeCapacity() REQUIRES_SHARED(Locks::mutator_lock_);
+  size_t FreeCapacity() const;
 
   // Note IrtIterator does not have a read barrier as it's used to visit roots.
   IrtIterator begin() {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index ce06a03..74a7a66 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1751,12 +1751,6 @@
   result->SetL(receiver->AsString()->Intern());
 }
 
-void UnstartedRuntime::UnstartedJNIStringFastIndexOf(
-    Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver,
-    uint32_t* args, JValue* result) {
-  result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1]));
-}
-
 void UnstartedRuntime::UnstartedJNIArrayCreateMultiArray(
     Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
     uint32_t* args, JValue* result) {
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 4791035..e7047c7 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -94,7 +94,6 @@
   V(ObjectNotifyAll, "void java.lang.Object.notifyAll()") \
   V(StringCompareTo, "int java.lang.String.compareTo(java.lang.String)") \
   V(StringIntern, "java.lang.String java.lang.String.intern()") \
-  V(StringFastIndexOf, "int java.lang.String.fastIndexOf(int, int)") \
   V(ArrayCreateMultiArray, "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") \
   V(ArrayCreateObjectArray, "java.lang.Object java.lang.reflect.Array.createObjectArray(java.lang.Class, int)") \
   V(ThrowableNativeFillInStackTrace, "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") \
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 5a16053..73746e1 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -28,6 +28,8 @@
 #include "check_jni.h"
 #include "dex_file-inl.h"
 #include "fault_handler.h"
+#include "gc/allocation_record.h"
+#include "gc/heap.h"
 #include "gc_root-inl.h"
 #include "indirect_reference_table-inl.h"
 #include "jni_internal.h"
@@ -468,7 +470,11 @@
       weak_globals_add_condition_("weak globals add condition",
                                   (CHECK(Locks::jni_weak_globals_lock_ != nullptr),
                                    *Locks::jni_weak_globals_lock_)),
-      env_hooks_() {
+      env_hooks_(),
+      enable_allocation_tracking_delta_(
+          runtime_options.GetOrDefault(RuntimeArgumentMap::GlobalRefAllocStackTraceLimit)),
+      allocation_tracking_enabled_(false),
+      old_allocation_tracking_state_(false) {
   functions = unchecked_functions_;
   SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni));
 }
@@ -583,18 +589,55 @@
   return true;
 }
 
+void JavaVMExt::CheckGlobalRefAllocationTracking() {
+  if (LIKELY(enable_allocation_tracking_delta_ == 0)) {
+    return;
+  }
+  size_t simple_free_capacity = globals_.FreeCapacity();
+  if (UNLIKELY(simple_free_capacity <= enable_allocation_tracking_delta_)) {
+    if (!allocation_tracking_enabled_) {
+      LOG(WARNING) << "Global reference storage appears close to exhaustion, program termination "
+                   << "may be imminent. Enabling allocation tracking to improve abort diagnostics. "
+                   << "This will result in program slow-down.";
+
+      old_allocation_tracking_state_ = runtime_->GetHeap()->IsAllocTrackingEnabled();
+      if (!old_allocation_tracking_state_) {
+        // Need to be guaranteed suspended.
+        ScopedObjectAccess soa(Thread::Current());
+        ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
+        gc::AllocRecordObjectMap::SetAllocTrackingEnabled(true);
+      }
+      allocation_tracking_enabled_ = true;
+    }
+  } else {
+    if (UNLIKELY(allocation_tracking_enabled_)) {
+      if (!old_allocation_tracking_state_) {
+        // Need to be guaranteed suspended.
+        ScopedObjectAccess soa(Thread::Current());
+        ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
+        gc::AllocRecordObjectMap::SetAllocTrackingEnabled(false);
+      }
+      allocation_tracking_enabled_ = false;
+    }
+  }
+}
+
 jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
   // Check for null after decoding the object to handle cleared weak globals.
   if (obj == nullptr) {
     return nullptr;
   }
-  WriterMutexLock mu(self, *Locks::jni_globals_lock_);
+  IndirectRef ref;
   std::string error_msg;
-  IndirectRef ref = globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  {
+    WriterMutexLock mu(self, *Locks::jni_globals_lock_);
+    ref = globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  }
   if (UNLIKELY(ref == nullptr)) {
     LOG(FATAL) << error_msg;
     UNREACHABLE();
   }
+  CheckGlobalRefAllocationTracking();
   return reinterpret_cast<jobject>(ref);
 }
 
@@ -625,11 +668,14 @@
   if (obj == nullptr) {
     return;
   }
-  WriterMutexLock mu(self, *Locks::jni_globals_lock_);
-  if (!globals_.Remove(kIRTFirstSegment, obj)) {
-    LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
-                 << "failed to find entry";
+  {
+    WriterMutexLock mu(self, *Locks::jni_globals_lock_);
+    if (!globals_.Remove(kIRTFirstSegment, obj)) {
+      LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
+                   << "failed to find entry";
+    }
   }
+  CheckGlobalRefAllocationTracking();
 }
 
 void JavaVMExt::DeleteWeakGlobalRef(Thread* self, jweak obj) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index b767b19..0510d6a 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -211,6 +211,8 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(Locks::jni_weak_globals_lock_);
 
+  void CheckGlobalRefAllocationTracking();
+
   Runtime* const runtime_;
 
   // Used for testing. By default, we'll LOG(FATAL) the reason.
@@ -247,6 +249,10 @@
   // TODO Maybe move this to Runtime.
   std::vector<GetEnvHook> env_hooks_;
 
+  size_t enable_allocation_tracking_delta_;
+  std::atomic<bool> allocation_tracking_enabled_;
+  std::atomic<bool> old_allocation_tracking_state_;
+
   DISALLOW_COPY_AND_ASSIGN(JavaVMExt);
 };
 
diff --git a/runtime/java_vm_ext_test.cc b/runtime/java_vm_ext_test.cc
index 2cbfa81..a15ec56 100644
--- a/runtime/java_vm_ext_test.cc
+++ b/runtime/java_vm_ext_test.cc
@@ -19,6 +19,7 @@
 #include <pthread.h>
 
 #include "common_runtime_test.h"
+#include "gc/heap.h"
 #include "java_vm_ext.h"
 #include "runtime.h"
 
@@ -134,4 +135,49 @@
   EXPECT_EQ(JNI_ERR, err);
 }
 
+class JavaVmExtStackTraceTest : public JavaVmExtTest {
+ protected:
+  void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
+    options->emplace_back("-XX:GlobalRefAllocStackTraceLimit=50000", nullptr);
+  }
+};
+
+TEST_F(JavaVmExtStackTraceTest, TestEnableDisable) {
+  ASSERT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
+
+  JNIEnv* env;
+  jint ok = vm_->AttachCurrentThread(&env, nullptr);
+  ASSERT_EQ(JNI_OK, ok);
+
+  std::vector<jobject> global_refs_;
+  jobject local_ref = env->NewStringUTF("Dummy");
+  for (size_t i = 0; i < 2000; ++i) {
+    global_refs_.push_back(env->NewGlobalRef(local_ref));
+  }
+
+  EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
+
+  for (jobject global_ref : global_refs_) {
+    env->DeleteGlobalRef(global_ref);
+  }
+
+  EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
+
+  global_refs_.clear();
+  for (size_t i = 0; i < 2000; ++i) {
+    global_refs_.push_back(env->NewGlobalRef(local_ref));
+  }
+
+  EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
+
+  for (jobject global_ref : global_refs_) {
+    env->DeleteGlobalRef(global_ref);
+  }
+
+  EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
+
+  ok = vm_->DetachCurrentThread();
+  EXPECT_EQ(JNI_OK, ok);
+}
+
 }  // namespace art
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index e122c6d..47615f5 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -26,6 +26,7 @@
 #include "base/time_utils.h"
 #include "cha.h"
 #include "debugger_interface.h"
+#include "dex_file_loader.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/bitmap-inl.h"
 #include "gc/scoped_gc_critical_section.h"
@@ -1350,7 +1351,8 @@
   for (const ProfilingInfo* info : profiling_infos_) {
     ArtMethod* method = info->GetMethod();
     const DexFile* dex_file = method->GetDexFile();
-    if (!ContainsElement(dex_base_locations, dex_file->GetBaseLocation())) {
+    const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+    if (!ContainsElement(dex_base_locations, base_location)) {
       // Skip dex files which are not profiled.
       continue;
     }
@@ -1404,7 +1406,8 @@
           is_missing_types = true;
           continue;
         }
-        if (ContainsElement(dex_base_locations, class_dex_file->GetBaseLocation())) {
+        if (ContainsElement(dex_base_locations,
+                            DexFileLoader::GetBaseLocation(class_dex_file->GetLocation()))) {
           // Only consider classes from the same apk (including multidex).
           profile_classes.emplace_back(/*ProfileMethodInfo::ProfileClassReference*/
               class_dex_file, type_index);
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index f9603a7..19501de 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -40,6 +40,7 @@
 #include "base/systrace.h"
 #include "base/time_utils.h"
 #include "base/unix_file/fd_file.h"
+#include "dex_file_loader.h"
 #include "jit/profiling_info.h"
 #include "os.h"
 #include "safe_map.h"
@@ -1537,7 +1538,7 @@
       os << dex_data->profile_key;
     } else {
       // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
-      std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_data->profile_key);
+      std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key);
       os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
     }
     os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
@@ -1696,7 +1697,7 @@
   const uint16_t kFavorSplit = 2;
 
   for (uint16_t i = 0; i < number_of_dex_files; i++) {
-    std::string dex_location = DexFile::GetMultiDexLocation(i, base_dex_location.c_str());
+    std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
     std::string profile_key = GetProfileDexFileKey(dex_location);
 
     for (uint16_t m = 0; m < number_of_methods; m++) {
@@ -1828,7 +1829,7 @@
 ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
   return &(method_map.FindOrAdd(
       method_index,
-      InlineCacheMap(std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)))->second);
+      InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
 }
 
 // Mark a method as executed at least once.
@@ -1847,7 +1848,7 @@
   if ((flags & MethodHotness::kFlagHot) != 0) {
     method_map.FindOrAdd(
         index,
-        InlineCacheMap(std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
+        InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
   }
   return true;
 }
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 8889b34..8dbb43f 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -434,7 +434,7 @@
                 uint32_t location_checksum,
                 uint16_t index,
                 uint32_t num_methods)
-        : arena_(allocator),
+        : allocator_(allocator),
           profile_key(key),
           profile_index(index),
           checksum(location_checksum),
@@ -466,8 +466,8 @@
 
     MethodHotness GetHotnessInfo(uint32_t dex_method_index) const;
 
-    // The arena used to allocate new inline cache maps.
-    ArenaAllocator* arena_;
+    // The allocator used to allocate new inline cache maps.
+    ArenaAllocator* const allocator_;
     // The profile key this data belongs to.
     std::string profile_key;
     // The profile index of this dex file (matches ClassReference#dex_profile_index).
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index 2cb8294..f155d7e 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -39,7 +39,7 @@
 class ProfileCompilationInfoTest : public CommonRuntimeTest {
  public:
   void PostRuntimeCreate() OVERRIDE {
-    arena_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
+    allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
   }
 
  protected:
@@ -176,7 +176,7 @@
   // Creates an inline cache which will be destructed at the end of the test.
   ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
     used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
-        std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
+        std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
     return used_inline_caches.back().get();
   }
 
@@ -188,7 +188,7 @@
     for (const auto& inline_cache : pmi.inline_caches) {
       ProfileCompilationInfo::DexPcData& dex_pc_data =
           ic_map->FindOrAdd(
-              inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(arena_.get()))->second;
+              inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
       if (inline_cache.is_missing_types) {
         dex_pc_data.SetIsMissingTypes();
       }
@@ -215,13 +215,13 @@
 
     // Monomorphic
     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.AddClass(0, dex::TypeIndex(0));
       ic_map->Put(dex_pc, dex_pc_data);
     }
     // Polymorphic
     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.AddClass(0, dex::TypeIndex(0));
       dex_pc_data.AddClass(1, dex::TypeIndex(1));
       dex_pc_data.AddClass(2, dex::TypeIndex(2));
@@ -230,13 +230,13 @@
     }
     // Megamorphic
     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.SetIsMegamorphic();
       ic_map->Put(dex_pc, dex_pc_data);
     }
     // Missing types
     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
       dex_pc_data.SetIsMissingTypes();
       ic_map->Put(dex_pc, dex_pc_data);
     }
@@ -273,7 +273,7 @@
   static constexpr int kProfileMagicSize = 4;
   static constexpr int kProfileVersionSize = 4;
 
-  std::unique_ptr<ArenaAllocator> arena_;
+  std::unique_ptr<ArenaAllocator> allocator_;
 
   // Cache of inline caches generated during tests.
   // This makes it easier to pass data between different utilities and ensure that
@@ -730,7 +730,7 @@
   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
   pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
-    ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+    ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
     dex_pc_data.AddClass(0, dex::TypeIndex(0));
     dex_pc_data.AddClass(1, dex::TypeIndex(1));
     ic_map->Put(dex_pc, dex_pc_data);
@@ -741,7 +741,7 @@
   pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
   pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
-    ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+    ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
     dex_pc_data.AddClass(1, dex::TypeIndex(0));
     dex_pc_data.AddClass(0, dex::TypeIndex(1));
     ic_map_reindexed->Put(dex_pc, dex_pc_data);
@@ -795,7 +795,7 @@
   ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
   ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+  ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   dex_pc_data.SetIsMegamorphic();
   ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
 
@@ -825,7 +825,7 @@
   ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
   ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
+  ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   dex_pc_data.SetIsMissingTypes();
   ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 2bf8d8b..01853de 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -31,6 +31,7 @@
 #include "base/time_utils.h"
 #include "class_table-inl.h"
 #include "compiler_filter.h"
+#include "dex_file_loader.h"
 #include "dex_reference_collection.h"
 #include "gc/collector_type.h"
 #include "gc/gc_cause.h"
@@ -414,7 +415,8 @@
     const std::set<std::string>& locations = it.second;
     for (const auto& pair : hot_methods.GetMap()) {
       const DexFile* const dex_file = pair.first;
-      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+      const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+      if (locations.find(base_location) != locations.end()) {
         const MethodReferenceCollection::IndexVector& indices = pair.second;
         uint8_t flags = Hotness::kFlagHot;
         flags |= startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup;
@@ -427,7 +429,8 @@
     }
     for (const auto& pair : sampled_methods.GetMap()) {
       const DexFile* const dex_file = pair.first;
-      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+      const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+      if (locations.find(base_location) != locations.end()) {
         const MethodReferenceCollection::IndexVector& indices = pair.second;
         cached_info->AddMethodsForDex(startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup,
                                       dex_file,
@@ -437,14 +440,15 @@
     }
     for (const auto& pair : resolved_classes.GetMap()) {
       const DexFile* const dex_file = pair.first;
-      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+      const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+      if (locations.find(base_location) != locations.end()) {
         const TypeReferenceCollection::IndexVector& classes = pair.second;
         VLOG(profiler) << "Added " << classes.size() << " classes for location "
-                       << dex_file->GetBaseLocation()
+                       << base_location
                        << " (" << dex_file->GetLocation() << ")";
         cached_info->AddClassesForDex(dex_file, classes.begin(), classes.end());
       } else {
-        VLOG(profiler) << "Location not found " << dex_file->GetBaseLocation()
+        VLOG(profiler) << "Location not found " << base_location
                        << " (" << dex_file->GetLocation() << ")";
       }
     }
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index d40e6d9..e75d097 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -26,6 +26,7 @@
 #include "common_throws.h"
 #include "compiler_filter.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
@@ -185,12 +186,12 @@
                                       dex_mem_map->Begin(),
                                       dex_mem_map->End());
   std::string error_message;
-  std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
-                                                        0,
-                                                        std::move(dex_mem_map),
-                                                        /* verify */ true,
-                                                        /* verify_location */ true,
-                                                        &error_message));
+  std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
+                                                              0,
+                                                              std::move(dex_mem_map),
+                                                              /* verify */ true,
+                                                              /* verify_location */ true,
+                                                              &error_message));
   if (dex_file == nullptr) {
     ScopedObjectAccess soa(env);
     ThrowWrappedIOException("%s", error_message.c_str());
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index e2de141..67f7c51 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -68,13 +68,6 @@
   return reinterpret_cast<jstring>(string_original);
 }
 
-static jint String_fastIndexOf(JNIEnv* env, jobject java_this, jint ch, jint start) {
-  ScopedFastNativeObjectAccess soa(env);
-  // This method does not handle supplementary characters. They're dealt with in managed code.
-  DCHECK_LE(ch, 0xffff);
-  return soa.Decode<mirror::String>(java_this)->FastIndexOf(ch, start);
-}
-
 static jstring String_fastSubstring(JNIEnv* env, jobject java_this, jint start, jint length) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
@@ -121,7 +114,6 @@
   FAST_NATIVE_METHOD(String, compareTo, "(Ljava/lang/String;)I"),
   FAST_NATIVE_METHOD(String, concat, "(Ljava/lang/String;)Ljava/lang/String;"),
   FAST_NATIVE_METHOD(String, doReplace, "(CC)Ljava/lang/String;"),
-  FAST_NATIVE_METHOD(String, fastIndexOf, "(II)I"),
   FAST_NATIVE_METHOD(String, fastSubstring, "(II)Ljava/lang/String;"),
   FAST_NATIVE_METHOD(String, getCharsNoCheck, "(II[CI)V"),
   FAST_NATIVE_METHOD(String, intern, "()Ljava/lang/String;"),
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 4034e8c..413149c 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -17,6 +17,7 @@
 #include "java_lang_VMClassLoader.h"
 
 #include "class_linker.h"
+#include "dex_file_loader.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
@@ -135,7 +136,7 @@
     const DexFile* dex_file = path[i];
 
     // For multidex locations, e.g., x.jar!classes2.dex, we want to look into x.jar.
-    const std::string& location(dex_file->GetBaseLocation());
+    const std::string location(DexFileLoader::GetBaseLocation(dex_file->GetLocation()));
 
     ScopedLocalRef<jstring> javaPath(env, env->NewStringUTF(location.c_str()));
     if (javaPath.get() == nullptr) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 3f4cb94..781ddd7 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -26,6 +26,7 @@
 #include <cstring>
 #include <sstream>
 #include <type_traits>
+#include <sys/stat.h>
 
 // dlopen_ext support from bionic.
 #ifdef ART_TARGET_ANDROID
@@ -41,6 +42,7 @@
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file_types.h"
+#include "dex_file_loader.h"
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "gc_root.h"
@@ -53,6 +55,7 @@
 #include "oat_file_manager.h"
 #include "os.h"
 #include "runtime.h"
+#include "standard_dex_file.h"
 #include "type_lookup_table.h"
 #include "utf-inl.h"
 #include "utils.h"
@@ -74,9 +77,6 @@
 // For debugging, Open will print DlOpen error message if set to true.
 static constexpr bool kPrintDlOpenErrorMessage = false;
 
-// If true, we advise the kernel about dex file mem map accesses.
-static constexpr bool kMadviseDexFileAccesses = true;
-
 // Note for OatFileBase and descendents:
 //
 // These are used in OatFile::Open to try all our loaders.
@@ -105,6 +105,19 @@
                                   const char* abs_dex_location,
                                   std::string* error_msg);
 
+  template <typename kOatFileBaseSubType>
+  static OatFileBase* OpenOatFile(int vdex_fd,
+                                  int oat_fd,
+                                  const std::string& vdex_filename,
+                                  const std::string& oat_filename,
+                                  uint8_t* requested_base,
+                                  uint8_t* oat_file_begin,
+                                  bool writable,
+                                  bool executable,
+                                  bool low_4gb,
+                                  const char* abs_dex_location,
+                                  std::string* error_msg);
+
  protected:
   OatFileBase(const std::string& filename, bool executable) : OatFile(filename, executable) {}
 
@@ -118,6 +131,12 @@
                 bool low_4gb,
                 std::string* error_msg);
 
+  bool LoadVdex(int vdex_fd,
+                const std::string& vdex_filename,
+                bool writable,
+                bool low_4gb,
+                std::string* error_msg);
+
   virtual bool Load(const std::string& elf_filename,
                     uint8_t* oat_file_begin,
                     bool writable,
@@ -125,6 +144,13 @@
                     bool low_4gb,
                     std::string* error_msg) = 0;
 
+  virtual bool Load(int oat_fd,
+                    uint8_t* oat_file_begin,
+                    bool writable,
+                    bool executable,
+                    bool low_4gb,
+                    std::string* error_msg) = 0;
+
   bool ComputeFields(uint8_t* requested_base,
                      const std::string& file_path,
                      std::string* error_msg);
@@ -192,6 +218,46 @@
   return ret.release();
 }
 
+template <typename kOatFileBaseSubType>
+OatFileBase* OatFileBase::OpenOatFile(int vdex_fd,
+                                      int oat_fd,
+                                      const std::string& vdex_location,
+                                      const std::string& oat_location,
+                                      uint8_t* requested_base,
+                                      uint8_t* oat_file_begin,
+                                      bool writable,
+                                      bool executable,
+                                      bool low_4gb,
+                                      const char* abs_dex_location,
+                                      std::string* error_msg) {
+  std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
+
+  if (kIsVdexEnabled && !ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
+    return nullptr;
+  }
+
+  if (!ret->Load(oat_fd,
+                 oat_file_begin,
+                 writable,
+                 executable,
+                 low_4gb,
+                 error_msg)) {
+    return nullptr;
+  }
+
+  if (!ret->ComputeFields(requested_base, oat_location, error_msg)) {
+    return nullptr;
+  }
+
+  ret->PreSetup(oat_location);
+
+  if (!ret->Setup(abs_dex_location, error_msg)) {
+    return nullptr;
+  }
+
+  return ret.release();
+}
+
 bool OatFileBase::LoadVdex(const std::string& vdex_filename,
                            bool writable,
                            bool low_4gb,
@@ -206,6 +272,33 @@
   return true;
 }
 
+bool OatFileBase::LoadVdex(int vdex_fd,
+                           const std::string& vdex_filename,
+                           bool writable,
+                           bool low_4gb,
+                           std::string* error_msg) {
+  if (vdex_fd != -1) {
+    struct stat s;
+    int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd, &s));
+    if (rc == -1) {
+      PLOG(WARNING) << "Failed getting length of vdex file";
+    } else {
+      vdex_ = VdexFile::Open(vdex_fd,
+                             s.st_size,
+                             vdex_filename,
+                             writable,
+                             low_4gb,
+                             false /* unquicken */,
+                             error_msg);
+      if (vdex_.get() == nullptr) {
+        *error_msg = "Failed opening vdex file.";
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 bool OatFileBase::ComputeFields(uint8_t* requested_base,
                                 const std::string& file_path,
                                 std::string* error_msg) {
@@ -458,7 +551,9 @@
     }
 
     const uint8_t* dex_file_pointer = DexBegin() + dex_file_offset;
-    if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
+
+    const bool valid_magic = StandardDexFile::IsMagicValid(dex_file_pointer);
+    if (UNLIKELY(!valid_magic)) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
                                     "dex file magic '%s'",
                                 GetLocation().c_str(),
@@ -467,7 +562,7 @@
                                 dex_file_pointer);
       return false;
     }
-    if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
+    if (UNLIKELY(!StandardDexFile::IsVersionValid(dex_file_pointer))) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
                                     "dex file version '%s'",
                                 GetLocation().c_str(),
@@ -611,7 +706,8 @@
                reinterpret_cast<const DexFile::Header*>(dex_file_pointer)->method_ids_size_);
     }
 
-    std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
+    std::string canonical_location =
+        DexFileLoader::GetDexCanonicalLocation(dex_file_location.c_str());
 
     // Create the OatDexFile and add it to the owning container.
     OatDexFile* oat_dex_file = new OatDexFile(this,
@@ -712,6 +808,10 @@
             bool low_4gb,
             std::string* error_msg) OVERRIDE;
 
+  bool Load(int, uint8_t*, bool, bool, bool, std::string*) {
+    return false;
+  }
+
   // Ask the linker where it mmaped the file and notify our mmap wrapper of the regions.
   void PreSetup(const std::string& elf_filename) OVERRIDE;
 
@@ -973,6 +1073,13 @@
             bool low_4gb,
             std::string* error_msg) OVERRIDE;
 
+  bool Load(int oat_fd,
+            uint8_t* oat_file_begin,  // Override where the file is loaded to if not null
+            bool writable,
+            bool executable,
+            bool low_4gb,
+            std::string* error_msg) OVERRIDE;
+
   void PreSetup(const std::string& elf_filename ATTRIBUTE_UNUSED) OVERRIDE {
   }
 
@@ -1065,6 +1172,31 @@
                                  error_msg);
 }
 
+bool ElfOatFile::Load(int oat_fd,
+                      uint8_t* oat_file_begin,  // Override where the file is loaded to if not null
+                      bool writable,
+                      bool executable,
+                      bool low_4gb,
+                      std::string* error_msg) {
+  ScopedTrace trace(__PRETTY_FUNCTION__);
+  if (oat_fd != -1) {
+    std::unique_ptr<File> file = std::make_unique<File>(oat_fd, false);
+    file->DisableAutoClose();
+    if (file == nullptr) {
+      *error_msg = StringPrintf("Failed to open oat filename for reading: %s",
+                                strerror(errno));
+      return false;
+    }
+    return ElfOatFile::ElfFileOpen(file.get(),
+                                   oat_file_begin,
+                                   writable,
+                                   executable,
+                                   low_4gb,
+                                   error_msg);
+  }
+  return false;
+}
+
 bool ElfOatFile::ElfFileOpen(File* file,
                              uint8_t* oat_file_begin,
                              bool writable,
@@ -1096,8 +1228,8 @@
       const char* abs_dex_location, const std::string& rel_dex_location) {
   if (abs_dex_location != nullptr && rel_dex_location[0] != '/') {
     // Strip :classes<N>.dex used for secondary multidex files.
-    std::string base = DexFile::GetBaseLocation(rel_dex_location);
-    std::string multidex_suffix = DexFile::GetMultiDexSuffix(rel_dex_location);
+    std::string base = DexFileLoader::GetBaseLocation(rel_dex_location);
+    std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(rel_dex_location);
 
     // Check if the base is a suffix of the provided abs_dex_location.
     std::string target_suffix = "/" + base;
@@ -1194,6 +1326,33 @@
   return with_internal;
 }
 
+OatFile* OatFile::Open(int vdex_fd,
+                       int oat_fd,
+                       const std::string& oat_location,
+                       uint8_t* requested_base,
+                       uint8_t* oat_file_begin,
+                       bool executable,
+                       bool low_4gb,
+                       const char* abs_dex_location,
+                       std::string* error_msg) {
+  CHECK(!oat_location.empty()) << oat_location;
+
+  std::string vdex_location = GetVdexFilename(oat_location);
+
+  OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(vdex_fd,
+                                                                oat_fd,
+                                                                vdex_location,
+                                                                oat_location,
+                                                                requested_base,
+                                                                oat_file_begin,
+                                                                false /* writable */,
+                                                                executable,
+                                                                low_4gb,
+                                                                abs_dex_location,
+                                                                error_msg);
+  return with_internal;
+}
+
 OatFile* OatFile::OpenWritable(File* file,
                                const std::string& location,
                                const char* abs_dex_location,
@@ -1324,7 +1483,7 @@
       oat_dex_file = secondary_lb->second;  // May be null.
     } else {
       // We haven't seen this dex_location before, we must check the canonical location.
-      std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+      std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
       if (dex_canonical_location != dex_location) {
         StringPiece canonical_key(dex_canonical_location);
         auto canonical_it = oat_dex_files_.find(canonical_key);
@@ -1342,7 +1501,7 @@
 
   if (oat_dex_file == nullptr) {
     if (error_msg != nullptr) {
-      std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+      std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
       *error_msg = "Failed to find OatDexFile for DexFile " + std::string(dex_location)
           + " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation();
     }
@@ -1352,7 +1511,7 @@
   if (dex_location_checksum != nullptr &&
       oat_dex_file->GetDexFileLocationChecksum() != *dex_location_checksum) {
     if (error_msg != nullptr) {
-      std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+      std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
       std::string checksum = StringPrintf("0x%08x", oat_dex_file->GetDexFileLocationChecksum());
       std::string required_checksum = StringPrintf("0x%08x", *dex_location_checksum);
       *error_msg = "OatDexFile for DexFile " + std::string(dex_location)
@@ -1408,14 +1567,14 @@
   ScopedTrace trace(__PRETTY_FUNCTION__);
   static constexpr bool kVerify = false;
   static constexpr bool kVerifyChecksum = false;
-  return DexFile::Open(dex_file_pointer_,
-                       FileSize(),
-                       dex_file_location_,
-                       dex_file_location_checksum_,
-                       this,
-                       kVerify,
-                       kVerifyChecksum,
-                       error_msg);
+  return DexFileLoader::Open(dex_file_pointer_,
+                             FileSize(),
+                             dex_file_location_,
+                             dex_file_location_checksum_,
+                             this,
+                             kVerify,
+                             kVerifyChecksum,
+                             error_msg);
 }
 
 uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
@@ -1489,20 +1648,19 @@
 
 // Madvise the dex file based on the state we are moving to.
 void OatDexFile::MadviseDexFile(const DexFile& dex_file, MadviseState state) {
-  const bool low_ram = Runtime::Current()->GetHeap()->IsLowMemoryMode();
+  Runtime* const runtime = Runtime::Current();
+  const bool low_ram = runtime->GetHeap()->IsLowMemoryMode();
   // TODO: Also do madvise hints for non low ram devices.
-  if (!kMadviseDexFileAccesses || !low_ram) {
+  if (!low_ram) {
     return;
   }
-  if (state == MadviseState::kMadviseStateAtLoad) {
-    if (low_ram) {
-      // Default every dex file to MADV_RANDOM when its loaded by default for low ram devices.
-      // Other devices have enough page cache to get performance benefits from loading more pages
-      // into the page cache.
-      MadviseLargestPageAlignedRegion(dex_file.Begin(),
-                                      dex_file.Begin() + dex_file.Size(),
-                                      MADV_RANDOM);
-    }
+  if (state == MadviseState::kMadviseStateAtLoad && runtime->MAdviseRandomAccess()) {
+    // Default every dex file to MADV_RANDOM when its loaded by default for low ram devices.
+    // Other devices have enough page cache to get performance benefits from loading more pages
+    // into the page cache.
+    MadviseLargestPageAlignedRegion(dex_file.Begin(),
+                                    dex_file.Begin() + dex_file.Size(),
+                                    MADV_RANDOM);
   }
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   if (oat_dex_file != nullptr) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 04cb3a0..7d4e6df 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -89,6 +89,18 @@
                        const char* abs_dex_location,
                        std::string* error_msg);
 
+  // Similar to OatFile::Open(const std::string...), but accepts input vdex and
+  // odex files as file descriptors.
+  static OatFile* Open(int vdex_fd,
+                       int oat_fd,
+                       const std::string& oat_location,
+                       uint8_t* requested_base,
+                       uint8_t* oat_file_begin,
+                       bool executable,
+                       bool low_4gb,
+                       const char* abs_dex_location,
+                       std::string* error_msg);
+
   // Open an oat file from an already opened File.
   // Does not use dlopen underneath so cannot be used for runtime use
   // where relocations may be required. Currently used from
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f3a0725..a7fe9b1 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -27,6 +27,7 @@
 #include "base/stl_util.h"
 #include "class_linker.h"
 #include "compiler_filter.h"
+#include "dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
@@ -69,7 +70,9 @@
 
 OatFileAssistant::OatFileAssistant(const char* dex_location,
                                    const InstructionSet isa,
-                                   bool load_executable)
+                                   bool load_executable,
+                                   int vdex_fd,
+                                   int oat_fd)
     : isa_(isa),
       load_executable_(load_executable),
       odex_(this, /*is_oat_location*/ false),
@@ -109,7 +112,7 @@
   std::string error_msg;
   std::string odex_file_name;
   if (DexLocationToOdexFilename(dex_location_, isa_, &odex_file_name, &error_msg)) {
-    odex_.Reset(odex_file_name);
+    odex_.Reset(odex_file_name, vdex_fd, oat_fd);
   } else {
     LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
   }
@@ -132,7 +135,7 @@
     LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
   } else {
     std::string parent = dex_location_.substr(0, pos);
-    if (access(parent.c_str(), W_OK) == 0) {
+    if (access(parent.c_str(), W_OK) == 0 || oat_fd > 0) {
       dex_parent_writable_ = true;
     } else {
       VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
@@ -349,7 +352,7 @@
 
   // Load the rest of the multidex entries
   for (size_t i = 1;; i++) {
-    std::string multidex_dex_location = DexFile::GetMultiDexLocation(i, dex_location.c_str());
+    std::string multidex_dex_location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
     oat_dex_file = oat_file.GetOatDexFile(multidex_dex_location.c_str(), nullptr);
     if (oat_dex_file == nullptr) {
       // There are no more multidex entries to load.
@@ -401,7 +404,7 @@
     uint32_t expected_checksum = (*required_dex_checksums)[i];
     uint32_t actual_checksum = file.GetLocationChecksum(i);
     if (expected_checksum != actual_checksum) {
-      std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+      std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
       *error_msg = StringPrintf("Dex checksum does not match for dex: %s."
                                 "Expected: %u, actual: %u",
                                 dex.c_str(),
@@ -430,7 +433,7 @@
   }
 
   for (uint32_t i = 0; i < number_of_dex_files; i++) {
-    std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+    std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
     uint32_t expected_checksum = (*required_dex_checksums)[i];
     const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr);
     if (oat_dex_file == nullptr) {
@@ -863,9 +866,9 @@
     required_dex_checksums_found_ = false;
     cached_required_dex_checksums_.clear();
     std::string error_msg;
-    if (DexFile::GetMultiDexChecksums(dex_location_.c_str(),
-                                      &cached_required_dex_checksums_,
-                                      &error_msg)) {
+    if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(),
+                                            &cached_required_dex_checksums_,
+                                            &error_msg)) {
       required_dex_checksums_found_ = true;
       has_original_dex_files_ = true;
     } else {
@@ -879,7 +882,7 @@
       if (odex_file != nullptr) {
         required_dex_checksums_found_ = true;
         for (size_t i = 0; i < odex_file->GetOatHeader().GetDexFileCount(); i++) {
-          std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+          std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
           const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(dex.c_str(), nullptr);
           if (odex_dex_file == nullptr) {
             required_dex_checksums_found_ = false;
@@ -1016,11 +1019,28 @@
       // Check to see if there is a vdex file we can make use of.
       std::string error_msg;
       std::string vdex_filename = GetVdexFilename(filename_);
-      std::unique_ptr<VdexFile> vdex = VdexFile::Open(vdex_filename,
-                                                      /*writeable*/false,
-                                                      /*low_4gb*/false,
-                                                      /*unquicken*/false,
-                                                      &error_msg);
+      std::unique_ptr<VdexFile> vdex;
+      if (vdex_fd_ == -1) {
+        vdex = VdexFile::Open(vdex_filename,
+                              false /*writeable*/,
+                              false /*low_4gb*/,
+                              false /*unquicken*/,
+                              &error_msg);
+      } else {
+        struct stat s;
+        int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
+        if (rc == -1) {
+          PLOG(WARNING) << "Failed getting length of vdex file";
+        } else {
+          vdex = VdexFile::Open(vdex_fd_,
+                                s.st_size,
+                                vdex_filename,
+                                false /*writable*/,
+                                false /*low_4gb*/,
+                                false /* unquicken */,
+                                &error_msg);
+        }
+      }
       if (vdex == nullptr) {
         status_ = kOatCannotOpen;
         VLOG(oat) << "unable to open vdex file " << vdex_filename << ": " << error_msg;
@@ -1095,14 +1115,26 @@
     load_attempted_ = true;
     if (filename_provided_) {
       std::string error_msg;
-      file_.reset(OatFile::Open(filename_.c_str(),
-                                filename_.c_str(),
-                                nullptr,
-                                nullptr,
-                                oat_file_assistant_->load_executable_,
-                                /*low_4gb*/false,
-                                oat_file_assistant_->dex_location_.c_str(),
-                                &error_msg));
+      if (oat_fd_ != -1 && vdex_fd_ != -1) {
+        file_.reset(OatFile::Open(vdex_fd_,
+                                  oat_fd_,
+                                  filename_.c_str(),
+                                  nullptr,
+                                  nullptr,
+                                  oat_file_assistant_->load_executable_,
+                                  false /* low_4gb */,
+                                  oat_file_assistant_->dex_location_.c_str(),
+                                  &error_msg));
+      } else {
+        file_.reset(OatFile::Open(filename_.c_str(),
+                                  filename_.c_str(),
+                                  nullptr,
+                                  nullptr,
+                                  oat_file_assistant_->load_executable_,
+                                  false /* low_4gb */,
+                                  oat_file_assistant_->dex_location_.c_str(),
+                                  &error_msg));
+      }
       if (file_.get() == nullptr) {
         VLOG(oat) << "OatFileAssistant test for existing oat file "
           << filename_ << ": " << error_msg;
@@ -1169,9 +1201,12 @@
   status_attempted_ = false;
 }
 
-void OatFileAssistant::OatFileInfo::Reset(const std::string& filename) {
+void OatFileAssistant::OatFileInfo::Reset(const std::string& filename, int vdex_fd,
+                                          int oat_fd) {
   filename_provided_ = true;
   filename_ = filename;
+  vdex_fd_ = vdex_fd;
+  oat_fd_ = oat_fd;
   Reset();
 }
 
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 6dc3c19..0f74ca4 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -121,7 +121,9 @@
   // executable code for this dex location.
   OatFileAssistant(const char* dex_location,
                    const InstructionSet isa,
-                   bool load_executable);
+                   bool load_executable,
+                   int vdex_fd = -1,
+                   int oat_fd = -1);
 
   ~OatFileAssistant();
 
@@ -349,7 +351,7 @@
 
     // Clear any cached information and switch to getting info about the oat
     // file with the given filename.
-    void Reset(const std::string& filename);
+    void Reset(const std::string& filename, int vdex_fd = -1, int oat_fd = -1);
 
     // Release the loaded oat file for runtime use.
     // Returns null if the oat file hasn't been loaded or is out of date.
@@ -386,6 +388,9 @@
     bool filename_provided_ = false;
     std::string filename_;
 
+    int oat_fd_ = -1;
+    int vdex_fd_ = -1;
+
     bool load_attempted_ = false;
     std::unique_ptr<OatFile> file_;
 
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 3ecd1b5..d99036d 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -20,6 +20,7 @@
 
 #include <string>
 #include <vector>
+#include <fcntl.h>
 
 #include <gtest/gtest.h>
 
@@ -222,6 +223,125 @@
   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
 }
 
+// Case: Passing valid file descriptors of updated odex/vdex filesalong with
+// the dex file.
+// Expect: The status is kNoDexOptNeeded.
+TEST_F(OatFileAssistantTest, GetDexOptNeededWithFd) {
+  std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
+  std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
+  std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
+
+  Copy(GetDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str(),
+                     odex_location.c_str(),
+                     CompilerFilter::kSpeed,
+                     true,
+                     false,
+                     false);
+
+  android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
+  android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      false,
+                                      vdex_fd.get(),
+                                      odex_fd.get());
+  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
+  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
+  EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+
+  EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: Passing valid odex fd, however, invalid fd for vdex with
+// the dex file.
+// Expect: The status is kDex2oatFromScratch.
+TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
+  std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
+  std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
+
+  Copy(GetDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str(),
+                     odex_location.c_str(),
+                     CompilerFilter::kSpeed,
+                     true,
+                     false,
+                     false);
+
+  android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY));
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      false,
+                                      -1,
+                                      odex_fd.get());
+  EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+}
+
+// Case: Passing valid vdex fd, however, invalid fd for odex with
+// the dex file.
+// Expect: The status is kDex2oatFromScratch.
+TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) {
+  std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
+  std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
+  std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
+
+  Copy(GetDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str(),
+                     odex_location.c_str(),
+                     CompilerFilter::kSpeed,
+                     true,
+                     false,
+                     false);
+
+  android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY));
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      false,
+                                      vdex_fd.get(),
+                                      -1);
+  // Even though the vdex file is up to date, because we don't have the oat
+  // file, we can't know that the vdex depends on the boot image and is up to
+  // date with respect to the boot image. Instead we must assume the vdex file
+  // depends on the boot image and is out of date with respect to the boot
+  // image.
+  EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+  EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+}
+
+// Case: Passing invalid vdex and odex fd with the dex file.
+// Expect: The status is kDex2oatFromScratch.
+TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) {
+  std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
+
+  Copy(GetDexSrc1(), dex_location);
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      false,
+                                      -1,
+                                      -1);
+  EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+}
+
 // Case: We have a DEX file and up-to-date OAT file for it. We load the dex file
 // via a symlink.
 // Expect: The status is kNoDexOptNeeded.
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 66b24a9..1e7cf72 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -31,6 +31,7 @@
 #include "class_linker.h"
 #include "class_loader_context.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "dex_file_tracking_registrar.h"
 #include "gc/scoped_gc_critical_section.h"
 #include "gc/space/image_space.h"
@@ -94,7 +95,7 @@
   for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
     const std::vector<const OatDexFile*>& oat_dex_files = oat_file->GetOatDexFiles();
     for (const OatDexFile* oat_dex_file : oat_dex_files) {
-      if (DexFile::GetBaseLocation(oat_dex_file->GetDexFileLocation()) == dex_base_location) {
+      if (DexFileLoader::GetBaseLocation(oat_dex_file->GetDexFileLocation()) == dex_base_location) {
         return oat_file.get();
       }
     }
@@ -596,7 +597,7 @@
     if (oat_file_assistant.HasOriginalDexFiles()) {
       if (Runtime::Current()->IsDexFileFallbackEnabled()) {
         static constexpr bool kVerifyChecksum = true;
-        if (!DexFile::Open(
+        if (!DexFileLoader::Open(
             dex_location, dex_location, kVerifyChecksum, /*out*/ &error_msg, &dex_files)) {
           LOG(WARNING) << error_msg;
           error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index 4162873..9a66983 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -28,6 +28,10 @@
 
 constexpr bool kObjPtrPoisoning = kIsDebugBuild;
 
+// It turns out that most of the performance overhead comes from copying. Don't validate for now.
+// This defers finding stale ObjPtr objects until they are used.
+constexpr bool kObjPtrPoisoningValidateOnCopy = false;
+
 // Value type representing a pointer to a mirror::Object of type MirrorType
 // Since the cookie is thread based, it is not safe to share an ObjPtr between threads.
 template<class MirrorType>
@@ -63,14 +67,18 @@
             typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type>
   ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other)  // NOLINT
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) {
+      : reference_(kObjPtrPoisoningValidateOnCopy
+                       ? Encode(static_cast<MirrorType*>(other.Ptr()))
+                       : other.reference_) {
   }
 
   template <typename Type,
             typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type>
   ALWAYS_INLINE ObjPtr& operator=(const ObjPtr<Type>& other)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    reference_ = Encode(static_cast<MirrorType*>(other.Ptr()));
+    reference_ = kObjPtrPoisoningValidateOnCopy
+                     ? Encode(static_cast<MirrorType*>(other.Ptr()))
+                     : other.reference_;
     return *this;
   }
 
@@ -160,6 +168,8 @@
   ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_);
   // The encoded reference and cookie.
   uintptr_t reference_;
+
+  template <class T> friend class ObjPtr;  // Required for reference_ access in copy cons/operator.
 };
 
 static_assert(std::is_trivially_copyable<ObjPtr<void>>::value,
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 1d524fd..71d7b6c 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -121,7 +121,7 @@
           .WithType<double>().WithRange(0.1, 0.9)
           .IntoKey(M::HeapTargetUtilization)
       .Define("-XX:ForegroundHeapGrowthMultiplier=_")
-          .WithType<double>().WithRange(0.1, 1.0)
+          .WithType<double>().WithRange(0.1, 5.0)
           .IntoKey(M::ForegroundHeapGrowthMultiplier)
       .Define("-XX:ParallelGCThreads=_")
           .WithType<unsigned int>()
@@ -159,6 +159,10 @@
           .WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
           .IntoKey(M::DumpNativeStackOnSigQuit)
+      .Define("-XX:MadviseRandomAccess:_")
+          .WithType<bool>()
+          .WithValueMap({{"false", false}, {"true", true}})
+          .IntoKey(M::MadviseRandomAccess)
       .Define("-Xusejit:_")
           .WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
@@ -310,6 +314,9 @@
       .Define("-XX:ThreadSuspendTimeout=_")  // in ms
           .WithType<MillisecondsToNanoseconds>()  // store as ns
           .IntoKey(M::ThreadSuspendTimeout)
+      .Define("-XX:GlobalRefAllocStackTraceLimit=_")  // Number of free slots to enable tracing.
+          .WithType<unsigned int>()
+          .IntoKey(M::GlobalRefAllocStackTraceLimit)
       .Define("-XX:SlowDebug=_")
           .WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
@@ -714,6 +721,7 @@
   UsageMessage(stream, "  -XX:LargeObjectSpace={disabled,map,freelist}\n");
   UsageMessage(stream, "  -XX:LargeObjectThreshold=N\n");
   UsageMessage(stream, "  -XX:DumpNativeStackOnSigQuit=booleanvalue\n");
+  UsageMessage(stream, "  -XX:MadviseRandomAccess:booleanvalue\n");
   UsageMessage(stream, "  -XX:SlowDebug={false,true}\n");
   UsageMessage(stream, "  -Xmethod-trace\n");
   UsageMessage(stream, "  -Xmethod-trace-file:filename");
diff --git a/runtime/plugin.cc b/runtime/plugin.cc
index 731967c..6aa0787 100644
--- a/runtime/plugin.cc
+++ b/runtime/plugin.cc
@@ -74,10 +74,8 @@
     LOG(WARNING) << this << " does not include a deinitialization function";
   }
   dlopen_handle_ = nullptr;
-  if (dlclose(handle) != 0) {
-    LOG(ERROR) << this << " failed to dlclose: " << dlerror();
-    ret = false;
-  }
+  // Don't bother to actually dlclose since we are shutting down anyway and there might be small
+  // amounts of processing still being done.
   return ret;
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7c05cb6..7f2f789 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -67,6 +67,7 @@
 #include "class_linker-inl.h"
 #include "compiler_callbacks.h"
 #include "debugger.h"
+#include "dex_file_loader.h"
 #include "elf_file.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "experimental_flags.h"
@@ -173,6 +174,11 @@
 static constexpr double kLowMemoryMaxLoadFactor = 0.8;
 static constexpr double kNormalMinLoadFactor = 0.4;
 static constexpr double kNormalMaxLoadFactor = 0.7;
+
+// Extra added to the default heap growth multiplier. Used to adjust the GC ergonomics for the read
+// barrier config.
+static constexpr double kExtraDefaultHeapGrowthMultiplier = kUseReadBarrier ? 1.0 : 0.0;
+
 Runtime* Runtime::instance_ = nullptr;
 
 struct TraceConfig {
@@ -1020,7 +1026,7 @@
       LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
       continue;
     }
-    if (!DexFile::Open(dex_filename, dex_location, kVerifyChecksum, &error_msg, dex_files)) {
+    if (!DexFileLoader::Open(dex_filename, dex_location, kVerifyChecksum, &error_msg, dex_files)) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     }
@@ -1142,6 +1148,7 @@
   zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
   experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental);
   is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode);
+  madvise_random_access_ = runtime_options.GetOrDefault(Opt::MadviseRandomAccess);
 
   plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins);
   agents_ = runtime_options.ReleaseOrDefault(Opt::AgentPath);
@@ -1150,13 +1157,22 @@
   //   agents_.push_back(lib);
   // }
 
+  float foreground_heap_growth_multiplier;
+  if (is_low_memory_mode_ && !runtime_options.Exists(Opt::ForegroundHeapGrowthMultiplier)) {
+    // If low memory mode, use 1.0 as the multiplier by default.
+    foreground_heap_growth_multiplier = 1.0f;
+  } else {
+    foreground_heap_growth_multiplier =
+        runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier) +
+            kExtraDefaultHeapGrowthMultiplier;
+  }
   XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
   heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
                        runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
                        runtime_options.GetOrDefault(Opt::HeapMinFree),
                        runtime_options.GetOrDefault(Opt::HeapMaxFree),
                        runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
-                       runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
+                       foreground_heap_growth_multiplier,
                        runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
                        runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
                        runtime_options.GetOrDefault(Opt::Image),
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 399e1c1..9f79a01 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -682,6 +682,12 @@
     return result;
   }
 
+  // Whether or not we use MADV_RANDOM on files that are thought to have random access patterns.
+  // This is beneficial for low RAM devices since it reduces page cache thrashing.
+  bool MAdviseRandomAccess() const {
+    return madvise_random_access_;
+  }
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -916,6 +922,10 @@
   // Whether or not we are on a low RAM device.
   bool is_low_memory_mode_;
 
+  // Whether or not we use MADV_RANDOM on files that are thought to have random access patterns.
+  // This is beneficial for low RAM devices since it reduces page cache thrashing.
+  bool madvise_random_access_;
+
   // Whether the application should run in safe mode, that is, interpreter only.
   bool safe_mode_;
 
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 78a60fa..2e03562 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -70,6 +70,7 @@
 RUNTIME_OPTIONS_KEY (bool,                EnableHSpaceCompactForOOM,      true)
 RUNTIME_OPTIONS_KEY (bool,                UseJitCompilation,              false)
 RUNTIME_OPTIONS_KEY (bool,                DumpNativeStackOnSigQuit,       true)
+RUNTIME_OPTIONS_KEY (bool,                MadviseRandomAccess,            false)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITWarmupThreshold)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITOsrThreshold)
@@ -145,4 +146,6 @@
 
 RUNTIME_OPTIONS_KEY (bool,                SlowDebug,                      false)
 
+RUNTIME_OPTIONS_KEY (unsigned int,        GlobalRefAllocStackTraceLimit,  0)  // 0 = off
+
 #undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/standard_dex_file.cc b/runtime/standard_dex_file.cc
new file mode 100644
index 0000000..36bb37a
--- /dev/null
+++ b/runtime/standard_dex_file.cc
@@ -0,0 +1,56 @@
+/*
+ * 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 "standard_dex_file.h"
+
+namespace art {
+
+const uint8_t StandardDexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
+const uint8_t StandardDexFile::kDexMagicVersions[StandardDexFile::kNumDexVersions]
+                                                [StandardDexFile::kDexVersionLen] = {
+  {'0', '3', '5', '\0'},
+  // Dex version 036 skipped because of an old dalvik bug on some versions of android where dex
+  // files with that version number would erroneously be accepted and run.
+  {'0', '3', '7', '\0'},
+  // Dex version 038: Android "O" and beyond.
+  {'0', '3', '8', '\0'},
+  // Dex verion 039: Beyond Android "O".
+  {'0', '3', '9', '\0'},
+};
+
+bool StandardDexFile::IsMagicValid(const uint8_t* magic) {
+  return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
+}
+
+bool StandardDexFile::IsVersionValid(const uint8_t* magic) {
+  const uint8_t* version = &magic[sizeof(kDexMagic)];
+  for (uint32_t i = 0; i < kNumDexVersions; i++) {
+    if (memcmp(version, kDexMagicVersions[i], kDexVersionLen) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool StandardDexFile::IsMagicValid() const {
+  return IsMagicValid(header_->magic_);
+}
+
+bool StandardDexFile::IsVersionValid() const {
+  return IsVersionValid(header_->magic_);
+}
+
+}  // namespace art
diff --git a/runtime/standard_dex_file.h b/runtime/standard_dex_file.h
new file mode 100644
index 0000000..1ec06ed
--- /dev/null
+++ b/runtime/standard_dex_file.h
@@ -0,0 +1,61 @@
+/*
+ * 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_STANDARD_DEX_FILE_H_
+#define ART_RUNTIME_STANDARD_DEX_FILE_H_
+
+#include <iosfwd>
+
+#include "dex_file.h"
+
+namespace art {
+
+class OatDexFile;
+
+// Standard dex file. This is the format that is packaged in APKs and produced by tools.
+class StandardDexFile : public DexFile {
+ public:
+  static const uint8_t kDexMagic[kDexMagicSize];
+  static constexpr size_t kNumDexVersions = 4;
+  static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
+
+  // Returns true if the byte string points to the magic value.
+  static bool IsMagicValid(const uint8_t* magic);
+  virtual bool IsMagicValid() const OVERRIDE;
+
+  // Returns true if the byte string after the magic is the correct value.
+  static bool IsVersionValid(const uint8_t* magic);
+  virtual bool IsVersionValid() const OVERRIDE;
+
+ private:
+  StandardDexFile(const uint8_t* base,
+                  size_t size,
+                  const std::string& location,
+                  uint32_t location_checksum,
+                  const OatDexFile* oat_dex_file)
+      : DexFile(base, size, location, location_checksum, oat_dex_file) {}
+
+  friend class DexFileLoader;
+  friend class DexFileVerifierTest;
+
+  ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for constructor
+
+  DISALLOW_COPY_AND_ASSIGN(StandardDexFile);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_STANDARD_DEX_FILE_H_
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index 6ff9666..20e297c 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -113,7 +113,8 @@
     if (onunload_ != nullptr) {
       onunload_(Runtime::Current()->GetJavaVM());
     }
-    dlclose(dlopen_handle_);
+    // Don't actually dlclose since some agents assume they will never get unloaded. Since this only
+    // happens when the runtime is shutting down anyway this isn't a big deal.
     dlopen_handle_ = nullptr;
     onload_ = nullptr;
     onattach_ = nullptr;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b72dec6..1f6bd74 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -48,6 +48,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
+#include "dex_file_loader.h"
 #include "dex_instruction.h"
 #include "oat_quick_method_header.h"
 #include "os.h"
@@ -858,7 +859,7 @@
       !android::base::EndsWith(location, ".art") &&
       !android::base::EndsWith(location, ".oat")) {
     cache_file += "/";
-    cache_file += DexFile::kClassesDex;
+    cache_file += DexFileLoader::kClassesDex;
   }
   std::replace(cache_file.begin(), cache_file.end(), '/', '@');
   *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index b955220..55bc9ec 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -25,6 +25,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "dex_to_dex_decompiler.h"
 
 namespace art {
@@ -151,15 +152,15 @@
     size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
     // TODO: Supply the location information for a vdex file.
     static constexpr char kVdexLocation[] = "";
-    std::string location = DexFile::GetMultiDexLocation(i, kVdexLocation);
-    std::unique_ptr<const DexFile> dex(DexFile::Open(dex_file_start,
-                                                     size,
-                                                     location,
-                                                     GetLocationChecksum(i),
-                                                     nullptr /*oat_dex_file*/,
-                                                     false /*verify*/,
-                                                     false /*verify_checksum*/,
-                                                     error_msg));
+    std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
+    std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start,
+                                                           size,
+                                                           location,
+                                                           GetLocationChecksum(i),
+                                                           nullptr /*oat_dex_file*/,
+                                                           false /*verify*/,
+                                                           false /*verify_checksum*/,
+                                                           error_msg));
     if (dex == nullptr) {
       return false;
     }
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7246bae..0033167 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -71,8 +71,8 @@
 // sure we only print this once.
 static bool gPrintedDxMonitorText = false;
 
-PcToRegisterLineTable::PcToRegisterLineTable(ScopedArenaAllocator& arena)
-    : register_lines_(arena.Adapter(kArenaAllocVerifier)) {}
+PcToRegisterLineTable::PcToRegisterLineTable(ScopedArenaAllocator& allocator)
+    : register_lines_(allocator.Adapter(kArenaAllocVerifier)) {}
 
 void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* flags,
                                  uint32_t insns_size, uint16_t registers_size,
@@ -552,9 +552,9 @@
                                bool allow_thread_suspension)
     : self_(self),
       arena_stack_(Runtime::Current()->GetArenaPool()),
-      arena_(&arena_stack_),
-      reg_types_(can_load_classes, arena_),
-      reg_table_(arena_),
+      allocator_(&arena_stack_),
+      reg_types_(can_load_classes, allocator_),
+      reg_table_(allocator_),
       work_insn_idx_(dex::kDexNoIndex),
       dex_method_idx_(dex_method_idx),
       mirror_method_(method),
@@ -868,7 +868,7 @@
   }
 
   // Allocate and initialize an array to hold instruction data.
-  insn_flags_.reset(arena_.AllocArray<InstructionFlags>(code_item_->insns_size_in_code_units_));
+  insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(code_item_->insns_size_in_code_units_));
   DCHECK(insn_flags_ != nullptr);
   std::uninitialized_fill_n(insn_flags_.get(),
                             code_item_->insns_size_in_code_units_,
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 57ab56c..1f1d7c1 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -67,7 +67,7 @@
 // execution of that instruction.
 class PcToRegisterLineTable {
  public:
-  explicit PcToRegisterLineTable(ScopedArenaAllocator& arena);
+  explicit PcToRegisterLineTable(ScopedArenaAllocator& allocator);
   ~PcToRegisterLineTable();
 
   // Initialize the RegisterTable. Every instruction address can have a different set of information
@@ -222,7 +222,7 @@
   }
 
   ScopedArenaAllocator& GetScopedAllocator() {
-    return arena_;
+    return allocator_;
   }
 
  private:
@@ -711,7 +711,7 @@
 
   // Arena allocator.
   ArenaStack arena_stack_;
-  ScopedArenaAllocator arena_;
+  ScopedArenaAllocator allocator_;
 
   RegTypeCache reg_types_;
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 0c00868..4ebe151 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -164,7 +164,7 @@
 }
 
 StringPiece RegTypeCache::AddString(const StringPiece& string_piece) {
-  char* ptr = arena_.AllocArray<char>(string_piece.length());
+  char* ptr = allocator_.AllocArray<char>(string_piece.length());
   memcpy(ptr, string_piece.data(), string_piece.length());
   return StringPiece(ptr, string_piece.length());
 }
@@ -197,9 +197,10 @@
     if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
-      entry = new (&arena_) PreciseReferenceType(klass, AddString(sp_descriptor), entries_.size());
+      entry =
+          new (&allocator_) PreciseReferenceType(klass, AddString(sp_descriptor), entries_.size());
     } else {
-      entry = new (&arena_) ReferenceType(klass, AddString(sp_descriptor), entries_.size());
+      entry = new (&allocator_) ReferenceType(klass, AddString(sp_descriptor), entries_.size());
     }
     return AddEntry(entry);
   } else {  // Class not resolved.
@@ -213,7 +214,7 @@
     }
     if (IsValidDescriptor(descriptor)) {
       return AddEntry(
-          new (&arena_) UnresolvedReferenceType(AddString(sp_descriptor), entries_.size()));
+          new (&allocator_) UnresolvedReferenceType(AddString(sp_descriptor), entries_.size()));
     } else {
       // The descriptor is broken return the unknown type as there's nothing sensible that
       // could be done at runtime
@@ -224,7 +225,7 @@
 
 const RegType& RegTypeCache::MakeUnresolvedReference() {
   // The descriptor is intentionally invalid so nothing else will match this type.
-  return AddEntry(new (&arena_) UnresolvedReferenceType(AddString("a"), entries_.size()));
+  return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString("a"), entries_.size()));
 }
 
 const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const {
@@ -253,8 +254,8 @@
   DCHECK(FindClass(klass, precise) == nullptr);
   RegType* const reg_type = precise
       ? static_cast<RegType*>(
-          new (&arena_) PreciseReferenceType(klass, descriptor, entries_.size()))
-      : new (&arena_) ReferenceType(klass, descriptor, entries_.size());
+          new (&allocator_) PreciseReferenceType(klass, descriptor, entries_.size()))
+      : new (&allocator_) ReferenceType(klass, descriptor, entries_.size());
   return &AddEntry(reg_type);
 }
 
@@ -267,11 +268,11 @@
   return *reg_type;
 }
 
-RegTypeCache::RegTypeCache(bool can_load_classes, ScopedArenaAllocator& arena)
-    : entries_(arena.Adapter(kArenaAllocVerifier)),
-      klass_entries_(arena.Adapter(kArenaAllocVerifier)),
+RegTypeCache::RegTypeCache(bool can_load_classes, ScopedArenaAllocator& allocator)
+    : entries_(allocator.Adapter(kArenaAllocVerifier)),
+      klass_entries_(allocator.Adapter(kArenaAllocVerifier)),
       can_load_classes_(can_load_classes),
-      arena_(arena) {
+      allocator_(allocator) {
   if (kIsDebugBuild) {
     Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0);
   }
@@ -349,7 +350,7 @@
 const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left,
                                                  const RegType& right,
                                                  MethodVerifier* verifier) {
-  ArenaBitVector types(&arena_,
+  ArenaBitVector types(&allocator_,
                        kDefaultArenaBitVectorBytes * kBitsPerByte,  // Allocate at least 8 bytes.
                        true);                                       // Is expandable.
   const RegType* left_resolved;
@@ -426,10 +427,10 @@
       }
     }
   }
-  return AddEntry(new (&arena_) UnresolvedMergedType(resolved_parts_merged,
-                                                     types,
-                                                     this,
-                                                     entries_.size()));
+  return AddEntry(new (&allocator_) UnresolvedMergedType(resolved_parts_merged,
+                                                         types,
+                                                         this,
+                                                         entries_.size()));
 }
 
 const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
@@ -446,7 +447,7 @@
       }
     }
   }
-  return AddEntry(new (&arena_) UnresolvedSuperClass(child.GetId(), this, entries_.size()));
+  return AddEntry(new (&allocator_) UnresolvedSuperClass(child.GetId(), this, entries_.size()));
 }
 
 const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
@@ -462,9 +463,9 @@
         return *down_cast<const UnresolvedUninitializedRefType*>(cur_entry);
       }
     }
-    entry = new (&arena_) UnresolvedUninitializedRefType(descriptor,
-                                                         allocation_pc,
-                                                         entries_.size());
+    entry = new (&allocator_) UnresolvedUninitializedRefType(descriptor,
+                                                             allocation_pc,
+                                                             entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
@@ -476,10 +477,10 @@
         return *down_cast<const UninitializedReferenceType*>(cur_entry);
       }
     }
-    entry = new (&arena_) UninitializedReferenceType(klass,
-                                                     descriptor,
-                                                     allocation_pc,
-                                                     entries_.size());
+    entry = new (&allocator_) UninitializedReferenceType(klass,
+                                                         descriptor,
+                                                         allocation_pc,
+                                                         entries_.size());
   }
   return AddEntry(entry);
 }
@@ -496,7 +497,7 @@
         return *cur_entry;
       }
     }
-    entry = new (&arena_) UnresolvedReferenceType(descriptor, entries_.size());
+    entry = new (&allocator_) UnresolvedReferenceType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
     if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
@@ -507,7 +508,7 @@
           return *cur_entry;
         }
       }
-      entry = new (&arena_) ReferenceType(klass, "", entries_.size());
+      entry = new (&allocator_) ReferenceType(klass, "", entries_.size());
     } else if (!klass->IsPrimitive()) {
       // We're uninitialized because of allocation, look or create a precise type as allocations
       // may only create objects of that type.
@@ -526,9 +527,9 @@
           return *cur_entry;
         }
       }
-      entry = new (&arena_) PreciseReferenceType(klass,
-                                                 uninit_type.GetDescriptor(),
-                                                 entries_.size());
+      entry = new (&allocator_) PreciseReferenceType(klass,
+                                                     uninit_type.GetDescriptor(),
+                                                     entries_.size());
     } else {
       return Conflict();
     }
@@ -547,7 +548,7 @@
         return *down_cast<const UninitializedType*>(cur_entry);
       }
     }
-    entry = new (&arena_) UnresolvedUninitializedThisRefType(descriptor, entries_.size());
+    entry = new (&allocator_) UnresolvedUninitializedThisRefType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
@@ -556,7 +557,7 @@
         return *down_cast<const UninitializedType*>(cur_entry);
       }
     }
-    entry = new (&arena_) UninitializedThisReferenceType(klass, descriptor, entries_.size());
+    entry = new (&allocator_) UninitializedThisReferenceType(klass, descriptor, entries_.size());
   }
   return AddEntry(entry);
 }
@@ -572,9 +573,9 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&arena_) PreciseConstType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstType(value, entries_.size());
   } else {
-    entry = new (&arena_) ImpreciseConstType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstType(value, entries_.size());
   }
   return AddEntry(entry);
 }
@@ -589,9 +590,9 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&arena_) PreciseConstLoType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstLoType(value, entries_.size());
   } else {
-    entry = new (&arena_) ImpreciseConstLoType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstLoType(value, entries_.size());
   }
   return AddEntry(entry);
 }
@@ -606,9 +607,9 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&arena_) PreciseConstHiType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstHiType(value, entries_.size());
   } else {
-    entry = new (&arena_) ImpreciseConstHiType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstHiType(value, entries_.size());
   }
   return AddEntry(entry);
 }
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 96eca05..74d9e9d 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -61,7 +61,7 @@
 
 class RegTypeCache {
  public:
-  explicit RegTypeCache(bool can_load_classes, ScopedArenaAllocator& arena);
+  explicit RegTypeCache(bool can_load_classes, ScopedArenaAllocator& allocator);
   ~RegTypeCache();
   static void Init() REQUIRES_SHARED(Locks::mutator_lock_) {
     if (!RegTypeCache::primitive_initialized_) {
@@ -201,7 +201,7 @@
   const bool can_load_classes_;
 
   // Arena allocator.
-  ScopedArenaAllocator& arena_;
+  ScopedArenaAllocator& allocator_;
 
   DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
 };
diff --git a/test/004-ThreadStress/src/Main.java b/test/004-ThreadStress/src/Main.java
index 35f394c..a9e0faf 100644
--- a/test/004-ThreadStress/src/Main.java
+++ b/test/004-ThreadStress/src/Main.java
@@ -462,7 +462,69 @@
             permits = 3;
         }
 
-        return new Semaphore(permits, /* fair */ true);
+        Semaphore semaphore = new Semaphore(permits, /* fair */ true);
+        forceTransitiveClassInitialization(semaphore, permits);
+        return semaphore;
+    }
+
+    // Force ahead-of-time initialization of classes used by Semaphore
+    // code. Try to exercise all code paths likely to be taken during
+    // the actual test later (including having a thread blocking on
+    // the semaphore trying to acquire a permit), so that we increase
+    // the chances to initialize all classes indirectly used by
+    // QueuedWait (e.g. AbstractQueuedSynchronizer$Node).
+    private static void forceTransitiveClassInitialization(Semaphore semaphore, final int permits) {
+        // Ensure `semaphore` has the expected number of permits
+        // before we start.
+        assert semaphore.availablePermits() == permits;
+
+        // Let the main (current) thread acquire all permits from
+        // `semaphore`. Then create an auxiliary thread acquiring a
+        // permit from `semaphore`, blocking because none is
+        // available. Have the main thread release one permit, thus
+        // unblocking the second thread.
+
+        // Auxiliary thread.
+        Thread auxThread = new Thread("Aux") {
+            public void run() {
+                try {
+                    // Try to acquire one permit, and block until
+                    // that permit is released by the main thread.
+                    semaphore.acquire();
+                    // When unblocked, release the acquired permit
+                    // immediately.
+                    semaphore.release();
+                } catch (InterruptedException ignored) {
+                    throw new RuntimeException("Test set up failed in auxiliary thread");
+                }
+            }
+        };
+
+        // Main thread.
+        try {
+            // Acquire all permits.
+            semaphore.acquire(permits);
+            // Start the auxiliary thread and have it try to acquire a
+            // permit.
+            auxThread.start();
+            // Synchronization: Wait until the auxiliary thread is
+            // blocked trying to acquire a permit from `semaphore`.
+            while (!semaphore.hasQueuedThreads()) {
+                Thread.sleep(100);
+            }
+            // Release one permit, thus unblocking `auxThread` and let
+            // it acquire a permit.
+            semaphore.release();
+            // Synchronization: Wait for the auxiliary thread to die.
+            auxThread.join();
+            // Release remaining permits.
+            semaphore.release(permits - 1);
+
+            // Verify that all permits have been released.
+            assert semaphore.availablePermits() == permits;
+        } catch (InterruptedException ignored) {
+            throw new RuntimeException("Test set up failed in main thread");
+        }
     }
 
     public static void runTest(final int numberOfThreads, final int numberOfDaemons,
diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java
index 3016187..3924fa6 100644
--- a/test/088-monitor-verification/src/Main.java
+++ b/test/088-monitor-verification/src/Main.java
@@ -43,6 +43,7 @@
         ensureJitCompiled(Class.forName("OK"), "runNoMonitors");
         ensureJitCompiled(Class.forName("OK"), "runStraightLine");
         ensureJitCompiled(Class.forName("OK"), "runBalancedJoin");
+        ensureJitCompiled(Class.forName("NullLocks"), "run");
 
         Main m = new Main();
 
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
index e2a1001..6a9bf61 100644
--- a/test/100-reflect2/expected.txt
+++ b/test/100-reflect2/expected.txt
@@ -33,7 +33,7 @@
 14 (class java.lang.Short)
 [java.lang.String(int,int,char[]), public java.lang.String(), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder)]
 [private final int java.lang.String.count, private int java.lang.String.hash, private static final java.io.ObjectStreamField[] java.lang.String.serialPersistentFields, private static final long java.lang.String.serialVersionUID, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER]
-[native void java.lang.String.getCharsNoCheck(int,int,char[],int), private boolean java.lang.String.nonSyncContentEquals(java.lang.AbstractStringBuilder), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private native int java.lang.String.fastIndexOf(int,int), private native java.lang.String java.lang.String.doReplace(char,char), private native java.lang.String java.lang.String.fastSubstring(int,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public byte[] java.lang.String.getBytes(), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public native char java.lang.String.charAt(int), public native char[] java.lang.String.toCharArray(), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(java.lang.String,java.lang.String,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), static int java.lang.String.lastIndexOf(java.lang.String,java.lang.String,int), void java.lang.String.getChars(char[],int)]
+[native void java.lang.String.getCharsNoCheck(int,int,char[],int), private boolean java.lang.String.nonSyncContentEquals(java.lang.AbstractStringBuilder), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private native java.lang.String java.lang.String.doReplace(char,char), private native java.lang.String java.lang.String.fastSubstring(int,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public byte[] java.lang.String.getBytes(), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public native char java.lang.String.charAt(int), public native char[] java.lang.String.toCharArray(), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(java.lang.String,java.lang.String,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), static int java.lang.String.lastIndexOf(java.lang.String,java.lang.String,int), void java.lang.String.getChars(char[],int)]
 []
 [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence]
 0
diff --git a/test/1914-get-local-instance/expected.txt b/test/1914-get-local-instance/expected.txt
index 4117942..09f0df1 100644
--- a/test/1914-get-local-instance/expected.txt
+++ b/test/1914-get-local-instance/expected.txt
@@ -10,3 +10,6 @@
 Running public native void art.Test1914$TargetClass.NativeInstanceMethod(java.lang.Runnable) with "GetThis" on remote thread.
 "GetThis" on public native void art.Test1914$TargetClass.NativeInstanceMethod(java.lang.Runnable) got value: TargetClass("NativeInstanceMethodObject")
 	Value is 'TargetClass("NativeInstanceMethodObject")' (class: class art.Test1914$TargetClass)
+Running public abstract void art.Test1914$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetThis" on remote thread.
+"GetThis" on public abstract void art.Test1914$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: Proxy for [interface art.Test1914$Foo]
+	Value is 'Proxy for [interface art.Test1914$Foo]' (class: PROXY CLASS)
diff --git a/test/1914-get-local-instance/src/art/Test1914.java b/test/1914-get-local-instance/src/art/Test1914.java
index c09f519..e47f9cb 100644
--- a/test/1914-get-local-instance/src/art/Test1914.java
+++ b/test/1914-get-local-instance/src/art/Test1914.java
@@ -18,7 +18,9 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.nio.ByteBuffer;
 import java.util.concurrent.Semaphore;
 import java.util.Arrays;
@@ -35,7 +37,7 @@
 
   public static void reportValue(Object val) {
     System.out.println("\tValue is '" + val + "' (class: "
-        + (val != null ? val.getClass() : "NULL") + ")");
+        + (val != null ? (val instanceof Proxy ? "PROXY CLASS" : val.getClass()) : "NULL") + ")");
   }
 
   public static void StaticMethod(Runnable safepoint) {
@@ -151,7 +153,10 @@
 
     private StackTrace.StackFrameData findStackFrame(Thread thr) {
       for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
-        if (frame.method.equals(target)) {
+        if (frame.method.equals(target) ||
+            (frame.method.getName().equals(target.getName()) &&
+             Arrays.deepEquals(frame.method.getParameterTypes(), target.getParameterTypes()) &&
+             ((Method)frame.method).getReturnType().equals(target.getReturnType()))) {
           return frame;
         }
       }
@@ -163,6 +168,25 @@
     return klass.getDeclaredMethod(name, Runnable.class);
   }
 
+  public static interface Foo {
+    public void InterfaceProxyMethod(Runnable r);
+  }
+
+  public static Object getProxyObject(final Class... k) {
+    return Proxy.newProxyInstance(
+        Test1914.class.getClassLoader(),
+        k,
+        (p, m, a) -> {
+          if (m.getName().equals("toString")) {
+            return "Proxy for " + Arrays.toString(k);
+          } else {
+            ((Runnable)a[0]).run();
+            reportValue(p);
+            return null;
+          }
+        });
+  }
+
   public static void run() throws Exception {
     Locals.EnableLocalVariableAccess();
     final TestCase[] MAIN_TEST_CASES = new TestCase[] {
@@ -172,6 +196,8 @@
                    getMethod(TargetClass.class, "InstanceMethod")),
       new TestCase(new TargetClass("NativeInstanceMethodObject"),
                    getMethod(TargetClass.class, "NativeInstanceMethod")),
+      new TestCase(getProxyObject(Foo.class),
+                   getMethod(Foo.class, "InterfaceProxyMethod")),
     };
 
     for (TestCase t: MAIN_TEST_CASES) {
diff --git a/test/1929-exception-catch-exception/build b/test/1929-exception-catch-exception/build
index 42b99ad..10ffcc5 100644
--- a/test/1929-exception-catch-exception/build
+++ b/test/1929-exception-catch-exception/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/1934-jvmti-signal-thread/info.txt b/test/1934-jvmti-signal-thread/info.txt
index c8c9189..1c58674 100644
--- a/test/1934-jvmti-signal-thread/info.txt
+++ b/test/1934-jvmti-signal-thread/info.txt
@@ -1,3 +1,3 @@
 Tests basic functions in the jvmti plugin.
 
-Tests that the GetBytecodes function works as expected.
+Tests that the StopThread and InterruptThread functions work as expected.
diff --git a/test/1934-jvmti-signal-thread/src/art/Test1934.java b/test/1934-jvmti-signal-thread/src/art/Test1934.java
index 552570a..3ab4cf6 100644
--- a/test/1934-jvmti-signal-thread/src/art/Test1934.java
+++ b/test/1934-jvmti-signal-thread/src/art/Test1934.java
@@ -173,11 +173,13 @@
     destroyNativeMonitor(native_monitor_id);
   }
 
-  public static void doRecur(Runnable r) {
+  public static void doRecurCnt(Runnable r, int cnt) {
     if (r != null) {
       r.run();
     }
-    doRecur(r);
+    if (cnt != 0) {
+      doRecurCnt(r, cnt - 1);
+    }
   }
 
   public static void testStopRecur() throws Exception {
@@ -186,9 +188,7 @@
     Thread target = new Thread(() -> {
       sem.release();
       while (true) {
-        try {
-          doRecur(null);
-        } catch (StackOverflowError e) {}
+        doRecurCnt(null, 50);
       }
     }, "recuring thread!");
     target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; });
@@ -209,11 +209,9 @@
     Thread target = new Thread(() -> {
       sem.release();
       while (true) {
-        try {
-          doRecur(() -> {
-            if (Thread.currentThread().isInterrupted()) { throw new Error("Interrupted!"); }
-          });
-        } catch (StackOverflowError e) { }
+        doRecurCnt(() -> {
+          if (Thread.currentThread().isInterrupted()) { throw new Error("Interrupted!"); }
+        }, 50);
       }
     }, "recuring thread!");
     target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; });
diff --git a/test/1939-proxy-frames/expected.txt b/test/1939-proxy-frames/expected.txt
new file mode 100644
index 0000000..a4c97c9
--- /dev/null
+++ b/test/1939-proxy-frames/expected.txt
@@ -0,0 +1,8 @@
+Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetThis" on remote thread.
+"GetThis" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: Proxy for [interface art.Test1939$Foo]
+Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetLocalReference0" on remote thread.
+"GetLocalReference0" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) failed due to JVMTI_ERROR_OPAQUE_FRAME
+Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetProxyFrameLocation" on remote thread.
+"GetProxyFrameLocation" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: -1
+Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetProxyFrameMethod" on remote thread.
+"GetProxyFrameMethod" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: public final void $Proxy0.InterfaceProxyMethod(java.lang.Runnable)
diff --git a/test/1939-proxy-frames/info.txt b/test/1939-proxy-frames/info.txt
new file mode 100644
index 0000000..9fc3d62
--- /dev/null
+++ b/test/1939-proxy-frames/info.txt
@@ -0,0 +1,2 @@
+Test for jvmti get local instance
+
diff --git a/test/1939-proxy-frames/local_instance.cc b/test/1939-proxy-frames/local_instance.cc
new file mode 100644
index 0000000..dc833bf
--- /dev/null
+++ b/test/1939-proxy-frames/local_instance.cc
@@ -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.
+ */
+
+#include <iostream>
+#include <pthread.h>
+#include <stdio.h>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "jni.h"
+#include "scoped_local_ref.h"
+#include "scoped_primitive_array.h"
+
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test1939ProxyFrames {
+
+extern "C" JNIEXPORT jobject Java_art_Test1939_GetFrameMethod(JNIEnv* env,
+                                                              jclass,
+                                                              jthread thr,
+                                                              jint depth) {
+  jmethodID m = nullptr;
+  jlong loc = -1;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetFrameLocation(thr, depth, &m, &loc))) {
+    return nullptr;
+  }
+  jclass klass = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetMethodDeclaringClass(m, &klass))) {
+    return nullptr;
+  }
+  jobject res = env->ToReflectedMethod(klass, m, false);
+  env->DeleteLocalRef(klass);
+  return res;
+}
+
+extern "C" JNIEXPORT jlong Java_art_Test1939_GetFrameLocation(JNIEnv* env,
+                                                              jclass,
+                                                              jthread thr,
+                                                              jint depth) {
+  jmethodID m = nullptr;
+  jlong loc = -1;
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetFrameLocation(thr, depth, &m, &loc));
+  return loc;
+}
+
+}  // namespace Test1939ProxyFrames
+}  // namespace art
+
diff --git a/test/1939-proxy-frames/run b/test/1939-proxy-frames/run
new file mode 100755
index 0000000..51875a7
--- /dev/null
+++ b/test/1939-proxy-frames/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+# Ask for stack traces to be dumped to a file rather than to stdout.
+./default-run "$@" --jvmti
diff --git a/test/1939-proxy-frames/src/Main.java b/test/1939-proxy-frames/src/Main.java
new file mode 100644
index 0000000..85cab34
--- /dev/null
+++ b/test/1939-proxy-frames/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    art.Test1939.run();
+  }
+}
diff --git a/test/1939-proxy-frames/src/art/Breakpoint.java b/test/1939-proxy-frames/src/art/Breakpoint.java
new file mode 100644
index 0000000..bbb89f7
--- /dev/null
+++ b/test/1939-proxy-frames/src/art/Breakpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
+
+public class Breakpoint {
+  public static class Manager {
+    public static class BP {
+      public final Executable method;
+      public final long location;
+
+      public BP(Executable method) {
+        this(method, getStartLocation(method));
+      }
+
+      public BP(Executable method, long location) {
+        this.method = method;
+        this.location = location;
+      }
+
+      @Override
+      public boolean equals(Object other) {
+        return (other instanceof BP) &&
+            method.equals(((BP)other).method) &&
+            location == ((BP)other).location;
+      }
+
+      @Override
+      public String toString() {
+        return method.toString() + " @ " + getLine();
+      }
+
+      @Override
+      public int hashCode() {
+        return Objects.hash(method, location);
+      }
+
+      public int getLine() {
+        try {
+          LineNumber[] lines = getLineNumberTable(method);
+          int best = -1;
+          for (LineNumber l : lines) {
+            if (l.location > location) {
+              break;
+            } else {
+              best = l.line;
+            }
+          }
+          return best;
+        } catch (Exception e) {
+          return -1;
+        }
+      }
+    }
+
+    private Set<BP> breaks = new HashSet<>();
+
+    public void setBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.add(b)) {
+          Breakpoint.setBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void setBreakpoint(Executable method, long location) {
+      setBreakpoints(new BP(method, location));
+    }
+
+    public void clearBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.remove(b)) {
+          Breakpoint.clearBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void clearBreakpoint(Executable method, long location) {
+      clearBreakpoints(new BP(method, location));
+    }
+
+    public void clearAllBreakpoints() {
+      clearBreakpoints(breaks.toArray(new BP[0]));
+    }
+  }
+
+  public static void startBreakpointWatch(Class<?> methodClass,
+                                          Executable breakpointReached,
+                                          Thread thr) {
+    startBreakpointWatch(methodClass, breakpointReached, false, thr);
+  }
+
+  /**
+   * Enables the trapping of breakpoint events.
+   *
+   * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
+   */
+  public static native void startBreakpointWatch(Class<?> methodClass,
+                                                 Executable breakpointReached,
+                                                 boolean allowRecursive,
+                                                 Thread thr);
+  public static native void stopBreakpointWatch(Thread thr);
+
+  public static final class LineNumber implements Comparable<LineNumber> {
+    public final long location;
+    public final int line;
+
+    private LineNumber(long loc, int line) {
+      this.location = loc;
+      this.line = line;
+    }
+
+    public boolean equals(Object other) {
+      return other instanceof LineNumber && ((LineNumber)other).line == line &&
+          ((LineNumber)other).location == location;
+    }
+
+    public int compareTo(LineNumber other) {
+      int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
+      if (v != 0) {
+        return v;
+      } else {
+        return Long.valueOf(location).compareTo(Long.valueOf(other.location));
+      }
+    }
+  }
+
+  public static native void setBreakpoint(Executable m, long loc);
+  public static void setBreakpoint(Executable m, LineNumber l) {
+    setBreakpoint(m, l.location);
+  }
+
+  public static native void clearBreakpoint(Executable m, long loc);
+  public static void clearBreakpoint(Executable m, LineNumber l) {
+    clearBreakpoint(m, l.location);
+  }
+
+  private static native Object[] getLineNumberTableNative(Executable m);
+  public static LineNumber[] getLineNumberTable(Executable m) {
+    Object[] nativeTable = getLineNumberTableNative(m);
+    long[] location = (long[])(nativeTable[0]);
+    int[] lines = (int[])(nativeTable[1]);
+    if (lines.length != location.length) {
+      throw new Error("Lines and locations have different lengths!");
+    }
+    LineNumber[] out = new LineNumber[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      out[i] = new LineNumber(location[i], lines[i]);
+    }
+    return out;
+  }
+
+  public static native long getStartLocation(Executable m);
+
+  public static int locationToLine(Executable m, long location) {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      int best = -1;
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.location > location) {
+          break;
+        } else {
+          best = l.line;
+        }
+      }
+      return best;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  public static long lineToLocation(Executable m, int line) throws Exception {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.line == line) {
+          return l.location;
+        }
+      }
+      throw new Exception("Unable to find line " + line + " in " + m);
+    } catch (Exception e) {
+      throw new Exception("Unable to get line number info for " + m, e);
+    }
+  }
+}
+
diff --git a/test/1939-proxy-frames/src/art/Locals.java b/test/1939-proxy-frames/src/art/Locals.java
new file mode 100644
index 0000000..22e21be
--- /dev/null
+++ b/test/1939-proxy-frames/src/art/Locals.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.Objects;
+
+public class Locals {
+  public static native void EnableLocalVariableAccess();
+
+  public static class VariableDescription {
+    public final long start_location;
+    public final int length;
+    public final String name;
+    public final String signature;
+    public final String generic_signature;
+    public final int slot;
+
+    public VariableDescription(
+        long start, int length, String name, String sig, String gen_sig, int slot) {
+      this.start_location = start;
+      this.length = length;
+      this.name = name;
+      this.signature = sig;
+      this.generic_signature = gen_sig;
+      this.slot = slot;
+    }
+
+    @Override
+    public String toString() {
+      return String.format(
+          "VariableDescription { " +
+            "Sig: '%s', Name: '%s', Gen_sig: '%s', slot: %d, start: %d, len: %d" +
+          "}",
+          this.signature,
+          this.name,
+          this.generic_signature,
+          this.slot,
+          this.start_location,
+          this.length);
+    }
+    public boolean equals(Object other) {
+      if (!(other instanceof VariableDescription)) {
+        return false;
+      } else {
+        VariableDescription v = (VariableDescription)other;
+        return Objects.equals(v.signature, signature) &&
+            Objects.equals(v.name, name) &&
+            Objects.equals(v.generic_signature, generic_signature) &&
+            v.slot == slot &&
+            v.start_location == start_location &&
+            v.length == length;
+      }
+    }
+    public int hashCode() {
+      return Objects.hash(this.signature, this.name, this.generic_signature, this.slot,
+          this.start_location, this.length);
+    }
+  }
+
+  public static native VariableDescription[] GetLocalVariableTable(Executable e);
+
+  public static VariableDescription GetVariableAtLine(
+      Executable e, String name, String sig, int line) throws Exception {
+    return GetVariableAtLocation(e, name, sig, Breakpoint.lineToLocation(e, line));
+  }
+
+  public static VariableDescription GetVariableAtLocation(
+      Executable e, String name, String sig, long loc) {
+    VariableDescription[] vars = GetLocalVariableTable(e);
+    for (VariableDescription var : vars) {
+      if (var.start_location <= loc &&
+          var.length + var.start_location > loc &&
+          var.name.equals(name) &&
+          var.signature.equals(sig)) {
+        return var;
+      }
+    }
+    throw new Error(
+        "Unable to find variable " + name + " (sig: " + sig + ") in " + e + " at loc " + loc);
+  }
+
+  public static native int GetLocalVariableInt(Thread thr, int depth, int slot);
+  public static native long GetLocalVariableLong(Thread thr, int depth, int slot);
+  public static native float GetLocalVariableFloat(Thread thr, int depth, int slot);
+  public static native double GetLocalVariableDouble(Thread thr, int depth, int slot);
+  public static native Object GetLocalVariableObject(Thread thr, int depth, int slot);
+  public static native Object GetLocalInstance(Thread thr, int depth);
+
+  public static void SetLocalVariableInt(Thread thr, int depth, int slot, Object val) {
+    SetLocalVariableInt(thr, depth, slot, ((Number)val).intValue());
+  }
+  public static void SetLocalVariableLong(Thread thr, int depth, int slot, Object val) {
+    SetLocalVariableLong(thr, depth, slot, ((Number)val).longValue());
+  }
+  public static void SetLocalVariableFloat(Thread thr, int depth, int slot, Object val) {
+    SetLocalVariableFloat(thr, depth, slot, ((Number)val).floatValue());
+  }
+  public static void SetLocalVariableDouble(Thread thr, int depth, int slot, Object val) {
+    SetLocalVariableDouble(thr, depth, slot, ((Number)val).doubleValue());
+  }
+  public static native void SetLocalVariableInt(Thread thr, int depth, int slot, int val);
+  public static native void SetLocalVariableLong(Thread thr, int depth, int slot, long val);
+  public static native void SetLocalVariableFloat(Thread thr, int depth, int slot, float val);
+  public static native void SetLocalVariableDouble(Thread thr, int depth, int slot, double val);
+  public static native void SetLocalVariableObject(Thread thr, int depth, int slot, Object val);
+}
diff --git a/test/1939-proxy-frames/src/art/StackTrace.java b/test/1939-proxy-frames/src/art/StackTrace.java
new file mode 100644
index 0000000..2ea2f20
--- /dev/null
+++ b/test/1939-proxy-frames/src/art/StackTrace.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Executable;
+
+public class StackTrace {
+  public static class StackFrameData {
+    public final Thread thr;
+    public final Executable method;
+    public final long current_location;
+    public final int depth;
+
+    public StackFrameData(Thread thr, Executable e, long loc, int depth) {
+      this.thr = thr;
+      this.method = e;
+      this.current_location = loc;
+      this.depth = depth;
+    }
+    @Override
+    public String toString() {
+      return String.format(
+          "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }",
+          this.thr,
+          this.method,
+          this.current_location,
+          this.depth);
+    }
+  }
+
+  public static native int GetStackDepth(Thread thr);
+
+  private static native StackFrameData[] nativeGetStackTrace(Thread thr);
+
+  public static StackFrameData[] GetStackTrace(Thread thr) {
+    // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not
+    // suspended. The spec says that not being suspended is fine but since we want this to be
+    // consistent we will suspend for the RI.
+    boolean suspend_thread =
+        !System.getProperty("java.vm.name").equals("Dalvik") &&
+        !thr.equals(Thread.currentThread()) &&
+        !Suspension.isSuspended(thr);
+    if (suspend_thread) {
+      Suspension.suspend(thr);
+    }
+    StackFrameData[] out = nativeGetStackTrace(thr);
+    if (suspend_thread) {
+      Suspension.resume(thr);
+    }
+    return out;
+  }
+}
+
diff --git a/test/1939-proxy-frames/src/art/Suspension.java b/test/1939-proxy-frames/src/art/Suspension.java
new file mode 100644
index 0000000..16e62cc
--- /dev/null
+++ b/test/1939-proxy-frames/src/art/Suspension.java
@@ -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.
+ */
+
+package art;
+
+public class Suspension {
+  // Suspends a thread using jvmti.
+  public native static void suspend(Thread thr);
+
+  // Resumes a thread using jvmti.
+  public native static void resume(Thread thr);
+
+  public native static boolean isSuspended(Thread thr);
+
+  public native static int[] suspendList(Thread... threads);
+  public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1939-proxy-frames/src/art/Test1939.java b/test/1939-proxy-frames/src/art/Test1939.java
new file mode 100644
index 0000000..83d0d2c
--- /dev/null
+++ b/test/1939-proxy-frames/src/art/Test1939.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Semaphore;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.Consumer;
+
+public class Test1939 {
+  public static interface SafepointFunction {
+    public void invoke(
+        Thread thread,
+        Method target,
+        int depth) throws Exception;
+  }
+
+  public static interface GetterFunction {
+    public Object GetVar(Thread t, int depth);
+  }
+
+  public static SafepointFunction NamedGet(final String type, final GetterFunction get) {
+    return new SafepointFunction() {
+      public void invoke(Thread t, Method method, int depth) {
+        try {
+          Object res = get.GetVar(t, depth);
+          System.out.println(this + " on " + method + " got value: " + res);
+        } catch (Exception e) {
+          System.out.println(this + " on " + method + " failed due to " + e.getMessage());
+        }
+      }
+      public String toString() {
+        return "\"Get" + type + "\"";
+      }
+    };
+  }
+
+  public static class TestCase {
+    public final Object thiz;
+    public final Method target;
+
+    public TestCase(Method target) {
+      this(null, target);
+    }
+    public TestCase(Object thiz, Method target) {
+      this.thiz = thiz;
+      this.target = target;
+    }
+
+    public static class ThreadPauser implements Runnable {
+      public final Semaphore sem_wakeup_main;
+      public final Semaphore sem_wait;
+
+      public ThreadPauser() {
+        sem_wakeup_main = new Semaphore(0);
+        sem_wait = new Semaphore(0);
+      }
+
+      public void run() {
+        try {
+          sem_wakeup_main.release();
+          sem_wait.acquire();
+        } catch (Exception e) {
+          throw new Error("Error with semaphores!", e);
+        }
+      }
+
+      public void waitForOtherThreadToPause() throws Exception {
+        sem_wakeup_main.acquire();
+      }
+
+      public void wakeupOtherThread() throws Exception {
+        sem_wait.release();
+      }
+    }
+
+    public void exec(final SafepointFunction safepoint) throws Exception {
+      System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
+      final ThreadPauser pause = new ThreadPauser();
+      Thread remote = new Thread(
+          () -> {
+            try {
+              target.invoke(thiz, pause);
+            } catch (Exception e) {
+              throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
+            }
+          },
+          "remote thread for " + target + " with " + safepoint);
+      remote.start();
+      pause.waitForOtherThreadToPause();
+      try {
+        Suspension.suspend(remote);
+        StackTrace.StackFrameData frame = findStackFrame(remote);
+        safepoint.invoke(remote, target, frame.depth);
+      } finally {
+        Suspension.resume(remote);
+        pause.wakeupOtherThread();
+        remote.join();
+      }
+    }
+
+    private StackTrace.StackFrameData findStackFrame(Thread thr) {
+      for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
+        if (frame.method.equals(target) ||
+            (frame.method.getName().equals(target.getName()) &&
+             Arrays.deepEquals(frame.method.getParameterTypes(), target.getParameterTypes()) &&
+             ((Method)frame.method).getReturnType().equals(target.getReturnType()))) {
+          return frame;
+        }
+      }
+      throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
+    }
+  }
+
+  public static Method getMethod(Class<?> klass, String name) throws Exception {
+    return klass.getDeclaredMethod(name, Runnable.class);
+  }
+
+  public static interface Foo {
+    public void InterfaceProxyMethod(Runnable r);
+  }
+
+  public static Object getProxyObject(final Class... k) {
+    return Proxy.newProxyInstance(
+        Test1939.class.getClassLoader(),
+        k,
+        (p, m, a) -> {
+          if (m.getName().equals("toString")) {
+            return "Proxy for " + Arrays.toString(k);
+          } else {
+            ((Runnable)a[0]).run();
+            return null;
+          }
+        });
+  }
+
+  public static void run() throws Exception {
+    Locals.EnableLocalVariableAccess();
+    TestCase test = new TestCase(
+        getProxyObject(Foo.class), getMethod(Foo.class, "InterfaceProxyMethod"));
+    test.exec(NamedGet("This", Locals::GetLocalInstance));
+    test.exec(NamedGet("LocalReference0", (t, d) -> Locals.GetLocalVariableObject(t, d, 0)));
+    test.exec(NamedGet("ProxyFrameLocation", (t, d) -> Long.valueOf(GetFrameLocation(t, d))));
+    test.exec(NamedGet("ProxyFrameMethod", Test1939::GetFrameMethod));
+  }
+
+  public static native long GetFrameLocation(Thread thr, int depth);
+  public static native Executable GetFrameMethod(Thread thr, int depth);
+}
+
diff --git a/test/450-checker-types/build b/test/450-checker-types/build
index 947ec9a..3721955 100755
--- a/test/450-checker-types/build
+++ b/test/450-checker-types/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/458-checker-instruct-simplification/build b/test/458-checker-instruct-simplification/build
index 947ec9a..3721955 100755
--- a/test/458-checker-instruct-simplification/build
+++ b/test/458-checker-instruct-simplification/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/463-checker-boolean-simplifier/build b/test/463-checker-boolean-simplifier/build
index 947ec9a..3721955 100755
--- a/test/463-checker-boolean-simplifier/build
+++ b/test/463-checker-boolean-simplifier/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/476-checker-ctor-fence-redun-elim/build b/test/476-checker-ctor-fence-redun-elim/build
index 42b99ad..10ffcc5 100644
--- a/test/476-checker-ctor-fence-redun-elim/build
+++ b/test/476-checker-ctor-fence-redun-elim/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/482-checker-loop-back-edge-use/build b/test/482-checker-loop-back-edge-use/build
index 42b99ad..10ffcc5 100644
--- a/test/482-checker-loop-back-edge-use/build
+++ b/test/482-checker-loop-back-edge-use/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/484-checker-register-hints/build b/test/484-checker-register-hints/build
index 42b99ad..10ffcc5 100644
--- a/test/484-checker-register-hints/build
+++ b/test/484-checker-register-hints/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/530-checker-lse/build b/test/530-checker-lse/build
index 42b99ad..10ffcc5 100755
--- a/test/530-checker-lse/build
+++ b/test/530-checker-lse/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/549-checker-types-merge/build b/test/549-checker-types-merge/build
index 42b99ad..10ffcc5 100644
--- a/test/549-checker-types-merge/build
+++ b/test/549-checker-types-merge/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/565-checker-doublenegbitwise/build b/test/565-checker-doublenegbitwise/build
index 947ec9a..3721955 100755
--- a/test/565-checker-doublenegbitwise/build
+++ b/test/565-checker-doublenegbitwise/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/565-checker-rotate/build b/test/565-checker-rotate/build
index 42b99ad..10ffcc5 100644
--- a/test/565-checker-rotate/build
+++ b/test/565-checker-rotate/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/566-checker-signum/build b/test/566-checker-signum/build
index 42b99ad..10ffcc5 100644
--- a/test/566-checker-signum/build
+++ b/test/566-checker-signum/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/567-checker-compare/build b/test/567-checker-compare/build
index 1d269dc..10ffcc5 100644
--- a/test/567-checker-compare/build
+++ b/test/567-checker-compare/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx 
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/570-checker-osr/build b/test/570-checker-osr/build
index 42b99ad..10ffcc5 100644
--- a/test/570-checker-osr/build
+++ b/test/570-checker-osr/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/586-checker-null-array-get/build b/test/586-checker-null-array-get/build
index 947ec9a..3721955 100755
--- a/test/586-checker-null-array-get/build
+++ b/test/586-checker-null-array-get/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/593-checker-boolean-2-integral-conv/build b/test/593-checker-boolean-2-integral-conv/build
index 947ec9a..3721955 100755
--- a/test/593-checker-boolean-2-integral-conv/build
+++ b/test/593-checker-boolean-2-integral-conv/build
@@ -21,6 +21,6 @@
 export DESUGAR=false
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/611-checker-simplify-if/build b/test/611-checker-simplify-if/build
index 42b99ad..10ffcc5 100644
--- a/test/611-checker-simplify-if/build
+++ b/test/611-checker-simplify-if/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/618-checker-induction/build b/test/618-checker-induction/build
index 42b99ad..10ffcc5 100644
--- a/test/618-checker-induction/build
+++ b/test/618-checker-induction/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index 0daeedd..338e841 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -31,6 +31,17 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
@@ -65,6 +76,9 @@
   //
   // No ABS? No SAD!
   //
+  /// CHECK-START-ARM: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
+  /// CHECK-NOT: VecSADAccumulate
+  //
   /// CHECK-START-ARM64: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
   private static int sadInt2IntAlt(int[] x, int[] y) {
@@ -90,6 +104,17 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]       loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java
index bcfa968..0b425d8 100644
--- a/test/661-checker-simd-reduc/src/Main.java
+++ b/test/661-checker-simd-reduc/src/Main.java
@@ -20,6 +20,7 @@
 public class Main {
 
   static final int N = 500;
+  static final int M = 100;
 
   //
   // Basic reductions in loops.
@@ -61,6 +62,18 @@
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Return [<<Phi2>>]             loop:none
   //
+  /// CHECK-START-ARM: int Main.reductionInt(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  //
   /// CHECK-START-ARM64: int Main.reductionInt(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
@@ -97,6 +110,30 @@
   //
   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
   //
+  /// CHECK-START-ARM: int Main.reductionIntChain() loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set1:d\d+>>   VecSetScalars [<<Cons1>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set1>>,{{d\d+}}]       loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Red1:d\d+>>   VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr1:i\d+>>  VecExtractScalar [<<Red1>>]   loop:none
+  /// CHECK-DAG: <<Set2:d\d+>>   VecSetScalars [<<Extr1>>]     loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:d\d+>>   Phi [<<Set2>>,{{d\d+}}]       loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi3>>]   loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi4>>,<<Load2>>]   loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi3>>,<<Cons2>>]      loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Red2:d\d+>>   VecReduce [<<Phi4>>]          loop:none
+  /// CHECK-DAG: <<Extr2:i\d+>>  VecExtractScalar [<<Red2>>]   loop:none
+  /// CHECK-DAG:                 Return [<<Extr2>>]            loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
   /// CHECK-START-ARM64: int Main.reductionIntChain() loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
@@ -147,6 +184,23 @@
   //
   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
   //
+  /// CHECK-START-ARM: int Main.reductionIntToLoop(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load1>>]   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Extr>>,{{i\d+}}]       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi4:i\d+>>   Phi [<<Extr>>,{{i\d+}}]       loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
   /// CHECK-START-ARM64: int Main.reductionIntToLoop(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                 loop:none
@@ -241,6 +295,19 @@
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Return [<<Phi2>>]             loop:none
   //
+  /// CHECK-START-ARM: int Main.reductionIntM1(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<ConsM1:i\d+>> IntConstant -1                loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsM1>>]    loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 VecAdd [<<Phi2>>,<<Load>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  //
   /// CHECK-START-ARM64: int Main.reductionIntM1(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<ConsM1:i\d+>> IntConstant -1                loop:none
@@ -326,6 +393,18 @@
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Return [<<Phi2>>]             loop:none
   //
+  /// CHECK-START-ARM: int Main.reductionMinusInt(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]     loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 VecSub [<<Phi2>>,<<Load>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  //
   /// CHECK-START-ARM64: int Main.reductionMinusInt(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
@@ -411,11 +490,24 @@
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Return [<<Phi2>>]             loop:none
   //
+  /// CHECK-START-ARM: int Main.reductionMinInt(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<ConsM:i\d+>>  IntConstant 2147483647        loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecReplicateScalar [<<ConsM>>] loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 VecMin [<<Phi2>>,<<Load>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  //
   /// CHECK-START-ARM64: int Main.reductionMinInt(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<ConsM:i\d+>>  IntConstant 2147483647        loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
-  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsM>>]     loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecReplicateScalar [<<ConsM>>] loop:none
   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
@@ -474,11 +566,24 @@
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Return [<<Phi2>>]             loop:none
   //
+  /// CHECK-START-ARM: int Main.reductionMaxInt(int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
+  /// CHECK-DAG: <<ConsM:i\d+>>  IntConstant -2147483648       loop:none
+  /// CHECK-DAG: <<Cons2:i\d+>>  IntConstant 2                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecReplicateScalar [<<ConsM>>] loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 VecMax [<<Phi2>>,<<Load>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Red:d\d+>>    VecReduce [<<Phi2>>]          loop:none
+  /// CHECK-DAG: <<Extr:i\d+>>   VecExtractScalar [<<Red>>]    loop:none
+  //
   /// CHECK-START-ARM64: int Main.reductionMaxInt(int[]) loop_optimization (after)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                 loop:none
   /// CHECK-DAG: <<ConsM:i\d+>>  IntConstant -2147483648       loop:none
   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                 loop:none
-  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsM>>]     loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecReplicateScalar [<<ConsM>>] loop:none
   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]        loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: <<Load:d\d+>>   VecLoad [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
@@ -562,6 +667,32 @@
       xl[i] = k;
     }
 
+    // Arrays with all positive elements.
+    byte[] xpb = new byte[M];
+    short[] xps = new short[M];
+    char[] xpc = new char[M];
+    int[] xpi = new int[M];
+    long[] xpl = new long[M];
+    for (int i = 0, k = 3; i < M; i++, k++) {
+      xpb[i] = (byte) k;
+      xps[i] = (short) k;
+      xpc[i] = (char) k;
+      xpi[i] = k;
+      xpl[i] = k;
+    }
+
+    // Arrays with all negative elements.
+    byte[] xnb = new byte[M];
+    short[] xns = new short[M];
+    int[] xni = new int[M];
+    long[] xnl = new long[M];
+    for (int i = 0, k = -103; i < M; i++, k++) {
+      xnb[i] = (byte) k;
+      xns[i] = (short) k;
+      xni[i] = k;
+      xnl[i] = k;
+    }
+
     // Test various reductions in loops.
     int[] x0 = { 0, 0, 0, 0 };
     int[] x1 = { 0, 0, 0, 1 };
@@ -601,11 +732,29 @@
     expectEquals(1, reductionMinChar(xc));
     expectEquals(-17, reductionMinInt(xi));
     expectEquals(-17L, reductionMinLong(xl));
+    expectEquals(3, reductionMinByte(xpb));
+    expectEquals(3, reductionMinShort(xps));
+    expectEquals(3, reductionMinChar(xpc));
+    expectEquals(3, reductionMinInt(xpi));
+    expectEquals(3L, reductionMinLong(xpl));
+    expectEquals(-103, reductionMinByte(xnb));
+    expectEquals(-103, reductionMinShort(xns));
+    expectEquals(-103, reductionMinInt(xni));
+    expectEquals(-103L, reductionMinLong(xnl));
     expectEquals(127, reductionMaxByte(xb));
     expectEquals(1480, reductionMaxShort(xs));
     expectEquals(65534, reductionMaxChar(xc));
     expectEquals(1480, reductionMaxInt(xi));
     expectEquals(1480L, reductionMaxLong(xl));
+    expectEquals(102, reductionMaxByte(xpb));
+    expectEquals(102, reductionMaxShort(xps));
+    expectEquals(102, reductionMaxChar(xpc));
+    expectEquals(102, reductionMaxInt(xpi));
+    expectEquals(102L, reductionMaxLong(xpl));
+    expectEquals(-4, reductionMaxByte(xnb));
+    expectEquals(-4, reductionMaxShort(xns));
+    expectEquals(-4, reductionMaxInt(xni));
+    expectEquals(-4L, reductionMaxLong(xnl));
 
     // Test special cases.
     expectEquals(13, reductionInt10(xi));
diff --git a/test/667-out-of-bounds/expected.txt b/test/667-out-of-bounds/expected.txt
new file mode 100644
index 0000000..e114c50
--- /dev/null
+++ b/test/667-out-of-bounds/expected.txt
@@ -0,0 +1 @@
+java.lang.ArrayIndexOutOfBoundsException: length=5; index=82
diff --git a/test/667-out-of-bounds/info.txt b/test/667-out-of-bounds/info.txt
new file mode 100644
index 0000000..19be695
--- /dev/null
+++ b/test/667-out-of-bounds/info.txt
@@ -0,0 +1,3 @@
+Regression test for the x86/x64 backends which under certain
+cirumstances used to pass the wrong value for the length of
+an array when throwing an AIOOBE.
diff --git a/test/667-out-of-bounds/src/Main.java b/test/667-out-of-bounds/src/Main.java
new file mode 100644
index 0000000..7842569
--- /dev/null
+++ b/test/667-out-of-bounds/src/Main.java
@@ -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.
+ */
+
+public class Main {
+  static int $noinline$arrayAccess(int[] array) {
+    return array[82];
+  }
+
+  public static void main(String[] args) {
+    int[] array = new int[5];
+    try {
+      $noinline$arrayAccess(array);
+    } catch (Exception e) {
+      System.out.println(e);
+    }
+  }
+}
diff --git a/test/710-varhandle-creation/build b/test/710-varhandle-creation/build
new file mode 100644
index 0000000..ca1e557
--- /dev/null
+++ b/test/710-varhandle-creation/build
@@ -0,0 +1,20 @@
+#!/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.
+
+# Stop if something fails.
+set -e
+
+./default-build "$@" --experimental var-handles
diff --git a/test/710-varhandle-creation/expected.txt b/test/710-varhandle-creation/expected.txt
new file mode 100644
index 0000000..89dfb48
--- /dev/null
+++ b/test/710-varhandle-creation/expected.txt
@@ -0,0 +1,6 @@
+checkAccessModes...PASS
+checkInstantiatedVarHandles...vz...vb...vc...vs...vi...vj...vf...vd...vo...vfz...vfb...vfc...vfs...vfi...vfj...vff...vfd...vfo...vfss...vsz...vsb...vsc...vss...vsi...vsj...vsf...vsd...vso...vaz...vab...vac...vas...vai...vaj...vaf...vad...vao...vbaz...vbab...vbac...vbas...vbai...vbaj...vbaf...vbad...vbao...vbbz...vbbb...vbbc...vbbs...vbbi...vbbj...vbbf...vbbd...vbbo...PASS
+LookupCheckA...PASS
+LookupCheckB...PASS
+UnreflectCheck...PASS
+LookupCheckC...PASS
diff --git a/test/710-varhandle-creation/info.txt b/test/710-varhandle-creation/info.txt
new file mode 100644
index 0000000..d0b2dad
--- /dev/null
+++ b/test/710-varhandle-creation/info.txt
@@ -0,0 +1,2 @@
+This test checks VarHandle creation and the VarHandle instance methods
+other than the signature polymorphic ones.
diff --git a/test/710-varhandle-creation/src-art/Main.java b/test/710-varhandle-creation/src-art/Main.java
new file mode 100644
index 0000000..6d542bb
--- /dev/null
+++ b/test/710-varhandle-creation/src-art/Main.java
@@ -0,0 +1,2421 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Google designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Google in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import dalvik.system.VMRuntime;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.VarHandle.AccessMode;
+import java.lang.reflect.Field;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public final class Main {
+    // Mutable fields
+    boolean z;
+    byte b;
+    char c;
+    short s;
+    int i;
+    long j;
+    float f;
+    double d;
+    Object o;
+
+    // Final fields
+    final boolean fz = true;
+    final byte fb = (byte) 2;
+    final char fc = 'c';
+    final short fs = (short) 3;
+    final int fi = 4;
+    final long fj = 5;
+    final float ff = 6.0f;
+    final double fd = 7.0;
+    final Object fo = "Hello";
+    final String fss = "Boo";
+
+    // Static fields
+    static boolean sz;
+    static byte sb;
+    static char sc;
+    static short ss;
+    static int si;
+    static long sj;
+    static float sf;
+    static double sd;
+    static Object so;
+
+    // VarHandle instances for mutable fields
+    static final VarHandle vz;
+    static final VarHandle vb;
+    static final VarHandle vc;
+    static final VarHandle vs;
+    static final VarHandle vi;
+    static final VarHandle vj;
+    static final VarHandle vf;
+    static final VarHandle vd;
+    static final VarHandle vo;
+
+    // VarHandle instances for final fields
+    static final VarHandle vfz;
+    static final VarHandle vfb;
+    static final VarHandle vfc;
+    static final VarHandle vfs;
+    static final VarHandle vfi;
+    static final VarHandle vfj;
+    static final VarHandle vff;
+    static final VarHandle vfd;
+    static final VarHandle vfo;
+    static final VarHandle vfss;
+
+    // VarHandle instances for static fields
+    static final VarHandle vsz;
+    static final VarHandle vsb;
+    static final VarHandle vsc;
+    static final VarHandle vss;
+    static final VarHandle vsi;
+    static final VarHandle vsj;
+    static final VarHandle vsf;
+    static final VarHandle vsd;
+    static final VarHandle vso;
+
+    // VarHandle instances for array elements
+    static final VarHandle vaz;
+    static final VarHandle vab;
+    static final VarHandle vac;
+    static final VarHandle vas;
+    static final VarHandle vai;
+    static final VarHandle vaj;
+    static final VarHandle vaf;
+    static final VarHandle vad;
+    static final VarHandle vao;
+
+    // VarHandle instances for byte array view
+    static final VarHandle vbaz;
+    static final VarHandle vbab;
+    static final VarHandle vbac;
+    static final VarHandle vbas;
+    static final VarHandle vbai;
+    static final VarHandle vbaj;
+    static final VarHandle vbaf;
+    static final VarHandle vbad;
+    static final VarHandle vbao;
+
+    // VarHandle instances for byte buffer view
+    static final VarHandle vbbz;
+    static final VarHandle vbbb;
+    static final VarHandle vbbc;
+    static final VarHandle vbbs;
+    static final VarHandle vbbi;
+    static final VarHandle vbbj;
+    static final VarHandle vbbf;
+    static final VarHandle vbbd;
+    static final VarHandle vbbo;
+
+    // Some test results vary depending on 32-bit vs 64-bit.
+    static final boolean IS_64_BIT = VMRuntime.getRuntime().is64Bit();
+
+    static {
+        try {
+            vz = MethodHandles.lookup().findVarHandle(Main.class, "z", boolean.class);
+            vb = MethodHandles.lookup().findVarHandle(Main.class, "b", byte.class);
+            vc = MethodHandles.lookup().findVarHandle(Main.class, "c", char.class);
+            vs = MethodHandles.lookup().findVarHandle(Main.class, "s", short.class);
+            vi = MethodHandles.lookup().findVarHandle(Main.class, "i", int.class);
+            vj = MethodHandles.lookup().findVarHandle(Main.class, "j", long.class);
+            vf = MethodHandles.lookup().findVarHandle(Main.class, "f", float.class);
+            vd = MethodHandles.lookup().findVarHandle(Main.class, "d", double.class);
+            vo = MethodHandles.lookup().findVarHandle(Main.class, "o", Object.class);
+
+            vfz = MethodHandles.lookup().findVarHandle(Main.class, "fz", boolean.class);
+            vfb = MethodHandles.lookup().findVarHandle(Main.class, "fb", byte.class);
+            vfc = MethodHandles.lookup().findVarHandle(Main.class, "fc", char.class);
+            vfs = MethodHandles.lookup().findVarHandle(Main.class, "fs", short.class);
+            vfi = MethodHandles.lookup().findVarHandle(Main.class, "fi", int.class);
+            vfj = MethodHandles.lookup().findVarHandle(Main.class, "fj", long.class);
+            vff = MethodHandles.lookup().findVarHandle(Main.class, "ff", float.class);
+            vfd = MethodHandles.lookup().findVarHandle(Main.class, "fd", double.class);
+            vfo = MethodHandles.lookup().findVarHandle(Main.class, "fo", Object.class);
+            vfss = MethodHandles.lookup().findVarHandle(Main.class, "fss", String.class);
+
+            vsz = MethodHandles.lookup().findStaticVarHandle(Main.class, "sz", boolean.class);
+            vsb = MethodHandles.lookup().findStaticVarHandle(Main.class, "sb", byte.class);
+            vsc = MethodHandles.lookup().findStaticVarHandle(Main.class, "sc", char.class);
+            vss = MethodHandles.lookup().findStaticVarHandle(Main.class, "ss", short.class);
+            vsi = MethodHandles.lookup().findStaticVarHandle(Main.class, "si", int.class);
+            vsj = MethodHandles.lookup().findStaticVarHandle(Main.class, "sj", long.class);
+            vsf = MethodHandles.lookup().findStaticVarHandle(Main.class, "sf", float.class);
+            vsd = MethodHandles.lookup().findStaticVarHandle(Main.class, "sd", double.class);
+            vso = MethodHandles.lookup().findStaticVarHandle(Main.class, "so", Object.class);
+
+            vaz = MethodHandles.arrayElementVarHandle(boolean[].class);
+            vab = MethodHandles.arrayElementVarHandle(byte[].class);
+            vac = MethodHandles.arrayElementVarHandle(char[].class);
+            vas = MethodHandles.arrayElementVarHandle(short[].class);
+            vai = MethodHandles.arrayElementVarHandle(int[].class);
+            vaj = MethodHandles.arrayElementVarHandle(long[].class);
+            vaf = MethodHandles.arrayElementVarHandle(float[].class);
+            vad = MethodHandles.arrayElementVarHandle(double[].class);
+            vao = MethodHandles.arrayElementVarHandle(Object[].class);
+
+            try {
+                MethodHandles.byteArrayViewVarHandle(boolean[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbaz = null;
+            }
+            try {
+                MethodHandles.byteArrayViewVarHandle(byte[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbab = null;
+            }
+            vbac = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.LITTLE_ENDIAN);
+            vbas = MethodHandles.byteArrayViewVarHandle(short[].class, ByteOrder.BIG_ENDIAN);
+            vbai = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
+            vbaj = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN);
+            vbaf = MethodHandles.byteArrayViewVarHandle(float[].class, ByteOrder.LITTLE_ENDIAN);
+            vbad = MethodHandles.byteArrayViewVarHandle(double[].class, ByteOrder.BIG_ENDIAN);
+            try {
+                MethodHandles.byteArrayViewVarHandle(Object[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbao = null;
+            }
+
+            try {
+                MethodHandles.byteBufferViewVarHandle(boolean[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbbz = null;
+            }
+            try {
+                MethodHandles.byteBufferViewVarHandle(byte[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbbb = null;
+            }
+            vbbc = MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.LITTLE_ENDIAN);
+            vbbs = MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.BIG_ENDIAN);
+            vbbi = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
+            vbbj = MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN);
+            vbbf = MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.LITTLE_ENDIAN);
+            vbbd = MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.BIG_ENDIAN);
+            try {
+                MethodHandles.byteBufferViewVarHandle(Object[].class, ByteOrder.LITTLE_ENDIAN);
+                throw new RuntimeException("Unexpected instantiation");
+            } catch (UnsupportedOperationException e) {
+                vbbo = null;
+            }
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void fail(String reason) {
+        throw new RuntimeException("FAIL: " + reason);
+    }
+
+    private static void checkNull(VarHandle v) {
+        if (v != null) {
+            fail("Instance unexpectedly not null:" + v);
+        }
+    }
+
+    private static void checkNotNull(VarHandle v) {
+        if (v == null) {
+            fail("Instance unexpectedly null:" + v);
+        }
+    }
+
+    private static void checkVarType(VarHandle v, Class<?> expectedVarType) {
+        if (v.varType() != expectedVarType) {
+            fail("varType " + v.varType() + " != " + expectedVarType);
+        }
+    }
+
+    private static void checkCoordinateTypes(VarHandle v, String expectedCoordinateTypes) {
+        String actualCoordinateTypes = Arrays.toString(v.coordinateTypes().toArray());
+        if (!actualCoordinateTypes.equals(expectedCoordinateTypes)) {
+            fail("coordinateTypes " + actualCoordinateTypes + " != " + expectedCoordinateTypes);
+        }
+    }
+
+    private static void checkVarHandleAccessMode(VarHandle v, VarHandle.AccessMode accessMode,
+                                                 boolean expectedSupported, String expectedAccessModeType) {
+        boolean actualSupported = v.isAccessModeSupported(accessMode);
+        if (actualSupported != expectedSupported) {
+            fail("isAccessModeSupported(" + accessMode + ") is " +
+                 actualSupported + " != " + expectedSupported);
+        }
+
+        String actualAccessModeType = v.accessModeType(accessMode).toString();
+        if (!actualAccessModeType.equals(expectedAccessModeType)) {
+            fail("accessModeType(" + accessMode + ") is " +
+                 actualAccessModeType + " != " + expectedAccessModeType);
+        }
+    }
+
+    private static void checkInstantiatedVarHandles() {
+        System.out.print("checkInstantiatedVarHandles...");
+
+        System.out.print("vz...");
+        checkNotNull(vz);
+        checkVarType(vz, boolean.class);
+        checkCoordinateTypes(vz, "[class Main]");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET, true, "(Main)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.SET, true, "(Main,boolean)void");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,boolean)void");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.SET_RELEASE, true, "(Main,boolean)void");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,boolean)void");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_SET, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,boolean)boolean");
+
+        System.out.print("vb...");
+        checkNotNull(vb);
+        checkVarType(vb, byte.class);
+        checkCoordinateTypes(vb, "[class Main]");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET, true, "(Main)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.SET, true, "(Main,byte)void");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,byte)void");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.SET_RELEASE, true, "(Main,byte)void");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,byte)void");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_SET, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,byte)byte");
+        checkVarHandleAccessMode(vb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,byte)byte");
+
+        System.out.print("vc...");
+        checkNotNull(vc);
+        checkVarType(vc, char.class);
+        checkCoordinateTypes(vc, "[class Main]");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET, true, "(Main)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.SET, true, "(Main,char)void");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,char)void");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.SET_RELEASE, true, "(Main,char)void");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,char)void");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,char,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,char,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,char,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_SET, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,char)char");
+        checkVarHandleAccessMode(vc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,char)char");
+
+        System.out.print("vs...");
+        checkNotNull(vs);
+        checkVarType(vs, short.class);
+        checkCoordinateTypes(vs, "[class Main]");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET, true, "(Main)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.SET, true, "(Main,short)void");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,short)void");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.SET_RELEASE, true, "(Main,short)void");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,short)void");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,short,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,short,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,short,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_SET, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,short)short");
+        checkVarHandleAccessMode(vs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,short)short");
+
+        System.out.print("vi...");
+        checkNotNull(vi);
+        checkVarType(vi, int.class);
+        checkCoordinateTypes(vi, "[class Main]");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET, true, "(Main)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.SET, true, "(Main,int)void");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,int)void");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.SET_RELEASE, true, "(Main,int)void");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,int)void");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,int,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,int,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,int,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_SET, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,int)int");
+        checkVarHandleAccessMode(vi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,int)int");
+
+        System.out.print("vj...");
+        checkNotNull(vj);
+        checkVarType(vj, long.class);
+        checkCoordinateTypes(vj, "[class Main]");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET, true, "(Main)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.SET, true, "(Main,long)void");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,long)void");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.SET_RELEASE, true, "(Main,long)void");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,long)void");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,long,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,long,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,long,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_SET, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(Main,long)long");
+        checkVarHandleAccessMode(vj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(Main,long)long");
+
+        System.out.print("vf...");
+        checkNotNull(vf);
+        checkVarType(vf, float.class);
+        checkCoordinateTypes(vf, "[class Main]");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET, true, "(Main)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.SET, true, "(Main,float)void");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,float)void");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.SET_RELEASE, true, "(Main,float)void");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,float)void");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,float,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,float,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,float,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_SET, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,float)float");
+
+        System.out.print("vd...");
+        checkNotNull(vd);
+        checkVarType(vd, double.class);
+        checkCoordinateTypes(vd, "[class Main]");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET, true, "(Main)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.SET, true, "(Main,double)void");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,double)void");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.SET_RELEASE, true, "(Main,double)void");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,double)void");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,double,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,double,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,double,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_SET, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_ADD, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,double)double");
+
+        System.out.print("vo...");
+        checkNotNull(vo);
+        checkVarType(vo, Object.class);
+        checkCoordinateTypes(vo, "[class Main]");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET, true, "(Main)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.SET, true, "(Main,Object)void");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.SET_VOLATILE, true, "(Main,Object)void");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.SET_RELEASE, true, "(Main,Object)void");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.SET_OPAQUE, true, "(Main,Object)void");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_SET, true, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vo, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,Object)Object");
+
+        System.out.print("vfz...");
+        checkNotNull(vfz);
+        checkVarType(vfz, boolean.class);
+        checkCoordinateTypes(vfz, "[class Main]");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET, true, "(Main)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.SET, false, "(Main,boolean)void");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,boolean)void");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.SET_RELEASE, false, "(Main,boolean)void");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,boolean)void");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_SET, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,boolean)boolean");
+        checkVarHandleAccessMode(vfz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,boolean)boolean");
+
+        System.out.print("vfb...");
+        checkNotNull(vfb);
+        checkVarType(vfb, byte.class);
+        checkCoordinateTypes(vfb, "[class Main]");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET, true, "(Main)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.SET, false, "(Main,byte)void");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,byte)void");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.SET_RELEASE, false, "(Main,byte)void");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,byte)void");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,byte,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,byte,byte)boolean");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_SET, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,byte)byte");
+        checkVarHandleAccessMode(vfb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,byte)byte");
+
+        System.out.print("vfc...");
+        checkNotNull(vfc);
+        checkVarType(vfc, char.class);
+        checkCoordinateTypes(vfc, "[class Main]");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET, true, "(Main)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.SET, false, "(Main,char)void");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,char)void");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.SET_RELEASE, false, "(Main,char)void");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,char)void");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,char,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,char,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,char,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,char,char)boolean");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_SET, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,char)char");
+        checkVarHandleAccessMode(vfc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,char)char");
+
+        System.out.print("vfs...");
+        checkNotNull(vfs);
+        checkVarType(vfs, short.class);
+        checkCoordinateTypes(vfs, "[class Main]");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET, true, "(Main)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.SET, false, "(Main,short)void");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,short)void");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.SET_RELEASE, false, "(Main,short)void");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,short)void");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,short,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,short,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,short,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,short,short)boolean");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_SET, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,short)short");
+        checkVarHandleAccessMode(vfs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,short)short");
+
+        System.out.print("vfi...");
+        checkNotNull(vfi);
+        checkVarType(vfi, int.class);
+        checkCoordinateTypes(vfi, "[class Main]");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET, true, "(Main)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.SET, false, "(Main,int)void");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,int)void");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.SET_RELEASE, false, "(Main,int)void");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,int)void");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,int,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,int,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,int,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,int,int)boolean");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_SET, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,int)int");
+        checkVarHandleAccessMode(vfi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,int)int");
+
+        System.out.print("vfj...");
+        checkNotNull(vfj);
+        checkVarType(vfj, long.class);
+        checkCoordinateTypes(vfj, "[class Main]");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET, true, "(Main)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.SET, false, "(Main,long)void");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,long)void");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.SET_RELEASE, false, "(Main,long)void");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,long)void");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,long,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,long,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,long,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,long,long)boolean");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_SET, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,long)long");
+        checkVarHandleAccessMode(vfj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,long)long");
+
+        System.out.print("vff...");
+        checkNotNull(vff);
+        checkVarType(vff, float.class);
+        checkCoordinateTypes(vff, "[class Main]");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET, true, "(Main)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.SET, false, "(Main,float)void");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,float)void");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.SET_RELEASE, false, "(Main,float)void");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,float)void");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,float,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,float,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,float,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,float,float)boolean");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_SET, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,float)float");
+        checkVarHandleAccessMode(vff, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,float)float");
+
+        System.out.print("vfd...");
+        checkNotNull(vfd);
+        checkVarType(vfd, double.class);
+        checkCoordinateTypes(vfd, "[class Main]");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET, true, "(Main)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.SET, false, "(Main,double)void");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,double)void");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.SET_RELEASE, false, "(Main,double)void");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,double)void");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,double,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,double,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,double,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,double,double)boolean");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_SET, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,double)double");
+        checkVarHandleAccessMode(vfd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,double)double");
+
+        System.out.print("vfo...");
+        checkNotNull(vfo);
+        checkVarType(vfo, Object.class);
+        checkCoordinateTypes(vfo, "[class Main]");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET, true, "(Main)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.SET, false, "(Main,Object)void");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,Object)void");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.SET_RELEASE, false, "(Main,Object)void");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,Object)void");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,Object,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,Object,Object)boolean");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_SET, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,Object)Object");
+        checkVarHandleAccessMode(vfo, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,Object)Object");
+
+        System.out.print("vfss...");
+        checkNotNull(vfss);
+        checkVarType(vfss, java.lang.String.class);
+        checkCoordinateTypes(vfss, "[class Main]");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET, true, "(Main)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.SET, false, "(Main,String)void");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_VOLATILE, true, "(Main)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.SET_VOLATILE, false, "(Main,String)void");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_ACQUIRE, true, "(Main)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.SET_RELEASE, false, "(Main,String)void");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_OPAQUE, true, "(Main)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.SET_OPAQUE, false, "(Main,String)void");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.COMPARE_AND_SET, false, "(Main,String,String)boolean");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(Main,String,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(Main,String,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(Main,String,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(Main,String,String)boolean");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(Main,String,String)boolean");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(Main,String,String)boolean");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(Main,String,String)boolean");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_SET, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_ADD, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Main,String)String");
+        checkVarHandleAccessMode(vfss, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Main,String)String");
+
+        System.out.print("vsz...");
+        checkNotNull(vsz);
+        checkVarType(vsz, boolean.class);
+        checkCoordinateTypes(vsz, "[]");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET, true, "()boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.SET, true, "(boolean)void");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_VOLATILE, true, "()boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.SET_VOLATILE, true, "(boolean)void");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_ACQUIRE, true, "()boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.SET_RELEASE, true, "(boolean)void");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_OPAQUE, true, "()boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.SET_OPAQUE, true, "(boolean)void");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.COMPARE_AND_SET, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(boolean,boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_SET, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_ADD, false, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(boolean)boolean");
+        checkVarHandleAccessMode(vsz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(boolean)boolean");
+
+        System.out.print("vsb...");
+        checkNotNull(vsb);
+        checkVarType(vsb, byte.class);
+        checkCoordinateTypes(vsb, "[]");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET, true, "()byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.SET, true, "(byte)void");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_VOLATILE, true, "()byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.SET_VOLATILE, true, "(byte)void");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_ACQUIRE, true, "()byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.SET_RELEASE, true, "(byte)void");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_OPAQUE, true, "()byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.SET_OPAQUE, true, "(byte)void");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte,byte)boolean");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte,byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte,byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte,byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte,byte)boolean");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte,byte)boolean");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte,byte)boolean");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte,byte)boolean");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_SET, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_ADD, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(byte)byte");
+        checkVarHandleAccessMode(vsb, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(byte)byte");
+
+        System.out.print("vsc...");
+        checkNotNull(vsc);
+        checkVarType(vsc, char.class);
+        checkCoordinateTypes(vsc, "[]");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET, true, "()char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.SET, true, "(char)void");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_VOLATILE, true, "()char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.SET_VOLATILE, true, "(char)void");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_ACQUIRE, true, "()char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.SET_RELEASE, true, "(char)void");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_OPAQUE, true, "()char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.SET_OPAQUE, true, "(char)void");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.COMPARE_AND_SET, true, "(char,char)boolean");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(char,char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(char,char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(char,char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(char,char)boolean");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(char,char)boolean");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(char,char)boolean");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(char,char)boolean");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_SET, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_ADD, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(char)char");
+        checkVarHandleAccessMode(vsc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(char)char");
+
+        System.out.print("vss...");
+        checkNotNull(vss);
+        checkVarType(vss, short.class);
+        checkCoordinateTypes(vss, "[]");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET, true, "()short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.SET, true, "(short)void");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_VOLATILE, true, "()short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.SET_VOLATILE, true, "(short)void");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_ACQUIRE, true, "()short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.SET_RELEASE, true, "(short)void");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_OPAQUE, true, "()short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.SET_OPAQUE, true, "(short)void");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.COMPARE_AND_SET, true, "(short,short)boolean");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(short,short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(short,short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(short,short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(short,short)boolean");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(short,short)boolean");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(short,short)boolean");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(short,short)boolean");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_SET, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_ADD, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(short)short");
+        checkVarHandleAccessMode(vss, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(short)short");
+
+        System.out.print("vsi...");
+        checkNotNull(vsi);
+        checkVarType(vsi, int.class);
+        checkCoordinateTypes(vsi, "[]");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET, true, "()int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.SET, true, "(int)void");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_VOLATILE, true, "()int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.SET_VOLATILE, true, "(int)void");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_ACQUIRE, true, "()int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.SET_RELEASE, true, "(int)void");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_OPAQUE, true, "()int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.SET_OPAQUE, true, "(int)void");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.COMPARE_AND_SET, true, "(int,int)boolean");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(int,int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(int,int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(int,int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(int,int)boolean");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(int,int)boolean");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(int,int)boolean");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(int,int)boolean");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_SET, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_ADD, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(int)int");
+        checkVarHandleAccessMode(vsi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(int)int");
+
+        System.out.print("vsj...");
+        checkNotNull(vsj);
+        checkVarType(vsj, long.class);
+        checkCoordinateTypes(vsj, "[]");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET, true, "()long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.SET, true, "(long)void");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_VOLATILE, true, "()long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.SET_VOLATILE, true, "(long)void");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_ACQUIRE, true, "()long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.SET_RELEASE, true, "(long)void");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_OPAQUE, true, "()long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.SET_OPAQUE, true, "(long)void");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.COMPARE_AND_SET, true, "(long,long)boolean");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(long,long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(long,long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(long,long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(long,long)boolean");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(long,long)boolean");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(long,long)boolean");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(long,long)boolean");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_SET, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_ADD, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(long)long");
+        checkVarHandleAccessMode(vsj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(long)long");
+
+        System.out.print("vsf...");
+        checkNotNull(vsf);
+        checkVarType(vsf, float.class);
+        checkCoordinateTypes(vsf, "[]");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET, true, "()float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.SET, true, "(float)void");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_VOLATILE, true, "()float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.SET_VOLATILE, true, "(float)void");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_ACQUIRE, true, "()float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.SET_RELEASE, true, "(float)void");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_OPAQUE, true, "()float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.SET_OPAQUE, true, "(float)void");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.COMPARE_AND_SET, true, "(float,float)boolean");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(float,float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(float,float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(float,float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(float,float)boolean");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(float,float)boolean");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(float,float)boolean");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(float,float)boolean");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_SET, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_ADD, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(float)float");
+        checkVarHandleAccessMode(vsf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(float)float");
+
+        System.out.print("vsd...");
+        checkNotNull(vsd);
+        checkVarType(vsd, double.class);
+        checkCoordinateTypes(vsd, "[]");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET, true, "()double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.SET, true, "(double)void");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_VOLATILE, true, "()double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.SET_VOLATILE, true, "(double)void");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_ACQUIRE, true, "()double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.SET_RELEASE, true, "(double)void");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_OPAQUE, true, "()double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.SET_OPAQUE, true, "(double)void");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.COMPARE_AND_SET, true, "(double,double)boolean");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(double,double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(double,double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(double,double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(double,double)boolean");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(double,double)boolean");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(double,double)boolean");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(double,double)boolean");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_SET, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_ADD, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(double)double");
+        checkVarHandleAccessMode(vsd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(double)double");
+
+        System.out.print("vso...");
+        checkNotNull(vso);
+        checkVarType(vso, Object.class);
+        checkCoordinateTypes(vso, "[]");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET, true, "()Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.SET, true, "(Object)void");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_VOLATILE, true, "()Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.SET_VOLATILE, true, "(Object)void");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_ACQUIRE, true, "()Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.SET_RELEASE, true, "(Object)void");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_OPAQUE, true, "()Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.SET_OPAQUE, true, "(Object)void");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Object,Object)boolean");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Object,Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Object,Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Object,Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Object,Object)boolean");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Object,Object)boolean");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Object,Object)boolean");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Object,Object)boolean");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_SET, true, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_ADD, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Object)Object");
+        checkVarHandleAccessMode(vso, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Object)Object");
+
+        System.out.print("vaz...");
+        checkNotNull(vaz);
+        checkVarType(vaz, boolean.class);
+        checkCoordinateTypes(vaz, "[class [Z, int]");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET, true, "(boolean[],int)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.SET, true, "(boolean[],int,boolean)void");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_VOLATILE, true, "(boolean[],int)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.SET_VOLATILE, true, "(boolean[],int,boolean)void");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_ACQUIRE, true, "(boolean[],int)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.SET_RELEASE, true, "(boolean[],int,boolean)void");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_OPAQUE, true, "(boolean[],int)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.SET_OPAQUE, true, "(boolean[],int,boolean)void");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.COMPARE_AND_SET, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(boolean[],int,boolean,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_SET, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_ADD, false, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(boolean[],int,boolean)boolean");
+        checkVarHandleAccessMode(vaz, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(boolean[],int,boolean)boolean");
+
+        System.out.print("vab...");
+        checkNotNull(vab);
+        checkVarType(vab, byte.class);
+        checkCoordinateTypes(vab, "[class [B, int]");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET, true, "(byte[],int)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.SET, true, "(byte[],int,byte)void");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_VOLATILE, true, "(byte[],int)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.SET_VOLATILE, true, "(byte[],int,byte)void");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_ACQUIRE, true, "(byte[],int)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.SET_RELEASE, true, "(byte[],int,byte)void");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_OPAQUE, true, "(byte[],int)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.SET_OPAQUE, true, "(byte[],int,byte)void");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte[],int,byte,byte)boolean");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte[],int,byte,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte[],int,byte,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte[],int,byte,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte[],int,byte,byte)boolean");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte[],int,byte,byte)boolean");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte[],int,byte,byte)boolean");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte[],int,byte,byte)boolean");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_SET, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_ADD, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(byte[],int,byte)byte");
+        checkVarHandleAccessMode(vab, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(byte[],int,byte)byte");
+
+        System.out.print("vac...");
+        checkNotNull(vac);
+        checkVarType(vac, char.class);
+        checkCoordinateTypes(vac, "[class [C, int]");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET, true, "(char[],int)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.SET, true, "(char[],int,char)void");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_VOLATILE, true, "(char[],int)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.SET_VOLATILE, true, "(char[],int,char)void");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_ACQUIRE, true, "(char[],int)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.SET_RELEASE, true, "(char[],int,char)void");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_OPAQUE, true, "(char[],int)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.SET_OPAQUE, true, "(char[],int,char)void");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.COMPARE_AND_SET, true, "(char[],int,char,char)boolean");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(char[],int,char,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(char[],int,char,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(char[],int,char,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(char[],int,char,char)boolean");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(char[],int,char,char)boolean");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(char[],int,char,char)boolean");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(char[],int,char,char)boolean");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_SET, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_ADD, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(char[],int,char)char");
+        checkVarHandleAccessMode(vac, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(char[],int,char)char");
+
+        System.out.print("vas...");
+        checkNotNull(vas);
+        checkVarType(vas, short.class);
+        checkCoordinateTypes(vas, "[class [S, int]");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET, true, "(short[],int)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.SET, true, "(short[],int,short)void");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_VOLATILE, true, "(short[],int)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.SET_VOLATILE, true, "(short[],int,short)void");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_ACQUIRE, true, "(short[],int)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.SET_RELEASE, true, "(short[],int,short)void");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_OPAQUE, true, "(short[],int)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.SET_OPAQUE, true, "(short[],int,short)void");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.COMPARE_AND_SET, true, "(short[],int,short,short)boolean");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(short[],int,short,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(short[],int,short,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(short[],int,short,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(short[],int,short,short)boolean");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(short[],int,short,short)boolean");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(short[],int,short,short)boolean");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(short[],int,short,short)boolean");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_SET, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_ADD, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(short[],int,short)short");
+        checkVarHandleAccessMode(vas, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(short[],int,short)short");
+
+        System.out.print("vai...");
+        checkNotNull(vai);
+        checkVarType(vai, int.class);
+        checkCoordinateTypes(vai, "[class [I, int]");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET, true, "(int[],int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.SET, true, "(int[],int,int)void");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_VOLATILE, true, "(int[],int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.SET_VOLATILE, true, "(int[],int,int)void");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_ACQUIRE, true, "(int[],int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.SET_RELEASE, true, "(int[],int,int)void");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_OPAQUE, true, "(int[],int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.SET_OPAQUE, true, "(int[],int,int)void");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.COMPARE_AND_SET, true, "(int[],int,int,int)boolean");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(int[],int,int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(int[],int,int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(int[],int,int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(int[],int,int,int)boolean");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(int[],int,int,int)boolean");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(int[],int,int,int)boolean");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(int[],int,int,int)boolean");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_SET, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_ADD, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(int[],int,int)int");
+        checkVarHandleAccessMode(vai, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(int[],int,int)int");
+
+        System.out.print("vaj...");
+        checkNotNull(vaj);
+        checkVarType(vaj, long.class);
+        checkCoordinateTypes(vaj, "[class [J, int]");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET, true, "(long[],int)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.SET, true, "(long[],int,long)void");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_VOLATILE, true, "(long[],int)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.SET_VOLATILE, true, "(long[],int,long)void");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_ACQUIRE, true, "(long[],int)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.SET_RELEASE, true, "(long[],int,long)void");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_OPAQUE, true, "(long[],int)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.SET_OPAQUE, true, "(long[],int,long)void");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.COMPARE_AND_SET, true, "(long[],int,long,long)boolean");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(long[],int,long,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(long[],int,long,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(long[],int,long,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(long[],int,long,long)boolean");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(long[],int,long,long)boolean");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(long[],int,long,long)boolean");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(long[],int,long,long)boolean");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_SET, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_ADD, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(long[],int,long)long");
+        checkVarHandleAccessMode(vaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(long[],int,long)long");
+
+        System.out.print("vaf...");
+        checkNotNull(vaf);
+        checkVarType(vaf, float.class);
+        checkCoordinateTypes(vaf, "[class [F, int]");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET, true, "(float[],int)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.SET, true, "(float[],int,float)void");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_VOLATILE, true, "(float[],int)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.SET_VOLATILE, true, "(float[],int,float)void");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_ACQUIRE, true, "(float[],int)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.SET_RELEASE, true, "(float[],int,float)void");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_OPAQUE, true, "(float[],int)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.SET_OPAQUE, true, "(float[],int,float)void");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.COMPARE_AND_SET, true, "(float[],int,float,float)boolean");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(float[],int,float,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(float[],int,float,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(float[],int,float,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(float[],int,float,float)boolean");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(float[],int,float,float)boolean");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(float[],int,float,float)boolean");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(float[],int,float,float)boolean");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_SET, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_ADD, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(float[],int,float)float");
+        checkVarHandleAccessMode(vaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(float[],int,float)float");
+
+        System.out.print("vad...");
+        checkNotNull(vad);
+        checkVarType(vad, double.class);
+        checkCoordinateTypes(vad, "[class [D, int]");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET, true, "(double[],int)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.SET, true, "(double[],int,double)void");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_VOLATILE, true, "(double[],int)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.SET_VOLATILE, true, "(double[],int,double)void");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_ACQUIRE, true, "(double[],int)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.SET_RELEASE, true, "(double[],int,double)void");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_OPAQUE, true, "(double[],int)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.SET_OPAQUE, true, "(double[],int,double)void");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.COMPARE_AND_SET, true, "(double[],int,double,double)boolean");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(double[],int,double,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(double[],int,double,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(double[],int,double,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(double[],int,double,double)boolean");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(double[],int,double,double)boolean");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(double[],int,double,double)boolean");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(double[],int,double,double)boolean");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_SET, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_ADD, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(double[],int,double)double");
+        checkVarHandleAccessMode(vad, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(double[],int,double)double");
+
+        System.out.print("vao...");
+        checkNotNull(vao);
+        checkVarType(vao, Object.class);
+        checkCoordinateTypes(vao, "[class [Ljava.lang.Object;, int]");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET, true, "(Object[],int)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.SET, true, "(Object[],int,Object)void");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_VOLATILE, true, "(Object[],int)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.SET_VOLATILE, true, "(Object[],int,Object)void");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_ACQUIRE, true, "(Object[],int)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.SET_RELEASE, true, "(Object[],int,Object)void");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_OPAQUE, true, "(Object[],int)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.SET_OPAQUE, true, "(Object[],int,Object)void");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.COMPARE_AND_SET, true, "(Object[],int,Object,Object)boolean");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(Object[],int,Object,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(Object[],int,Object,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(Object[],int,Object,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(Object[],int,Object,Object)boolean");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(Object[],int,Object,Object)boolean");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(Object[],int,Object,Object)boolean");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(Object[],int,Object,Object)boolean");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_SET, true, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_ADD, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(Object[],int,Object)Object");
+        checkVarHandleAccessMode(vao, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(Object[],int,Object)Object");
+
+        System.out.print("vbaz...");
+        checkNull(vbaz);
+
+        System.out.print("vbab...");
+        checkNull(vbab);
+
+        System.out.print("vbac...");
+        checkNotNull(vbac);
+        checkVarType(vbac, char.class);
+        checkCoordinateTypes(vbac, "[class [B, int]");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET, true, "(byte[],int)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.SET, true, "(byte[],int,char)void");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_VOLATILE, true, "(byte[],int)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.SET_VOLATILE, true, "(byte[],int,char)void");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_ACQUIRE, true, "(byte[],int)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.SET_RELEASE, true, "(byte[],int,char)void");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_OPAQUE, true, "(byte[],int)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.SET_OPAQUE, true, "(byte[],int,char)void");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.COMPARE_AND_SET, false, "(byte[],int,char,char)boolean");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(byte[],int,char,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(byte[],int,char,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(byte[],int,char,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(byte[],int,char,char)boolean");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(byte[],int,char,char)boolean");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(byte[],int,char,char)boolean");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(byte[],int,char,char)boolean");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_SET, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_ADD, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(byte[],int,char)char");
+        checkVarHandleAccessMode(vbac, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(byte[],int,char)char");
+
+        System.out.print("vbas...");
+        checkNotNull(vbas);
+        checkVarType(vbas, short.class);
+        checkCoordinateTypes(vbas, "[class [B, int]");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET, true, "(byte[],int)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.SET, true, "(byte[],int,short)void");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_VOLATILE, true, "(byte[],int)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.SET_VOLATILE, true, "(byte[],int,short)void");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_ACQUIRE, true, "(byte[],int)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.SET_RELEASE, true, "(byte[],int,short)void");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_OPAQUE, true, "(byte[],int)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.SET_OPAQUE, true, "(byte[],int,short)void");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.COMPARE_AND_SET, false, "(byte[],int,short,short)boolean");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(byte[],int,short,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(byte[],int,short,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(byte[],int,short,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(byte[],int,short,short)boolean");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(byte[],int,short,short)boolean");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(byte[],int,short,short)boolean");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(byte[],int,short,short)boolean");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_SET, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_ADD, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(byte[],int,short)short");
+        checkVarHandleAccessMode(vbas, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(byte[],int,short)short");
+
+        System.out.print("vbai...");
+        checkNotNull(vbai);
+        checkVarType(vbai, int.class);
+        checkCoordinateTypes(vbai, "[class [B, int]");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET, true, "(byte[],int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.SET, true, "(byte[],int,int)void");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_VOLATILE, true, "(byte[],int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.SET_VOLATILE, true, "(byte[],int,int)void");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_ACQUIRE, true, "(byte[],int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.SET_RELEASE, true, "(byte[],int,int)void");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_OPAQUE, true, "(byte[],int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.SET_OPAQUE, true, "(byte[],int,int)void");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte[],int,int,int)boolean");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte[],int,int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte[],int,int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte[],int,int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte[],int,int,int)boolean");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte[],int,int,int)boolean");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte[],int,int,int)boolean");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte[],int,int,int)boolean");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_SET, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_ADD, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(byte[],int,int)int");
+        checkVarHandleAccessMode(vbai, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(byte[],int,int)int");
+
+        System.out.print("vbaj...");
+        checkNotNull(vbaj);
+        checkVarType(vbaj, long.class);
+        checkCoordinateTypes(vbaj, "[class [B, int]");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET, IS_64_BIT, "(byte[],int)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.SET, IS_64_BIT, "(byte[],int,long)void");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_VOLATILE, IS_64_BIT, "(byte[],int)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.SET_VOLATILE, IS_64_BIT, "(byte[],int,long)void");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_ACQUIRE, IS_64_BIT, "(byte[],int)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.SET_RELEASE, IS_64_BIT, "(byte[],int,long)void");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_OPAQUE, IS_64_BIT, "(byte[],int)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.SET_OPAQUE, IS_64_BIT, "(byte[],int,long)void");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte[],int,long,long)boolean");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte[],int,long,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte[],int,long,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte[],int,long,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte[],int,long,long)boolean");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte[],int,long,long)boolean");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte[],int,long,long)boolean");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte[],int,long,long)boolean");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_SET, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_ADD, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(byte[],int,long)long");
+        checkVarHandleAccessMode(vbaj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(byte[],int,long)long");
+
+        System.out.print("vbaf...");
+        checkNotNull(vbaf);
+        checkVarType(vbaf, float.class);
+        checkCoordinateTypes(vbaf, "[class [B, int]");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET, true, "(byte[],int)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.SET, true, "(byte[],int,float)void");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_VOLATILE, true, "(byte[],int)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.SET_VOLATILE, true, "(byte[],int,float)void");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_ACQUIRE, true, "(byte[],int)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.SET_RELEASE, true, "(byte[],int,float)void");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_OPAQUE, true, "(byte[],int)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.SET_OPAQUE, true, "(byte[],int,float)void");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte[],int,float,float)boolean");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte[],int,float,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte[],int,float,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte[],int,float,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte[],int,float,float)boolean");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte[],int,float,float)boolean");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte[],int,float,float)boolean");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte[],int,float,float)boolean");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_SET, true, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_ADD, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(byte[],int,float)float");
+        checkVarHandleAccessMode(vbaf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(byte[],int,float)float");
+
+        System.out.print("vbad...");
+        checkNotNull(vbad);
+        checkVarType(vbad, double.class);
+        checkCoordinateTypes(vbad, "[class [B, int]");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET, IS_64_BIT, "(byte[],int)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.SET, IS_64_BIT, "(byte[],int,double)void");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_VOLATILE, IS_64_BIT, "(byte[],int)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.SET_VOLATILE, IS_64_BIT, "(byte[],int,double)void");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_ACQUIRE, IS_64_BIT, "(byte[],int)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.SET_RELEASE, IS_64_BIT, "(byte[],int,double)void");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_OPAQUE, IS_64_BIT, "(byte[],int)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.SET_OPAQUE, IS_64_BIT, "(byte[],int,double)void");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.COMPARE_AND_SET, true, "(byte[],int,double,double)boolean");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(byte[],int,double,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(byte[],int,double,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(byte[],int,double,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(byte[],int,double,double)boolean");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(byte[],int,double,double)boolean");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(byte[],int,double,double)boolean");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(byte[],int,double,double)boolean");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_SET, true, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_ADD, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(byte[],int,double)double");
+        checkVarHandleAccessMode(vbad, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(byte[],int,double)double");
+
+        System.out.print("vbao...");
+        checkNull(vbao);
+
+        System.out.print("vbbz...");
+        checkNull(vbbz);
+
+        System.out.print("vbbb...");
+        checkNull(vbbb);
+
+        System.out.print("vbbc...");
+        checkNotNull(vbbc);
+        checkVarType(vbbc, char.class);
+        checkCoordinateTypes(vbbc, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET, true, "(ByteBuffer,int)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.SET, true, "(ByteBuffer,int,char)void");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_VOLATILE, true, "(ByteBuffer,int)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.SET_VOLATILE, true, "(ByteBuffer,int,char)void");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_ACQUIRE, true, "(ByteBuffer,int)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.SET_RELEASE, true, "(ByteBuffer,int,char)void");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_OPAQUE, true, "(ByteBuffer,int)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.SET_OPAQUE, true, "(ByteBuffer,int,char)void");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.COMPARE_AND_SET, false, "(ByteBuffer,int,char,char)boolean");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(ByteBuffer,int,char,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(ByteBuffer,int,char,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(ByteBuffer,int,char,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(ByteBuffer,int,char,char)boolean");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(ByteBuffer,int,char,char)boolean");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(ByteBuffer,int,char,char)boolean");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(ByteBuffer,int,char,char)boolean");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_SET, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_ADD, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(ByteBuffer,int,char)char");
+        checkVarHandleAccessMode(vbbc, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(ByteBuffer,int,char)char");
+
+        System.out.print("vbbs...");
+        checkNotNull(vbbs);
+        checkVarType(vbbs, short.class);
+        checkCoordinateTypes(vbbs, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET, true, "(ByteBuffer,int)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.SET, true, "(ByteBuffer,int,short)void");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_VOLATILE, true, "(ByteBuffer,int)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.SET_VOLATILE, true, "(ByteBuffer,int,short)void");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_ACQUIRE, true, "(ByteBuffer,int)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.SET_RELEASE, true, "(ByteBuffer,int,short)void");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_OPAQUE, true, "(ByteBuffer,int)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.SET_OPAQUE, true, "(ByteBuffer,int,short)void");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.COMPARE_AND_SET, false, "(ByteBuffer,int,short,short)boolean");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, false, "(ByteBuffer,int,short,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, false, "(ByteBuffer,int,short,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, false, "(ByteBuffer,int,short,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, false, "(ByteBuffer,int,short,short)boolean");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, false, "(ByteBuffer,int,short,short)boolean");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, false, "(ByteBuffer,int,short,short)boolean");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, false, "(ByteBuffer,int,short,short)boolean");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_SET, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_SET_RELEASE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_ADD, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(ByteBuffer,int,short)short");
+        checkVarHandleAccessMode(vbbs, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(ByteBuffer,int,short)short");
+
+        System.out.print("vbbi...");
+        checkNotNull(vbbi);
+        checkVarType(vbbi, int.class);
+        checkCoordinateTypes(vbbi, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET, true, "(ByteBuffer,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.SET, true, "(ByteBuffer,int,int)void");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_VOLATILE, true, "(ByteBuffer,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.SET_VOLATILE, true, "(ByteBuffer,int,int)void");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_ACQUIRE, true, "(ByteBuffer,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.SET_RELEASE, true, "(ByteBuffer,int,int)void");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_OPAQUE, true, "(ByteBuffer,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.SET_OPAQUE, true, "(ByteBuffer,int,int)void");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.COMPARE_AND_SET, true, "(ByteBuffer,int,int,int)boolean");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(ByteBuffer,int,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(ByteBuffer,int,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(ByteBuffer,int,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(ByteBuffer,int,int,int)boolean");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(ByteBuffer,int,int,int)boolean");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(ByteBuffer,int,int,int)boolean");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(ByteBuffer,int,int,int)boolean");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_SET, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_ADD, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(ByteBuffer,int,int)int");
+        checkVarHandleAccessMode(vbbi, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(ByteBuffer,int,int)int");
+
+        System.out.print("vbbj...");
+        checkNotNull(vbbj);
+        checkVarType(vbbj, long.class);
+        checkCoordinateTypes(vbbj, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET, IS_64_BIT, "(ByteBuffer,int)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.SET, IS_64_BIT, "(ByteBuffer,int,long)void");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_VOLATILE, IS_64_BIT, "(ByteBuffer,int)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.SET_VOLATILE, IS_64_BIT, "(ByteBuffer,int,long)void");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_ACQUIRE, IS_64_BIT, "(ByteBuffer,int)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.SET_RELEASE, IS_64_BIT, "(ByteBuffer,int,long)void");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_OPAQUE, IS_64_BIT, "(ByteBuffer,int)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.SET_OPAQUE, IS_64_BIT, "(ByteBuffer,int,long)void");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.COMPARE_AND_SET, true, "(ByteBuffer,int,long,long)boolean");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(ByteBuffer,int,long,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(ByteBuffer,int,long,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(ByteBuffer,int,long,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(ByteBuffer,int,long,long)boolean");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(ByteBuffer,int,long,long)boolean");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(ByteBuffer,int,long,long)boolean");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(ByteBuffer,int,long,long)boolean");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_SET, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_ADD, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_ADD_RELEASE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_OR, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_AND, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_XOR, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, true, "(ByteBuffer,int,long)long");
+        checkVarHandleAccessMode(vbbj, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, true, "(ByteBuffer,int,long)long");
+
+        System.out.print("vbbf...");
+        checkNotNull(vbbf);
+        checkVarType(vbbf, float.class);
+        checkCoordinateTypes(vbbf, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET, true, "(ByteBuffer,int)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.SET, true, "(ByteBuffer,int,float)void");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_VOLATILE, true, "(ByteBuffer,int)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.SET_VOLATILE, true, "(ByteBuffer,int,float)void");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_ACQUIRE, true, "(ByteBuffer,int)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.SET_RELEASE, true, "(ByteBuffer,int,float)void");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_OPAQUE, true, "(ByteBuffer,int)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.SET_OPAQUE, true, "(ByteBuffer,int,float)void");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.COMPARE_AND_SET, true, "(ByteBuffer,int,float,float)boolean");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(ByteBuffer,int,float,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(ByteBuffer,int,float,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(ByteBuffer,int,float,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(ByteBuffer,int,float,float)boolean");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(ByteBuffer,int,float,float)boolean");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(ByteBuffer,int,float,float)boolean");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(ByteBuffer,int,float,float)boolean");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_SET, true, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_ADD, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(ByteBuffer,int,float)float");
+        checkVarHandleAccessMode(vbbf, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(ByteBuffer,int,float)float");
+
+        System.out.print("vbbd...");
+        checkNotNull(vbbd);
+        checkVarType(vbbd, double.class);
+        checkCoordinateTypes(vbbd, "[class java.nio.ByteBuffer, int]");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET, IS_64_BIT, "(ByteBuffer,int)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.SET, IS_64_BIT, "(ByteBuffer,int,double)void");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_VOLATILE, IS_64_BIT, "(ByteBuffer,int)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.SET_VOLATILE, IS_64_BIT, "(ByteBuffer,int,double)void");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_ACQUIRE, IS_64_BIT, "(ByteBuffer,int)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.SET_RELEASE, IS_64_BIT, "(ByteBuffer,int,double)void");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_OPAQUE, IS_64_BIT, "(ByteBuffer,int)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.SET_OPAQUE, IS_64_BIT, "(ByteBuffer,int,double)void");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.COMPARE_AND_SET, true, "(ByteBuffer,int,double,double)boolean");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE, true, "(ByteBuffer,int,double,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, true, "(ByteBuffer,int,double,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, true, "(ByteBuffer,int,double,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, true, "(ByteBuffer,int,double,double)boolean");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET, true, "(ByteBuffer,int,double,double)boolean");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, true, "(ByteBuffer,int,double,double)boolean");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, true, "(ByteBuffer,int,double,double)boolean");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_SET, true, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_SET_ACQUIRE, true, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_SET_RELEASE, true, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_ADD, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_ADD_RELEASE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_OR, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_AND, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_XOR, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, false, "(ByteBuffer,int,double)double");
+        checkVarHandleAccessMode(vbbd, VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, false, "(ByteBuffer,int,double)double");
+
+        System.out.print("vbbo...");
+        checkNull(vbbo);
+
+        System.out.println("PASS");
+    }
+
+    private static void checkAccessMode(final VarHandle.AccessMode accessMode,
+                                        final String expectedName,
+                                        final String expectedMethodName,
+                                        final int expectedOrdinal) {
+        final String actualName = accessMode.toString();
+        if (!actualName.equals(expectedName)) {
+            fail("AccessMode " + actualName + " != " + expectedName);
+        }
+
+        final String actualMethodName = accessMode.methodName();
+        if (!actualMethodName.equals(expectedMethodName)) {
+            fail("AccessMode " + actualName + " method name " + actualMethodName + " != " +
+                 expectedMethodName);
+        }
+
+        final int actualOrdinal = accessMode.ordinal();
+        if (actualOrdinal != expectedOrdinal) {
+            fail("AccessMode " + accessMode + " ordinal " + actualOrdinal + " != " +
+                 expectedOrdinal);
+        }
+
+        VarHandle.AccessMode accessModeByName = VarHandle.AccessMode.valueOf(expectedName);
+        if (accessModeByName != accessMode) {
+            fail("AccessMode.valueOf(" + expectedName + ") returned " + accessModeByName);
+        }
+    }
+
+    private static void checkAccessModes() {
+        System.out.print("checkAccessModes...");
+        final int expectedLength = 31;
+        // Check we're not missing tests if the number of access modes ever changes.
+        if (VarHandle.AccessMode.values().length != expectedLength) {
+            fail("VarHandle.AccessMode.value().length != " + expectedLength);
+        }
+        checkAccessMode(VarHandle.AccessMode.GET, "GET", "get", 0);
+        checkAccessMode(VarHandle.AccessMode.SET, "SET", "set", 1);
+        checkAccessMode(VarHandle.AccessMode.GET_VOLATILE, "GET_VOLATILE", "getVolatile", 2);
+        checkAccessMode(VarHandle.AccessMode.SET_VOLATILE, "SET_VOLATILE", "setVolatile", 3);
+        checkAccessMode(VarHandle.AccessMode.GET_ACQUIRE, "GET_ACQUIRE", "getAcquire", 4);
+        checkAccessMode(VarHandle.AccessMode.SET_RELEASE, "SET_RELEASE", "setRelease", 5);
+        checkAccessMode(VarHandle.AccessMode.GET_OPAQUE, "GET_OPAQUE", "getOpaque", 6);
+        checkAccessMode(VarHandle.AccessMode.SET_OPAQUE, "SET_OPAQUE", "setOpaque", 7);
+        checkAccessMode(VarHandle.AccessMode.COMPARE_AND_SET, "COMPARE_AND_SET", "compareAndSet", 8);
+        checkAccessMode(VarHandle.AccessMode.COMPARE_AND_EXCHANGE, "COMPARE_AND_EXCHANGE", "compareAndExchange", 9);
+        checkAccessMode(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE, "COMPARE_AND_EXCHANGE_ACQUIRE", "compareAndExchangeAcquire", 10);
+        checkAccessMode(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE, "COMPARE_AND_EXCHANGE_RELEASE", "compareAndExchangeRelease", 11);
+        checkAccessMode(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN, "WEAK_COMPARE_AND_SET_PLAIN", "weakCompareAndSetPlain", 12);
+        checkAccessMode(VarHandle.AccessMode.WEAK_COMPARE_AND_SET, "WEAK_COMPARE_AND_SET", "weakCompareAndSet", 13);
+        checkAccessMode(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE, "WEAK_COMPARE_AND_SET_ACQUIRE", "weakCompareAndSetAcquire", 14);
+        checkAccessMode(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE, "WEAK_COMPARE_AND_SET_RELEASE", "weakCompareAndSetRelease", 15);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_SET, "GET_AND_SET", "getAndSet", 16);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_SET_ACQUIRE, "GET_AND_SET_ACQUIRE", "getAndSetAcquire", 17);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_SET_RELEASE, "GET_AND_SET_RELEASE", "getAndSetRelease", 18);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_ADD, "GET_AND_ADD", "getAndAdd", 19);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_ADD_ACQUIRE, "GET_AND_ADD_ACQUIRE", "getAndAddAcquire", 20);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_ADD_RELEASE, "GET_AND_ADD_RELEASE", "getAndAddRelease", 21);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_OR, "GET_AND_BITWISE_OR", "getAndBitwiseOr", 22);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE, "GET_AND_BITWISE_OR_RELEASE", "getAndBitwiseOrRelease", 23);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE, "GET_AND_BITWISE_OR_ACQUIRE", "getAndBitwiseOrAcquire", 24);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_AND, "GET_AND_BITWISE_AND", "getAndBitwiseAnd", 25);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE, "GET_AND_BITWISE_AND_RELEASE", "getAndBitwiseAndRelease", 26);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE, "GET_AND_BITWISE_AND_ACQUIRE", "getAndBitwiseAndAcquire", 27);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_XOR, "GET_AND_BITWISE_XOR", "getAndBitwiseXor", 28);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE, "GET_AND_BITWISE_XOR_RELEASE", "getAndBitwiseXorRelease", 29);
+        checkAccessMode(VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE, "GET_AND_BITWISE_XOR_ACQUIRE", "getAndBitwiseXorAcquire", 30);
+        System.out.println("PASS");
+    }
+
+    public static class LookupCheckA {
+        public String fieldA = "123";
+        public Object fieldB = "123";
+        protected int fieldC = 0;
+        private int fieldD = 0;
+
+        public static String staticFieldA = "123";
+        public static Object staticFieldB = "123";
+        protected static int staticFieldC = 0;
+        private static int staticFieldD = 0;
+
+        private static final VarHandle vhA;
+        private static final VarHandle vhB;
+        private static final VarHandle vhC;
+        private static final VarHandle vhD;
+
+        private static final VarHandle vhsA;
+        private static final VarHandle vhsB;
+        private static final VarHandle vhsC;
+        private static final VarHandle vhsD;
+
+        static {
+            try {
+                // Instance fields
+                try {
+                    // Mis-spelling field name
+                    MethodHandles.lookup().findVarHandle(LookupCheckA.class, "feldA", Object.class);
+                    fail("Misspelled field name succeeded.");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Using wrong field type
+                    MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldA", Float.class);
+                    fail("Misspelled field name succeeded.");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Using wrong field type
+                    MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldB", Float.class);
+                    fail("Wrong field type succeeded.");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Looking up static field
+                    MethodHandles.lookup().findVarHandle(LookupCheckA.class, "staticFieldA", String.class);
+                    fail("Static field resolved as instance field.");
+                } catch (IllegalAccessException e) {}
+
+                vhA = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldA", String.class);
+                vhB = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldB", Object.class);
+                vhC = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldC", int.class);
+                vhD = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldD", int.class);
+
+                // Static fields
+                try {
+                    // Mis-spelling field name
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFeldA", Object.class);
+                    fail("Misspelled field name succeeded.");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Using wrong field type
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldA", Float.class);
+                    fail("Misspelled field name succeeded.");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Using wrong field type
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldB", Float.class);
+                    fail("Wrong field type succeeded");
+                } catch (NoSuchFieldException e) {}
+
+                try {
+                    // Looking up instance field
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "fieldA", String.class);
+                    fail("Instance field resolved as static field");
+                } catch (IllegalAccessException e) {}
+
+                vhsA = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldA", String.class);
+                vhsB = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldB", Object.class);
+                vhsC = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldC", int.class);
+                vhsD = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldD", int.class);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        protected static void fail(String reason) {
+            Main.fail(reason);
+        }
+
+        public static void run() {
+            System.out.print("LookupCheckA...");
+            if (vhA == null) fail("vhA is null");
+            if (vhB == null) fail("vhB is null");
+            if (vhC == null) fail("vhC is null");
+            if (vhD == null) fail("vhD is null");
+            if (vhsA == null) fail("vhsA is null");
+            if (vhsB == null) fail("vhsB is null");
+            if (vhsC == null) fail("vhsC is null");
+            if (vhsD == null) fail("vhsD is null");
+            System.out.println("PASS");
+        }
+    }
+
+    final static class LookupCheckB extends LookupCheckA {
+        private static final VarHandle vhA;
+        private static final VarHandle vhB;
+        private static final VarHandle vhC;
+
+        private static final VarHandle vhsA;
+        private static final VarHandle vhsB;
+        private static final VarHandle vhsC;
+
+        static {
+            try {
+                vhA = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldA", String.class);
+                MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldA", String.class);
+
+                vhB = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldB", Object.class);
+                MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldB", Object.class);
+
+                vhC = MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldC", int.class);
+                MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldC", int.class);
+
+                try {
+                    MethodHandles.lookup().findVarHandle(LookupCheckA.class, "fieldD", int.class);
+                    fail("Accessing private field");
+                } catch (IllegalAccessException e) {}
+
+                vhsA = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldA", String.class);
+                MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldA", String.class);
+
+                vhsB = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldB", Object.class);
+                MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldB", Object.class);
+
+                vhsC = MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldC", int.class);
+                MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldC", int.class);
+
+                try {
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckA.class, "staticFieldD", int.class);
+                    fail("Accessing private field");
+                } catch (IllegalAccessException e) {}
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public static void run() {
+            // Testing access
+            System.out.print("LookupCheckB...");
+            if (vhA == null) fail("vhA is null");
+            if (vhB == null) fail("vhB is null");
+            if (vhC == null) fail("vhC is null");
+            if (vhsA == null) fail("vhsA is null");
+            if (vhsB == null) fail("vhsB is null");
+            if (vhsC == null) fail("vhsC is null");
+            System.out.println("PASS");
+        }
+    }
+
+    public static class LookupCheckC {
+        private static final VarHandle vhA;
+        private static final VarHandle vhB;
+        private static final VarHandle vhC;
+        private static final VarHandle vhsA;
+        private static final VarHandle vhsB;
+        private static final VarHandle vhsC;
+
+        static {
+            try {
+                vhA = MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldA", String.class);
+                try {
+                    MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldA", Float.class);
+                } catch (NoSuchFieldException e) {}
+                vhB = MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldB", Object.class);
+                try {
+                    MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldB", int.class);
+                } catch (NoSuchFieldException e) {}
+                vhC = MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldC", int.class);
+                try {
+                    MethodHandles.lookup().findVarHandle(LookupCheckB.class, "fieldD", int.class);
+                    fail("Accessing private field in unrelated class");
+                } catch (IllegalAccessException e) {}
+
+                vhsA = MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldA", String.class);
+                try {
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldA", Float.class);
+                } catch (NoSuchFieldException e) {}
+                vhsB = MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldB", Object.class);
+                try {
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldB", int.class);
+                } catch (NoSuchFieldException e) {}
+                vhsC = MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldC", int.class);
+                try {
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "staticFieldD", int.class);
+                    fail("Accessing private field in unrelated class");
+                } catch (IllegalAccessException e) {}
+
+                try {
+                    MethodHandles.lookup().findStaticVarHandle(LookupCheckB.class, "fieldA", String.class);
+                    fail("Found instance field looking for static");
+                } catch (IllegalAccessException e) {}
+                try {
+                    MethodHandles.lookup().findVarHandle(LookupCheckB.class, "staticFieldA", String.class);
+                    fail("Found static field looking for instance");
+                } catch (IllegalAccessException e) {}
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public static void run() {
+            System.out.print("UnreflectCheck...");
+            if (vhA == null) fail("vhA is null");
+            if (vhB == null) fail("vhB is null");
+            if (vhsA == null) fail("vhsA is null");
+            if (vhsB == null) fail("vhsB is null");
+            System.out.println("PASS");
+        }
+    }
+
+    public static final class UnreflectCheck {
+        private static final VarHandle vhA;
+        private static final VarHandle vhsA;
+
+        static {
+            try {
+                Field publicField = LookupCheckA.class.getField("fieldA");
+                vhA = MethodHandles.lookup().unreflectVarHandle(publicField);
+                try {
+                    Field protectedField = LookupCheckA.class.getField("fieldC");
+                    MethodHandles.lookup().unreflectVarHandle(protectedField);
+                    fail("Unreflected protected field");
+                } catch (NoSuchFieldException e) {}
+                try {
+                    Field privateField = LookupCheckA.class.getField("fieldD");
+                    MethodHandles.lookup().unreflectVarHandle(privateField);
+                    fail("Unreflected private field");
+                } catch (NoSuchFieldException e) {}
+                try {
+                    Field privateField = LookupCheckA.class.getField("fieldD");
+                    privateField.setAccessible(true);
+                    MethodHandles.lookup().unreflectVarHandle(privateField);
+                    fail("Unreflected private field");
+                } catch (NoSuchFieldException e) {}
+
+                Field staticPublicField = LookupCheckA.class.getField("staticFieldA");
+                vhsA = MethodHandles.lookup().unreflectVarHandle(staticPublicField);
+                try {
+                    Field protectedField = LookupCheckA.class.getField("staticFieldC");
+                    MethodHandles.lookup().unreflectVarHandle(protectedField);
+                    fail("Unreflected protected field");
+                } catch (NoSuchFieldException e) {}
+                try {
+                    Field privateField = LookupCheckA.class.getField("staticFieldD");
+                    MethodHandles.lookup().unreflectVarHandle(privateField);
+                    fail("Unreflected private field");
+                } catch (NoSuchFieldException e) {}
+                try {
+                    Field privateField = LookupCheckA.class.getField("staticFieldD");
+                    privateField.setAccessible(true);
+                    MethodHandles.lookup().unreflectVarHandle(privateField);
+                    fail("Unreflected private field");
+                } catch (NoSuchFieldException e) {}
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public static void run() {
+            System.out.print("LookupCheckC...");
+            if (vhA == null) fail("vhA is null");
+            if (vhsA == null) fail("vhsA is null");
+            System.out.println("PASS");
+        }
+    }
+
+    public static void main(String[] args) {
+        checkAccessModes();
+        checkInstantiatedVarHandles();
+        LookupCheckA.run();
+        LookupCheckB.run();
+        LookupCheckC.run();
+        UnreflectCheck.run();
+    }
+}
+
diff --git a/test/910-methods/build b/test/910-methods/build
index 42b99ad..10ffcc5 100644
--- a/test/910-methods/build
+++ b/test/910-methods/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/910-methods/check b/test/910-methods/check
index f9552ad..e6f7d77 100644
--- a/test/910-methods/check
+++ b/test/910-methods/check
@@ -19,7 +19,7 @@
   patch -p0 expected.txt < expected_jack.diff
 fi
 
-if [[ "$DX" == 'd8' ]]; then
+if [[ "$USE_D8" == true ]]; then
   patch -p0 expected.txt < expected_d8.diff
 fi
 
diff --git a/test/911-get-stack-trace/build b/test/911-get-stack-trace/build
index 42b99ad..10ffcc5 100644
--- a/test/911-get-stack-trace/build
+++ b/test/911-get-stack-trace/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/913-heaps/build b/test/913-heaps/build
index 42b99ad..10ffcc5 100644
--- a/test/913-heaps/build
+++ b/test/913-heaps/build
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # See b/65168732
-export DX=$ANDROID_HOST_OUT/bin/dx
+export USE_D8=false
 
 ./default-build "$@"
diff --git a/test/959-invoke-polymorphic-accessors/expected.txt b/test/959-invoke-polymorphic-accessors/expected.txt
index de2916b..9df450b 100644
--- a/test/959-invoke-polymorphic-accessors/expected.txt
+++ b/test/959-invoke-polymorphic-accessors/expected.txt
@@ -2,3 +2,4 @@
 Passed MethodHandles.Lookup tests for accessors.
 Passed MethodHandle.invokeExact() tests for accessors.
 Passed MethodHandle.invoke() tests for accessors.
+Passed MethodHandles.unreflect(Field) tests.
diff --git a/test/959-invoke-polymorphic-accessors/src/Main.java b/test/959-invoke-polymorphic-accessors/src/Main.java
index 59db807..cdde1de 100644
--- a/test/959-invoke-polymorphic-accessors/src/Main.java
+++ b/test/959-invoke-polymorphic-accessors/src/Main.java
@@ -16,6 +16,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.WrongMethodTypeException;
+import java.lang.reflect.Field;
 
 public class Main {
 
@@ -42,11 +43,25 @@
 
         public final int m_fi = 0xa5a5a5a5;
         public static final int s_fi = 0x5a5a5a5a;
+
+        private boolean m_pz;
+        private static final boolean s_fz = false;
     }
 
     public static class Tester {
-        public static void assertActualAndExpectedMatch(boolean actual, boolean expected)
-                throws AssertionError {
+        public static void assertEquals(boolean expected, boolean actual) {
+            if (actual != expected) {
+                throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")");
+            }
+        }
+
+        public static void assertEquals(char expected, char actual) {
+            if (actual != expected) {
+                throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")");
+            }
+        }
+
+        public static void assertEquals(int expected, int actual) {
             if (actual != expected) {
                 throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")");
             }
@@ -58,8 +73,8 @@
             }
         }
 
-        public static void unreachable() throws Throwable{
-            throw new Error("unreachable");
+        public static void fail() throws Throwable{
+            throw new Error("fail");
         }
     }
 
@@ -97,7 +112,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
@@ -110,16 +125,16 @@
             try {
                 final byte got;
                 if (v == null) {
-                    got = (byte)m.invokeExact();
+                    got = (byte) m.invokeExact();
                 } else {
-                    got = (byte)m.invokeExact(v);
+                    got = (byte) m.invokeExact(v);
                 }
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
@@ -140,7 +155,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
@@ -153,16 +168,16 @@
             try {
                 final char got;
                 if (v == null) {
-                    got = (char)m.invokeExact();
+                    got = (char) m.invokeExact();
                 } else {
-                    got = (char)m.invokeExact(v);
+                    got = (char) m.invokeExact(v);
                 }
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
@@ -183,7 +198,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
@@ -194,13 +209,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final short got = (v == null) ? (short)m.invokeExact() : (short)m.invokeExact(v);
+                final short got = (v == null) ? (short) m.invokeExact() : (short) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
@@ -221,7 +236,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
@@ -232,13 +247,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final int got = (v == null) ? (int)m.invokeExact() : (int)m.invokeExact(v);
+                final int got = (v == null) ? (int) m.invokeExact() : (int) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
@@ -259,7 +274,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
@@ -270,13 +285,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final long got = (v == null) ? (long)m.invokeExact() : (long)m.invokeExact(v);
+                final long got = (v == null) ? (long) m.invokeExact() : (long) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
@@ -297,7 +312,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
@@ -308,13 +323,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final float got = (v == null) ? (float)m.invokeExact() : (float)m.invokeExact(v);
+                final float got = (v == null) ? (float) m.invokeExact() : (float) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
@@ -335,7 +350,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setDouble(MethodHandle m, double value, boolean expectFailure)
@@ -347,13 +362,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final double got = (v == null) ? (double)m.invokeExact() : (double)m.invokeExact(v);
+                final double got = (v == null) ? (double) m.invokeExact() : (double) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getDouble(MethodHandle m, double value, boolean expectFailure)
@@ -375,7 +390,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setString(MethodHandle m, String value, boolean expectFailure)
@@ -387,13 +402,13 @@
                 throws Throwable {
             boolean exceptionThrown = false;
             try {
-                final String got = (v == null) ? (String)m.invokeExact() : (String)m.invokeExact(v);
+                final String got = (v == null) ? (String) m.invokeExact() : (String) m.invokeExact(v);
                 assertTrue(got.equals(value));
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getString(MethodHandle m, String value, boolean expectFailure)
@@ -415,7 +430,7 @@
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void setBoolean(MethodHandle m, boolean value, boolean expectFailure)
@@ -428,13 +443,13 @@
             boolean exceptionThrown = false;
             try {
                 final boolean got =
-                        (v == null) ? (boolean)m.invokeExact() : (boolean)m.invokeExact(v);
+                        (v == null) ? (boolean) m.invokeExact() : (boolean) m.invokeExact(v);
                 assertTrue(got == value);
             }
             catch (WrongMethodTypeException e) {
                 exceptionThrown = true;
             }
-            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+            assertEquals(expectFailure, exceptionThrown);
         }
 
         static void getBoolean(MethodHandle m, boolean value, boolean expectFailure)
@@ -454,7 +469,7 @@
                                 Object value,
                                 AccessorType accessor) throws Throwable {
             boolean booleanValue =
-                    value instanceof Boolean ? ((Boolean)value).booleanValue() : false;
+                    value instanceof Boolean ? ((Boolean) value).booleanValue() : false;
             setBoolean(methodHandle, valueHolder, booleanValue,
                        resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IPUT));
             setBoolean(methodHandle, booleanValue,
@@ -464,7 +479,7 @@
             getBoolean(methodHandle, booleanValue,
                        resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SGET));
 
-            byte byteValue = value instanceof Byte ? ((Byte)value).byteValue() : (byte)0;
+            byte byteValue = value instanceof Byte ? ((Byte) value).byteValue() : (byte) 0;
             setByte(methodHandle, valueHolder, byteValue,
                     resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IPUT));
             setByte(methodHandle, byteValue,
@@ -474,7 +489,7 @@
             getByte(methodHandle, byteValue,
                     resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SGET));
 
-            char charValue = value instanceof Character ? ((Character)value).charValue() : 'z';
+            char charValue = value instanceof Character ? ((Character) value).charValue() : 'z';
             setChar(methodHandle, valueHolder, charValue,
                     resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IPUT));
             setChar(methodHandle, charValue,
@@ -484,7 +499,7 @@
             getChar(methodHandle, charValue,
                     resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SGET));
 
-            short shortValue = value instanceof Short ? ((Short)value).shortValue() : (short)0;
+            short shortValue = value instanceof Short ? ((Short) value).shortValue() : (short) 0;
             setShort(methodHandle, valueHolder, shortValue,
                      resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IPUT));
             setShort(methodHandle, shortValue,
@@ -494,7 +509,7 @@
             getShort(methodHandle, shortValue,
                     resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SGET));
 
-            int intValue = value instanceof Integer ? ((Integer)value).intValue() : -1;
+            int intValue = value instanceof Integer ? ((Integer) value).intValue() : -1;
             setInt(methodHandle, valueHolder, intValue,
                    resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IPUT));
             setInt(methodHandle, intValue,
@@ -504,7 +519,7 @@
             getInt(methodHandle, intValue,
                    resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SGET));
 
-            long longValue = value instanceof Long ? ((Long)value).longValue() : (long)-1;
+            long longValue = value instanceof Long ? ((Long) value).longValue() : (long) -1;
             setLong(methodHandle, valueHolder, longValue,
                     resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IPUT));
             setLong(methodHandle, longValue,
@@ -514,7 +529,7 @@
             getLong(methodHandle, longValue,
                     resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SGET));
 
-            float floatValue = value instanceof Float ? ((Float)value).floatValue() : -1.0f;
+            float floatValue = value instanceof Float ? ((Float) value).floatValue() : -1.0f;
             setFloat(methodHandle, valueHolder, floatValue,
                     resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IPUT));
             setFloat(methodHandle, floatValue,
@@ -524,7 +539,7 @@
             getFloat(methodHandle, floatValue,
                      resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SGET));
 
-            double doubleValue = value instanceof Double ? ((Double)value).doubleValue() : -1.0;
+            double doubleValue = value instanceof Double ? ((Double) value).doubleValue() : -1.0;
             setDouble(methodHandle, valueHolder, doubleValue,
                       resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IPUT));
             setDouble(methodHandle, doubleValue,
@@ -564,7 +579,7 @@
                 assertTrue(ValueHolder.s_z == b);
             }
 
-            byte [] bytes = { (byte)0x73, (byte)0xfe };
+            byte [] bytes = { (byte) 0x73, (byte) 0xfe };
             for (byte b : bytes) {
                 Byte boxed = new Byte(b);
                 tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class),
@@ -594,7 +609,7 @@
                 assertTrue(ValueHolder.s_c == c);
             }
 
-            short [] shorts = { (short)0x1234, (short)0x4321 };
+            short [] shorts = { (short) 0x1234, (short) 0x4321 };
             for (short s : shorts) {
                 Short boxed = new Short(s);
                 tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class),
@@ -626,7 +641,7 @@
 
             float [] floats = { 0.99f, -1.23e-17f };
             for (float f : floats) {
-                Float boxed = new Float(f);
+                Float boxed = Float.valueOf(f);
                 tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class),
                             valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
                 tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class),
@@ -641,7 +656,7 @@
 
             double [] doubles = { 0.44444444444e37, -0.555555555e-37 };
             for (double d : doubles) {
-                Double boxed = new Double(d);
+                Double boxed = Double.valueOf(d);
                 tryAccessor(lookup.findSetter(ValueHolder.class, "m_d", double.class),
                             valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT);
                 tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class),
@@ -694,41 +709,41 @@
             // (ValueHolder) is initialized. This happens in the
             // invoke-polymorphic dispatch.
             MethodHandles.Lookup lookup = MethodHandles.lookup();
-            try {
+            {
                 MethodHandle mh = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
-                int initialValue = (int)mh.invokeExact();
+                int initialValue = (int) mh.invokeExact();
                 System.out.println(initialValue);
-            } catch (NoSuchFieldException e) { unreachable(); }
-            try {
+            }
+            {
                 MethodHandle mh = lookup.findStaticSetter(ValueHolder.class, "s_i", int.class);
                 mh.invokeExact(0);
-            } catch (NoSuchFieldException e) { unreachable(); }
+            }
             try {
                 lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class);
-                unreachable();
-            } catch (NoSuchFieldException e) {}
+                fail();
+            } catch (NoSuchFieldException expected) {}
             try {
                 lookup.findGetter(ValueHolder.class, "s_fi", byte.class);
-                unreachable();
-            } catch (NoSuchFieldException e) {}
+                fail();
+            } catch (NoSuchFieldException eexpected) {}
             try {
                 lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class);
-                unreachable();
-            } catch (IllegalAccessException e) {}
+                fail();
+            } catch (IllegalAccessException expected) {}
 
             lookup.findGetter(ValueHolder.class, "m_fi", int.class);
             try {
                 lookup.findGetter(ValueHolder.class, "m_fi", byte.class);
-                unreachable();
-            } catch (NoSuchFieldException e) {}
+                fail();
+            } catch (NoSuchFieldException expected) {}
             try {
                 lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class);
-                unreachable();
-            } catch (NoSuchFieldException e) {}
+                fail();
+            } catch (NoSuchFieldException expected) {}
             try {
                 lookup.findSetter(ValueHolder.class, "m_fi", int.class);
-                unreachable();
-            } catch (IllegalAccessException e) {}
+                fail();
+            } catch (IllegalAccessException expected) {}
 
             System.out.println("Passed MethodHandles.Lookup tests for accessors.");
         }
@@ -739,22 +754,22 @@
             MethodHandles.Lookup lookup = MethodHandles.lookup();
             MethodHandle h0 = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
             h0.invoke();
-            Number t = (Number)h0.invoke();
-            int u = (int)h0.invoke();
-            Integer v = (Integer)h0.invoke();
-            long w = (long)h0.invoke();
+            Number t = (Number) h0.invoke();
+            int u = (int) h0.invoke();
+            Integer v = (Integer) h0.invoke();
+            long w = (long) h0.invoke();
             try {
-                byte x = (byte)h0.invoke();
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                byte x = (byte) h0.invoke();
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
-                String y = (String)h0.invoke();
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                String y = (String) h0.invoke();
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
-                Long z = (Long)h0.invoke();
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                Long z = (Long) h0.invoke();
+                fail();
+            } catch (WrongMethodTypeException expected) {}
         }
 
         private static void testMemberGetter() throws Throwable {
@@ -762,32 +777,32 @@
             MethodHandles.Lookup lookup = MethodHandles.lookup();
             MethodHandle h0 = lookup.findGetter(ValueHolder.class, "m_fi", int.class);
             h0.invoke(valueHolder);
-            Number t = (Number)h0.invoke(valueHolder);
-            int u = (int)h0.invoke(valueHolder);
-            Integer v = (Integer)h0.invoke(valueHolder);
-            long w = (long)h0.invoke(valueHolder);
+            Number t = (Number) h0.invoke(valueHolder);
+            int u = (int) h0.invoke(valueHolder);
+            Integer v = (Integer) h0.invoke(valueHolder);
+            long w = (long) h0.invoke(valueHolder);
             try {
-                byte x = (byte)h0.invoke(valueHolder);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                byte x = (byte) h0.invoke(valueHolder);
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
-                String y = (String)h0.invoke(valueHolder);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                String y = (String) h0.invoke(valueHolder);
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
-                Long z = (Long)h0.invoke(valueHolder);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                Long z = (Long) h0.invoke(valueHolder);
+                fail();
+            } catch (WrongMethodTypeException expected) {}
         }
 
         /*package*/ static Number getDoubleAsNumber() {
-            return new Double(1.4e77);
+            return Double.valueOf(1.4e77);
         }
         /*package*/ static Number getFloatAsNumber() {
-            return new Float(7.77);
+            return Float.valueOf(7.77f);
         }
         /*package*/ static Object getFloatAsObject() {
-            return new Float(-7.77);
+            return Float.valueOf(-7.77f);
         }
 
         private static void testMemberSetter() throws Throwable {
@@ -796,7 +811,7 @@
             MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class);
             MethodHandle s0 = lookup.findSetter(ValueHolder.class, "m_s", short.class);
             h0.invoke(valueHolder, 0.22f);
-            h0.invoke(valueHolder, new Float(1.11f));
+            h0.invoke(valueHolder, Float.valueOf(1.11f));
             Number floatNumber = getFloatAsNumber();
             h0.invoke(valueHolder, floatNumber);
             assertTrue(valueHolder.m_f == floatNumber.floatValue());
@@ -804,17 +819,17 @@
             h0.invoke(valueHolder, objNumber);
             assertTrue(valueHolder.m_f == ((Float) objNumber).floatValue());
             try {
-              h0.invoke(valueHolder, (Float)null);
-              unreachable();
-            } catch (NullPointerException e) {}
+              h0.invoke(valueHolder, (Float) null);
+              fail();
+            } catch (NullPointerException expected) {}
 
             // Test that type conversion checks work on small field types.
-            short temp = (short)s0.invoke(valueHolder, new Byte((byte)45));
+            short temp = (short) s0.invoke(valueHolder, new Byte((byte) 45));
             assertTrue(temp == 0);
             assertTrue(valueHolder.m_s == 45);
 
-            h0.invoke(valueHolder, (byte)1);
-            h0.invoke(valueHolder, (short)2);
+            h0.invoke(valueHolder, (byte) 1);
+            h0.invoke(valueHolder, (short) 2);
             h0.invoke(valueHolder, 3);
             h0.invoke(valueHolder, 4l);
 
@@ -824,32 +839,32 @@
 
             try {
                 h0.invoke(valueHolder, 0.33);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
                 Number doubleNumber = getDoubleAsNumber();
                 h0.invoke(valueHolder, doubleNumber);
-                unreachable();
-            } catch (ClassCastException e) {}
+                fail();
+            } catch (ClassCastException expected) {}
             try {
                 Number doubleNumber = null;
                 h0.invoke(valueHolder, doubleNumber);
-                unreachable();
-            } catch (NullPointerException e) {}
-            try {
+                fail();
+            } catch (NullPointerException expected) {}
+            {
                 // Mismatched return type - float != void
-                float tmp = (float)h0.invoke(valueHolder, 0.45f);
+                float tmp = (float) h0.invoke(valueHolder, 0.45f);
                 assertTrue(tmp == 0.0);
-            } catch (Exception e) { unreachable(); }
+            }
             try {
                 h0.invoke(valueHolder, "bam");
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
                 String s = null;
                 h0.invoke(valueHolder, s);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
         }
 
         private static void testStaticSetter() throws Throwable {
@@ -857,23 +872,23 @@
             MethodHandle s0 = lookup.findStaticSetter(ValueHolder.class, "s_s", short.class);
             MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
             h0.invoke(0.22f);
-            h0.invoke(new Float(1.11f));
-            Number floatNumber = new Float(0.88f);
+            h0.invoke(Float.valueOf(1.11f));
+            Number floatNumber = Float.valueOf(0.88f);
             h0.invoke(floatNumber);
             assertTrue(ValueHolder.s_f == floatNumber.floatValue());
 
             try {
-              h0.invoke((Float)null);
-              unreachable();
-            } catch (NullPointerException e) {}
+              h0.invoke((Float) null);
+              fail();
+            } catch (NullPointerException expected) {}
 
             // Test that type conversion checks work on small field types.
-            short temp = (short)s0.invoke(new Byte((byte)45));
+            short temp = (short) s0.invoke(new Byte((byte) 45));
             assertTrue(temp == 0);
             assertTrue(ValueHolder.s_s == 45);
 
-            h0.invoke((byte)1);
-            h0.invoke((short)2);
+            h0.invoke((byte) 1);
+            h0.invoke((short) 2);
             h0.invoke(3);
             h0.invoke(4l);
 
@@ -883,33 +898,33 @@
 
             try {
                 h0.invoke(0.33);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
                 Number doubleNumber = getDoubleAsNumber();
                 h0.invoke(doubleNumber);
-                unreachable();
-            } catch (ClassCastException e) {}
+                fail();
+            } catch (ClassCastException expected) {}
             try {
-                Number doubleNumber = new Double(1.01);
+                Number doubleNumber = Double.valueOf(1.01);
                 doubleNumber = (doubleNumber.doubleValue() != 0.1) ? null : doubleNumber;
                 h0.invoke(doubleNumber);
-                unreachable();
-            } catch (NullPointerException e) {}
+                fail();
+            } catch (NullPointerException expected) {}
             try {
                 // Mismatched return type - float != void
-                float tmp = (float)h0.invoke(0.45f);
+                float tmp = (float) h0.invoke(0.45f);
                 assertTrue(tmp == 0.0);
-            } catch (Exception e) { unreachable(); }
+            } catch (Exception e) { fail(); }
             try {
                 h0.invoke("bam");
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
             try {
                 String s = null;
                 h0.invoke(s);
-                unreachable();
-            } catch (WrongMethodTypeException e) {}
+                fail();
+            } catch (WrongMethodTypeException expected) {}
         }
 
         public static void main() throws Throwable{
@@ -921,11 +936,108 @@
         }
     }
 
+    public static class UnreflectTester extends Tester {
+        public static void main() throws Throwable {
+            ValueHolder v = new ValueHolder();
+            {
+                // public field test
+                Field f = ValueHolder.class.getDeclaredField("m_c");
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(v, 'z');
+                assertEquals('z', (char) MethodHandles.lookup().unreflectGetter(f).invokeExact(v));
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(v, 'A');
+                assertEquals('A', (char) MethodHandles.lookup().unreflectGetter(f).invokeExact(v));
+            }
+            {
+                // public static final field test
+                Field f = ValueHolder.class.getDeclaredField("s_fi");
+                try {
+                    MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                MethodHandles.lookup().unreflectGetter(f);
+                f.setAccessible(true);
+                int savedValue = (int) MethodHandles.lookup().unreflectGetter(f).invokeExact();
+                int newValue = savedValue + 1;
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(newValue);
+                assertEquals(newValue, (int) MethodHandles.lookup().unreflectGetter(f).invokeExact()
+                );
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(savedValue);
+                assertEquals(savedValue, (int) MethodHandles.lookup().unreflectGetter(f).invokeExact()
+                );
+                f.setAccessible(false);
+                try {
+                    MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                MethodHandles.lookup().unreflectGetter(f);
+            }
+            {
+                // private field test
+                Field f = ValueHolder.class.getDeclaredField("m_pz");
+                try {
+                    MethodHandle mh = MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                try {
+                    MethodHandle mh = MethodHandles.lookup().unreflectGetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                f.setAccessible(true);
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(v, true);
+                assertEquals(true, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact(v)
+                );
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(v, false);
+                assertEquals(false, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact(v)
+                );
+                f.setAccessible(false);
+                try {
+                    MethodHandle mh = MethodHandles.lookup().unreflectGetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                try {
+                    MethodHandle mh = MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+            }
+            {
+                // private static final field test
+                Field f = ValueHolder.class.getDeclaredField("s_fz");  // private static final field
+                try {
+                    MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                try {
+                    MethodHandles.lookup().unreflectGetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                f.setAccessible(true);
+                // Setter is okay despite being final because field isAccessible().
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(false);
+                assertEquals(false, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact()
+                );
+                MethodHandles.lookup().unreflectSetter(f).invokeExact(true);
+                assertEquals(true, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact()
+                );
+                f.setAccessible(false);
+                try {
+                    MethodHandles.lookup().unreflectSetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+                try {
+                    MethodHandles.lookup().unreflectGetter(f);
+                    fail();
+                } catch (IllegalAccessException expected) {}
+            }
+            System.out.println("Passed MethodHandles.unreflect(Field) tests.");
+        }
+    }
+
     public static void main(String[] args) throws Throwable {
         // FindAccessor test should be the first test class in this
         // file to ensure class initialization test is run.
         FindAccessorTester.main();
         InvokeExactTester.main();
         InvokeTester.main();
+        UnreflectTester.main();
     }
 }
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index 570ade3..ef67ace 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -29,6 +29,7 @@
 #include "base/macros.h"
 #include "bytecode_utils.h"
 #include "dex_file.h"
+#include "dex_file_loader.h"
 #include "dex_instruction.h"
 #include "jit/jit.h"
 #include "native_stack_dump.h"
@@ -66,14 +67,14 @@
     return;
   }
   std::string error;
-  std::unique_ptr<const DexFile> dex(DexFile::Open(class_data,
-                                                   class_data_len,
-                                                   "fake_location.dex",
-                                                   /*location_checksum*/ 0,
-                                                   /*oat_dex_file*/ nullptr,
-                                                   /*verify*/ true,
-                                                   /*verify_checksum*/ true,
-                                                   &error));
+  std::unique_ptr<const DexFile> dex(DexFileLoader::Open(class_data,
+                                                         class_data_len,
+                                                         "fake_location.dex",
+                                                         /*location_checksum*/ 0,
+                                                         /*oat_dex_file*/ nullptr,
+                                                         /*verify*/ true,
+                                                         /*verify_checksum*/ true,
+                                                         &error));
   if (dex.get() == nullptr) {
     std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
     return;
diff --git a/test/Android.bp b/test/Android.bp
index 31474d5..16b30f9 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -74,7 +74,7 @@
     ],
 
     target: {
-        linux_glibc: {
+        linux: {
             ldflags: [
                 // Allow jni_compiler_test to find Java_MyClassNatives_bar
                 // within itself using dlopen(NULL, ...).
@@ -83,9 +83,6 @@
                 "-Wl,-u,Java_MyClassNatives_bar",
                 "-Wl,-u,Java_MyClassNatives_sbar",
             ],
-            shared_libs: [
-                "libziparchive",
-            ],
             cflags: [
                 // gtest issue
                 "-Wno-used-but-marked-unused",
@@ -93,23 +90,15 @@
                 "-Wno-missing-noreturn",
             ],
         },
-        android: {
-            ldflags: [
-                // Allow jni_compiler_test to find Java_MyClassNatives_bar
-                // within itself using dlopen(NULL, ...).
-                "-Wl,--export-dynamic",
-                "-Wl,-u,Java_MyClassNatives_bar",
-                "-Wl,-u,Java_MyClassNatives_sbar",
+        host: {
+            shared_libs: [
+                "libziparchive",
             ],
+        },
+        android: {
             shared_libs: [
                 "liblog",
             ],
-            cflags: [
-                // gtest issue
-                "-Wno-used-but-marked-unused",
-                "-Wno-deprecated",
-                "-Wno-missing-noreturn",
-            ],
         },
     },
 }
@@ -135,15 +124,7 @@
         android64: {
             cflags: ["-DART_TARGET_NATIVETEST_DIR=/data/nativetest64/art"],
         },
-        android: {
-            cflags: [
-                // gtest issue
-                "-Wno-used-but-marked-unused",
-                "-Wno-deprecated",
-                "-Wno-missing-noreturn",
-            ],
-        },
-        linux_glibc: {
+        linux: {
             cflags: [
                 // gtest issue
                 "-Wno-used-but-marked-unused",
@@ -277,6 +258,7 @@
         "1930-monitor-info/monitor.cc",
         "1932-monitor-events-misc/monitor_misc.cc",
         "1934-jvmti-signal-thread/signal_threads.cc",
+        "1939-proxy-frames/local_instance.cc",
     ],
     shared_libs: [
         "libbase",
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index d37e6bc..2fda494 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -16,6 +16,8 @@
 COMPILE_FLAGS=""
 DALVIKVM="dalvikvm32"
 DEBUGGER="n"
+DEBUGGER_AGENT=""
+WRAP_DEBUGGER_AGENT="n"
 DEV_MODE="n"
 DEX2OAT=""
 EXPERIMENTAL=""
@@ -51,6 +53,7 @@
 fi
 USE_GDB="n"
 USE_JVM="n"
+USE_JVMTI="n"
 VERIFY="y" # y=yes,n=no,s=softfail
 ZYGOTE=""
 DEX_VERIFY=""
@@ -71,9 +74,9 @@
 PROFILE="n"
 RANDOM_PROFILE="n"
 # The normal dex2oat timeout.
-DEX2OAT_TIMEOUT="60"
+DEX2OAT_TIMEOUT="300" # 5 mins
 # The *hard* timeout where we really start trying to kill the dex2oat.
-DEX2OAT_RT_TIMEOUT="90"
+DEX2OAT_RT_TIMEOUT="360" # 6 mins
 
 # if "y", set -Xstacktracedir and inform the test of its location. When
 # this is set, stack trace dumps (from signal 3) will be written to a file
@@ -108,6 +111,7 @@
         DEX2OAT_TIMEOUT="$1"
         shift
     elif [ "x$1" = "x--jvmti" ]; then
+        USE_JVMTI="y"
         IS_JVMTI_TEST="y"
         shift
     elif [ "x$1" = "x-O" ]; then
@@ -180,19 +184,23 @@
         shift
     elif [ "x$1" = "x--jvmti-redefine-stress" ]; then
         # APP_IMAGE doesn't really work with jvmti redefine stress
+        USE_JVMTI="y"
         APP_IMAGE="n"
         JVMTI_STRESS="y"
         JVMTI_REDEFINE_STRESS="y"
         shift
     elif [ "x$1" = "x--jvmti-step-stress" ]; then
+        USE_JVMTI="y"
         JVMTI_STRESS="y"
         JVMTI_STEP_STRESS="y"
         shift
     elif [ "x$1" = "x--jvmti-field-stress" ]; then
+        USE_JVMTI="y"
         JVMTI_STRESS="y"
         JVMTI_FIELD_STRESS="y"
         shift
     elif [ "x$1" = "x--jvmti-trace-stress" ]; then
+        USE_JVMTI="y"
         JVMTI_STRESS="y"
         JVMTI_TRACE_STRESS="y"
         shift
@@ -220,6 +228,16 @@
         FLAGS="${FLAGS} -Xcompiler-option --dump-cfg-append"
         COMPILE_FLAGS="${COMPILE_FLAGS} --dump-cfg-append"
         shift
+    elif [ "x$1" = "x--debug-wrap-agent" ]; then
+        WRAP_DEBUGGER_AGENT="y"
+        shift
+    elif [ "x$1" = "x--debug-agent" ]; then
+        shift
+        DEBUGGER="agent"
+        USE_JVMTI="y"
+        DEBUGGER_AGENT="$1"
+        TIME_OUT="n"
+        shift
     elif [ "x$1" = "x--debug" ]; then
         DEBUGGER="y"
         TIME_OUT="n"
@@ -405,15 +423,43 @@
   fi
   msg "    jdb -attach localhost:$PORT"
   DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
+elif [ "$DEBUGGER" = "agent" ]; then
+  PORT=12345
+  # TODO Support ddms connection and support target.
+  if [ "$HOST" = "n" ]; then
+    echo "--debug-agent not supported yet for target!"
+    exit 1
+  fi
+  AGENTPATH=${DEBUGGER_AGENT}
+  if [ "$WRAP_DEBUGGER_AGENT" = "y" ]; then
+    WRAPPROPS="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}/libwrapagentpropertiesd.so"
+    if [ "$TEST_IS_NDEBUG" = "y" ]; then
+      WRAPPROPS="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}/libwrapagentproperties.so"
+    fi
+    AGENTPATH="${WRAPPROPS}=${ANDROID_BUILD_TOP}/art/tools/libjdwp-compat.props,${AGENTPATH}"
+  fi
+  msg "Connect to localhost:$PORT"
+  DEBUGGER_OPTS="-agentpath:${AGENTPATH}=transport=dt_socket,address=$PORT,server=y,suspend=y"
+fi
+
+if [ "$USE_JVMTI" = "y" ]; then
+  if [ "$USE_JVM" = "n" ]; then
+    plugin=libopenjdkjvmtid.so
+    if  [[ "$TEST_IS_NDEBUG" = "y" ]]; then
+      plugin=libopenjdkjvmti.so
+    fi
+    FLAGS="${FLAGS} -Xplugin:${plugin}"
+    FLAGS="${FLAGS} -Xcompiler-option --debuggable"
+    # Always make the compilation be debuggable.
+    COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable"
+  fi
 fi
 
 if [ "$IS_JVMTI_TEST" = "y" ]; then
-  plugin=libopenjdkjvmtid.so
   agent=libtiagentd.so
   lib=tiagentd
   if  [[ "$TEST_IS_NDEBUG" = "y" ]]; then
     agent=libtiagent.so
-    plugin=libopenjdkjvmti.so
     lib=tiagent
   fi
 
@@ -422,19 +468,13 @@
     FLAGS="${FLAGS} -agentpath:${ANDROID_HOST_OUT}/nativetest64/${agent}=${TEST_NAME},jvm"
   else
     FLAGS="${FLAGS} -agentpath:${agent}=${TEST_NAME},art"
-    FLAGS="${FLAGS} -Xplugin:${plugin}"
-    FLAGS="${FLAGS} -Xcompiler-option --debuggable"
-    # Always make the compilation be debuggable.
-    COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable"
   fi
 fi
 
 if [[ "$JVMTI_STRESS" = "y" ]]; then
-  plugin=libopenjdkjvmtid.so
   agent=libtistressd.so
   if  [[ "$TEST_IS_NDEBUG" = "y" ]]; then
     agent=libtistress.so
-    plugin=libopenjdkjvmti.so
   fi
 
   # Just give it a default start so we can always add ',' to it.
@@ -459,12 +499,6 @@
     FLAGS="${FLAGS} -agentpath:${ANDROID_HOST_OUT}/nativetest64/${agent}=${agent_args}"
   else
     FLAGS="${FLAGS} -agentpath:${agent}=${agent_args}"
-    if [ "$IS_JVMTI_TEST" = "n" ]; then
-      FLAGS="${FLAGS} -Xplugin:${plugin}"
-      FLAGS="${FLAGS} -Xcompiler-option --debuggable"
-      # Always make the compilation be debuggable.
-      COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable"
-    fi
   fi
 fi
 
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 68e9eb8..47b2f22 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1,5 +1,12 @@
 [
     {
+        "tests": [ "1939-proxy-frames", "1914-get-local-instance" ],
+        "description": ["Test 1939 & 1914 seems to consistently fail in gcstress on 64 bit with",
+                        "a proxy this object having no associated class!"],
+        "variant": "gcstress",
+        "bug": "http://b/67679263"
+    },
+    {
         "tests": "1934-jvmti-signal-thread",
         "description": ["Disables 1934-jvmti-signal-thread in tracing configurations"],
         "variant": "trace | stream",
diff --git a/test/run-test b/test/run-test
index d04cd05..09a70e5 100755
--- a/test/run-test
+++ b/test/run-test
@@ -288,6 +288,14 @@
     elif [ "x$1" = "x--debug" ]; then
         run_args="${run_args} --debug"
         shift
+    elif [ "x$1" = "x--debug-wrap-agent" ]; then
+        run_args="${run_args} --debug-wrap-agent"
+        shift
+    elif [ "x$1" = "x--debug-agent" ]; then
+        shift
+        option="$1"
+        run_args="${run_args} --debug-agent $1"
+        shift
     elif [ "x$1" = "x--gdb" ]; then
         run_args="${run_args} --gdb"
         dev_mode="yes"
@@ -647,7 +655,12 @@
         echo "    -Xcompiler-option     Pass an option to the compiler."
         echo "    --build-option        Pass an option to the build script."
         echo "    --runtime-option      Pass an option to the runtime."
-        echo "    --debug               Wait for a debugger to attach."
+        echo "    --debug               Wait for the default debugger to attach."
+        echo "    --debug-agent <agent-path>"
+        echo "                          Wait for the given debugger agent to attach. Currently"
+        echo "                          only supported on host."
+        echo "    --debug-wrap-agent    use libwrapagentproperties and tools/libjdwp-compat.props"
+        echo "                          to load the debugger agent specified by --debug-agent."
         echo "    --debuggable          Whether to compile Java code for a debugger."
         echo "    --gdb                 Run under gdb; incompatible with some tests."
         echo "    --gdb-arg             Pass an option to gdb."
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index b5929cb..ca29d0a 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -481,7 +481,7 @@
       if test_passed:
         print_test_info(test_name, 'PASS')
       else:
-        failed_tests.append((test_name, script_output))
+        failed_tests.append((test_name, str(command) + "\n" + script_output))
         if not env.ART_TEST_KEEP_GOING:
           stop_testrunner = True
         print_test_info(test_name, 'FAIL', ('%s\n%s') % (
@@ -536,10 +536,17 @@
       total_test_count)
 
     if result == 'FAIL' or result == 'TIMEOUT':
-      info += ('%s %s %s\n') % (
-        progress_info,
-        test_name,
-        COLOR_ERROR + result + COLOR_NORMAL)
+      if not verbose:
+        info += ('%s %s %s\n') % (
+          progress_info,
+          test_name,
+          COLOR_ERROR + result + COLOR_NORMAL)
+      else:
+        info += ('%s %s %s\n%s\n') % (
+          progress_info,
+          test_name,
+          COLOR_ERROR + result + COLOR_NORMAL,
+          failed_test_info)
     else:
       result_text = ''
       if result == 'PASS':
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index cf31e2e..5eccba1 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -20,9 +20,9 @@
 
 # --- ahat.jar ----------------
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAR_MANIFEST := src/manifest.txt
-LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/src/style.css
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
+LOCAL_JAR_MANIFEST := etc/ahat.mf
+LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/etc/style.css
 LOCAL_IS_HOST_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ahat
@@ -49,9 +49,9 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := ahat-test-dump
 LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, test-dump)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/test-dump)
 LOCAL_PROGUARD_ENABLED := obfuscation
-LOCAL_PROGUARD_FLAG_FILES := test-dump/config.pro
+LOCAL_PROGUARD_FLAG_FILES := etc/test-dump.pro
 include $(BUILD_JAVA_LIBRARY)
 
 # Determine the location of the test-dump.jar, test-dump.hprof, and proguard
@@ -87,15 +87,15 @@
 
 # --- ahat-tests.jar --------------
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, test)
-LOCAL_JAR_MANIFEST := test/manifest.txt
+LOCAL_SRC_FILES := $(call all-java-files-under, src/test)
+LOCAL_JAR_MANIFEST := etc/ahat-tests.mf
 LOCAL_JAVA_RESOURCE_FILES := \
   $(AHAT_TEST_DUMP_HPROF) \
   $(AHAT_TEST_DUMP_BASE_HPROF) \
   $(AHAT_TEST_DUMP_PROGUARD_MAP) \
-  $(LOCAL_PATH)/test-dump/L.hprof \
-  $(LOCAL_PATH)/test-dump/O.hprof \
-  $(LOCAL_PATH)/test-dump/RI.hprof
+  $(LOCAL_PATH)/etc/L.hprof \
+  $(LOCAL_PATH)/etc/O.hprof \
+  $(LOCAL_PATH)/etc/RI.hprof
 LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
 LOCAL_IS_HOST_MODULE := true
 LOCAL_MODULE_TAGS := tests
diff --git a/tools/ahat/test-dump/L.hprof b/tools/ahat/etc/L.hprof
similarity index 100%
rename from tools/ahat/test-dump/L.hprof
rename to tools/ahat/etc/L.hprof
Binary files differ
diff --git a/tools/ahat/test-dump/O.hprof b/tools/ahat/etc/O.hprof
similarity index 100%
rename from tools/ahat/test-dump/O.hprof
rename to tools/ahat/etc/O.hprof
Binary files differ
diff --git a/tools/ahat/etc/README.txt b/tools/ahat/etc/README.txt
new file mode 100644
index 0000000..e9b5b22
--- /dev/null
+++ b/tools/ahat/etc/README.txt
@@ -0,0 +1,9 @@
+L.hprof
+  A version of the test-dump hprof generated on Android L, with one of the
+  ROOT_DEBUGGER records manually changed to a ROOT_FINALIZING record.
+
+O.hprof
+  A version of the test-dump hprof generated on Android O.
+
+RI.hprof
+  A version of the test-dump hprof generated on the reference implementation.
diff --git a/tools/ahat/test-dump/RI.hprof b/tools/ahat/etc/RI.hprof
similarity index 100%
rename from tools/ahat/test-dump/RI.hprof
rename to tools/ahat/etc/RI.hprof
Binary files differ
diff --git a/tools/ahat/test/manifest.txt b/tools/ahat/etc/ahat-tests.mf
similarity index 100%
rename from tools/ahat/test/manifest.txt
rename to tools/ahat/etc/ahat-tests.mf
diff --git a/tools/ahat/src/manifest.txt b/tools/ahat/etc/ahat.mf
similarity index 100%
rename from tools/ahat/src/manifest.txt
rename to tools/ahat/etc/ahat.mf
diff --git a/tools/ahat/src/style.css b/tools/ahat/etc/style.css
similarity index 100%
rename from tools/ahat/src/style.css
rename to tools/ahat/etc/style.css
diff --git a/tools/ahat/test-dump/config.pro b/tools/ahat/etc/test-dump.pro
similarity index 100%
rename from tools/ahat/test-dump/config.pro
rename to tools/ahat/etc/test-dump.pro
diff --git a/tools/ahat/src/AhatHandler.java b/tools/ahat/src/main/com/android/ahat/AhatHandler.java
similarity index 100%
rename from tools/ahat/src/AhatHandler.java
rename to tools/ahat/src/main/com/android/ahat/AhatHandler.java
diff --git a/tools/ahat/src/AhatHttpHandler.java b/tools/ahat/src/main/com/android/ahat/AhatHttpHandler.java
similarity index 100%
rename from tools/ahat/src/AhatHttpHandler.java
rename to tools/ahat/src/main/com/android/ahat/AhatHttpHandler.java
diff --git a/tools/ahat/src/BitmapHandler.java b/tools/ahat/src/main/com/android/ahat/BitmapHandler.java
similarity index 100%
rename from tools/ahat/src/BitmapHandler.java
rename to tools/ahat/src/main/com/android/ahat/BitmapHandler.java
diff --git a/tools/ahat/src/Column.java b/tools/ahat/src/main/com/android/ahat/Column.java
similarity index 100%
rename from tools/ahat/src/Column.java
rename to tools/ahat/src/main/com/android/ahat/Column.java
diff --git a/tools/ahat/src/Doc.java b/tools/ahat/src/main/com/android/ahat/Doc.java
similarity index 100%
rename from tools/ahat/src/Doc.java
rename to tools/ahat/src/main/com/android/ahat/Doc.java
diff --git a/tools/ahat/src/DocString.java b/tools/ahat/src/main/com/android/ahat/DocString.java
similarity index 100%
rename from tools/ahat/src/DocString.java
rename to tools/ahat/src/main/com/android/ahat/DocString.java
diff --git a/tools/ahat/src/DominatedList.java b/tools/ahat/src/main/com/android/ahat/DominatedList.java
similarity index 100%
rename from tools/ahat/src/DominatedList.java
rename to tools/ahat/src/main/com/android/ahat/DominatedList.java
diff --git a/tools/ahat/src/HeapTable.java b/tools/ahat/src/main/com/android/ahat/HeapTable.java
similarity index 100%
rename from tools/ahat/src/HeapTable.java
rename to tools/ahat/src/main/com/android/ahat/HeapTable.java
diff --git a/tools/ahat/src/HtmlDoc.java b/tools/ahat/src/main/com/android/ahat/HtmlDoc.java
similarity index 100%
rename from tools/ahat/src/HtmlDoc.java
rename to tools/ahat/src/main/com/android/ahat/HtmlDoc.java
diff --git a/tools/ahat/src/HtmlEscaper.java b/tools/ahat/src/main/com/android/ahat/HtmlEscaper.java
similarity index 100%
rename from tools/ahat/src/HtmlEscaper.java
rename to tools/ahat/src/main/com/android/ahat/HtmlEscaper.java
diff --git a/tools/ahat/src/Main.java b/tools/ahat/src/main/com/android/ahat/Main.java
similarity index 64%
rename from tools/ahat/src/Main.java
rename to tools/ahat/src/main/com/android/ahat/Main.java
index 31c485d..a0fbf77 100644
--- a/tools/ahat/src/Main.java
+++ b/tools/ahat/src/main/com/android/ahat/Main.java
@@ -48,6 +48,26 @@
     out.println("");
   }
 
+  /**
+   * Load the given heap dump file.
+   * Prints an error message and exits the application on failure to load the
+   * heap dump.
+   */
+  private static AhatSnapshot loadHeapDump(File hprof, ProguardMap map) {
+    System.out.println("Processing '" + hprof + "' ...");
+    try {
+      return Parser.parseHeapDump(hprof, map);
+    } catch (IOException e) {
+      System.err.println("Unable to load '" + hprof + "':");
+      e.printStackTrace();
+    } catch (HprofFormatException e) {
+      System.err.println("'" + hprof + "' does not appear to be a valid Java heap dump:");
+      e.printStackTrace();
+    }
+    System.exit(1);
+    throw new AssertionError("Unreachable");
+  }
+
   public static void main(String[] args) {
     int port = 7100;
     for (String arg : args) {
@@ -105,40 +125,39 @@
       return;
     }
 
+    // Launch the server before parsing the hprof file so we get
+    // BindExceptions quickly.
+    InetAddress loopback = InetAddress.getLoopbackAddress();
+    InetSocketAddress addr = new InetSocketAddress(loopback, port);
+    System.out.println("Preparing " + addr + " ...");
+    HttpServer server = null;
     try {
-      // Launch the server before parsing the hprof file so we get
-      // BindExceptions quickly.
-      InetAddress loopback = InetAddress.getLoopbackAddress();
-      InetSocketAddress addr = new InetSocketAddress(loopback, port);
-      System.out.println("Preparing " + addr + " ...");
-      HttpServer server = HttpServer.create(addr, 0);
-
-      System.out.println("Processing '" + hprof + "' ...");
-      AhatSnapshot ahat = Parser.parseHeapDump(hprof, map);
-
-      if (hprofbase != null) {
-        System.out.println("Processing '" + hprofbase + "' ...");
-        AhatSnapshot base = Parser.parseHeapDump(hprofbase, mapbase);
-
-        System.out.println("Diffing heap dumps ...");
-        Diff.snapshots(ahat, base);
-      }
-
-      server.createContext("/", new AhatHttpHandler(new OverviewHandler(ahat, hprof, hprofbase)));
-      server.createContext("/rooted", new AhatHttpHandler(new RootedHandler(ahat)));
-      server.createContext("/object", new AhatHttpHandler(new ObjectHandler(ahat)));
-      server.createContext("/objects", new AhatHttpHandler(new ObjectsHandler(ahat)));
-      server.createContext("/site", new AhatHttpHandler(new SiteHandler(ahat)));
-      server.createContext("/bitmap", new BitmapHandler(ahat));
-      server.createContext("/style.css", new StaticHandler("style.css", "text/css"));
-      server.setExecutor(Executors.newFixedThreadPool(1));
-      System.out.println("Server started on localhost:" + port);
-
-      server.start();
-    } catch (HprofFormatException|IOException e) {
-      System.err.println("Unable to launch ahat:");
+      server = HttpServer.create(addr, 0);
+    } catch (IOException e) {
+      System.err.println("Unable to setup ahat server:");
       e.printStackTrace();
+      System.exit(1);
     }
+
+    AhatSnapshot ahat = loadHeapDump(hprof, map);
+    if (hprofbase != null) {
+      AhatSnapshot base = loadHeapDump(hprofbase, mapbase);
+
+      System.out.println("Diffing heap dumps ...");
+      Diff.snapshots(ahat, base);
+    }
+
+    server.createContext("/", new AhatHttpHandler(new OverviewHandler(ahat, hprof, hprofbase)));
+    server.createContext("/rooted", new AhatHttpHandler(new RootedHandler(ahat)));
+    server.createContext("/object", new AhatHttpHandler(new ObjectHandler(ahat)));
+    server.createContext("/objects", new AhatHttpHandler(new ObjectsHandler(ahat)));
+    server.createContext("/site", new AhatHttpHandler(new SiteHandler(ahat)));
+    server.createContext("/bitmap", new BitmapHandler(ahat));
+    server.createContext("/style.css", new StaticHandler("style.css", "text/css"));
+    server.setExecutor(Executors.newFixedThreadPool(1));
+    System.out.println("Server started on localhost:" + port);
+
+    server.start();
   }
 }
 
diff --git a/tools/ahat/src/Menu.java b/tools/ahat/src/main/com/android/ahat/Menu.java
similarity index 100%
rename from tools/ahat/src/Menu.java
rename to tools/ahat/src/main/com/android/ahat/Menu.java
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/main/com/android/ahat/ObjectHandler.java
similarity index 100%
rename from tools/ahat/src/ObjectHandler.java
rename to tools/ahat/src/main/com/android/ahat/ObjectHandler.java
diff --git a/tools/ahat/src/ObjectsHandler.java b/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
similarity index 100%
rename from tools/ahat/src/ObjectsHandler.java
rename to tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
diff --git a/tools/ahat/src/OverviewHandler.java b/tools/ahat/src/main/com/android/ahat/OverviewHandler.java
similarity index 100%
rename from tools/ahat/src/OverviewHandler.java
rename to tools/ahat/src/main/com/android/ahat/OverviewHandler.java
diff --git a/tools/ahat/src/Query.java b/tools/ahat/src/main/com/android/ahat/Query.java
similarity index 100%
rename from tools/ahat/src/Query.java
rename to tools/ahat/src/main/com/android/ahat/Query.java
diff --git a/tools/ahat/src/RootedHandler.java b/tools/ahat/src/main/com/android/ahat/RootedHandler.java
similarity index 100%
rename from tools/ahat/src/RootedHandler.java
rename to tools/ahat/src/main/com/android/ahat/RootedHandler.java
diff --git a/tools/ahat/src/SiteHandler.java b/tools/ahat/src/main/com/android/ahat/SiteHandler.java
similarity index 100%
rename from tools/ahat/src/SiteHandler.java
rename to tools/ahat/src/main/com/android/ahat/SiteHandler.java
diff --git a/tools/ahat/src/SitePrinter.java b/tools/ahat/src/main/com/android/ahat/SitePrinter.java
similarity index 100%
rename from tools/ahat/src/SitePrinter.java
rename to tools/ahat/src/main/com/android/ahat/SitePrinter.java
diff --git a/tools/ahat/src/SizeTable.java b/tools/ahat/src/main/com/android/ahat/SizeTable.java
similarity index 100%
rename from tools/ahat/src/SizeTable.java
rename to tools/ahat/src/main/com/android/ahat/SizeTable.java
diff --git a/tools/ahat/src/StaticHandler.java b/tools/ahat/src/main/com/android/ahat/StaticHandler.java
similarity index 100%
rename from tools/ahat/src/StaticHandler.java
rename to tools/ahat/src/main/com/android/ahat/StaticHandler.java
diff --git a/tools/ahat/src/SubsetSelector.java b/tools/ahat/src/main/com/android/ahat/SubsetSelector.java
similarity index 100%
rename from tools/ahat/src/SubsetSelector.java
rename to tools/ahat/src/main/com/android/ahat/SubsetSelector.java
diff --git a/tools/ahat/src/Summarizer.java b/tools/ahat/src/main/com/android/ahat/Summarizer.java
similarity index 100%
rename from tools/ahat/src/Summarizer.java
rename to tools/ahat/src/main/com/android/ahat/Summarizer.java
diff --git a/tools/ahat/src/dominators/DominatorsComputation.java b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
similarity index 100%
rename from tools/ahat/src/dominators/DominatorsComputation.java
rename to tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
diff --git a/tools/ahat/src/heapdump/AhatArrayInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatArrayInstance.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java
diff --git a/tools/ahat/src/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatClassInstance.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
diff --git a/tools/ahat/src/heapdump/AhatClassObj.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatClassObj.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java
diff --git a/tools/ahat/src/heapdump/AhatField.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatField.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatField.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatField.java
diff --git a/tools/ahat/src/heapdump/AhatHeap.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatHeap.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatInstance.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatPlaceHolderClassObj.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatPlaceHolderClassObj.java
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatPlaceHolderInstance.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatPlaceHolderInstance.java
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
similarity index 100%
rename from tools/ahat/src/heapdump/AhatSnapshot.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
diff --git a/tools/ahat/src/heapdump/Diff.java b/tools/ahat/src/main/com/android/ahat/heapdump/Diff.java
similarity index 100%
rename from tools/ahat/src/heapdump/Diff.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Diff.java
diff --git a/tools/ahat/src/heapdump/DiffFields.java b/tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java
similarity index 100%
rename from tools/ahat/src/heapdump/DiffFields.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java
diff --git a/tools/ahat/src/heapdump/Diffable.java b/tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java
similarity index 100%
rename from tools/ahat/src/heapdump/Diffable.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java
diff --git a/tools/ahat/src/heapdump/DiffedFieldValue.java b/tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java
similarity index 100%
rename from tools/ahat/src/heapdump/DiffedFieldValue.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java
diff --git a/tools/ahat/src/heapdump/DominatorReferenceIterator.java b/tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java
similarity index 100%
rename from tools/ahat/src/heapdump/DominatorReferenceIterator.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java
diff --git a/tools/ahat/src/heapdump/Field.java b/tools/ahat/src/main/com/android/ahat/heapdump/Field.java
similarity index 100%
rename from tools/ahat/src/heapdump/Field.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Field.java
diff --git a/tools/ahat/src/heapdump/FieldValue.java b/tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java
similarity index 100%
rename from tools/ahat/src/heapdump/FieldValue.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java
diff --git a/tools/ahat/src/heapdump/HprofFormatException.java b/tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java
similarity index 100%
rename from tools/ahat/src/heapdump/HprofFormatException.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java
diff --git a/tools/ahat/src/heapdump/Instances.java b/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
similarity index 100%
rename from tools/ahat/src/heapdump/Instances.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
diff --git a/tools/ahat/src/heapdump/Parser.java b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
similarity index 100%
rename from tools/ahat/src/heapdump/Parser.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
diff --git a/tools/ahat/src/heapdump/PathElement.java b/tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java
similarity index 100%
rename from tools/ahat/src/heapdump/PathElement.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java
diff --git a/tools/ahat/src/heapdump/Reference.java b/tools/ahat/src/main/com/android/ahat/heapdump/Reference.java
similarity index 100%
rename from tools/ahat/src/heapdump/Reference.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Reference.java
diff --git a/tools/ahat/src/heapdump/RootType.java b/tools/ahat/src/main/com/android/ahat/heapdump/RootType.java
similarity index 100%
rename from tools/ahat/src/heapdump/RootType.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/RootType.java
diff --git a/tools/ahat/src/heapdump/Site.java b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
similarity index 100%
rename from tools/ahat/src/heapdump/Site.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Site.java
diff --git a/tools/ahat/src/heapdump/Size.java b/tools/ahat/src/main/com/android/ahat/heapdump/Size.java
similarity index 100%
rename from tools/ahat/src/heapdump/Size.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Size.java
diff --git a/tools/ahat/src/heapdump/SkipNullsIterator.java b/tools/ahat/src/main/com/android/ahat/heapdump/SkipNullsIterator.java
similarity index 100%
rename from tools/ahat/src/heapdump/SkipNullsIterator.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/SkipNullsIterator.java
diff --git a/tools/ahat/src/heapdump/Sort.java b/tools/ahat/src/main/com/android/ahat/heapdump/Sort.java
similarity index 100%
rename from tools/ahat/src/heapdump/Sort.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Sort.java
diff --git a/tools/ahat/src/heapdump/SuperRoot.java b/tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java
similarity index 100%
rename from tools/ahat/src/heapdump/SuperRoot.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java
diff --git a/tools/ahat/src/heapdump/Type.java b/tools/ahat/src/main/com/android/ahat/heapdump/Type.java
similarity index 100%
rename from tools/ahat/src/heapdump/Type.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Type.java
diff --git a/tools/ahat/src/heapdump/Value.java b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
similarity index 100%
rename from tools/ahat/src/heapdump/Value.java
rename to tools/ahat/src/main/com/android/ahat/heapdump/Value.java
diff --git a/tools/ahat/src/proguard/ProguardMap.java b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
similarity index 100%
rename from tools/ahat/src/proguard/ProguardMap.java
rename to tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/src/test-dump/Main.java
similarity index 100%
rename from tools/ahat/test-dump/Main.java
rename to tools/ahat/src/test-dump/Main.java
diff --git a/tools/ahat/test/DiffFieldsTest.java b/tools/ahat/src/test/com/android/ahat/DiffFieldsTest.java
similarity index 100%
rename from tools/ahat/test/DiffFieldsTest.java
rename to tools/ahat/src/test/com/android/ahat/DiffFieldsTest.java
diff --git a/tools/ahat/test/DiffTest.java b/tools/ahat/src/test/com/android/ahat/DiffTest.java
similarity index 100%
rename from tools/ahat/test/DiffTest.java
rename to tools/ahat/src/test/com/android/ahat/DiffTest.java
diff --git a/tools/ahat/test/DominatorsTest.java b/tools/ahat/src/test/com/android/ahat/DominatorsTest.java
similarity index 100%
rename from tools/ahat/test/DominatorsTest.java
rename to tools/ahat/src/test/com/android/ahat/DominatorsTest.java
diff --git a/tools/ahat/test/HtmlEscaperTest.java b/tools/ahat/src/test/com/android/ahat/HtmlEscaperTest.java
similarity index 100%
rename from tools/ahat/test/HtmlEscaperTest.java
rename to tools/ahat/src/test/com/android/ahat/HtmlEscaperTest.java
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/src/test/com/android/ahat/InstanceTest.java
similarity index 100%
rename from tools/ahat/test/InstanceTest.java
rename to tools/ahat/src/test/com/android/ahat/InstanceTest.java
diff --git a/tools/ahat/test/NativeAllocationTest.java b/tools/ahat/src/test/com/android/ahat/NativeAllocationTest.java
similarity index 100%
rename from tools/ahat/test/NativeAllocationTest.java
rename to tools/ahat/src/test/com/android/ahat/NativeAllocationTest.java
diff --git a/tools/ahat/test/ObjectHandlerTest.java b/tools/ahat/src/test/com/android/ahat/ObjectHandlerTest.java
similarity index 100%
rename from tools/ahat/test/ObjectHandlerTest.java
rename to tools/ahat/src/test/com/android/ahat/ObjectHandlerTest.java
diff --git a/tools/ahat/test/OverviewHandlerTest.java b/tools/ahat/src/test/com/android/ahat/OverviewHandlerTest.java
similarity index 100%
rename from tools/ahat/test/OverviewHandlerTest.java
rename to tools/ahat/src/test/com/android/ahat/OverviewHandlerTest.java
diff --git a/tools/ahat/test/PerformanceTest.java b/tools/ahat/src/test/com/android/ahat/PerformanceTest.java
similarity index 100%
rename from tools/ahat/test/PerformanceTest.java
rename to tools/ahat/src/test/com/android/ahat/PerformanceTest.java
diff --git a/tools/ahat/test/ProguardMapTest.java b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
similarity index 100%
rename from tools/ahat/test/ProguardMapTest.java
rename to tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
diff --git a/tools/ahat/test/QueryTest.java b/tools/ahat/src/test/com/android/ahat/QueryTest.java
similarity index 100%
rename from tools/ahat/test/QueryTest.java
rename to tools/ahat/src/test/com/android/ahat/QueryTest.java
diff --git a/tools/ahat/test/RootedHandlerTest.java b/tools/ahat/src/test/com/android/ahat/RootedHandlerTest.java
similarity index 100%
rename from tools/ahat/test/RootedHandlerTest.java
rename to tools/ahat/src/test/com/android/ahat/RootedHandlerTest.java
diff --git a/tools/ahat/test/SiteHandlerTest.java b/tools/ahat/src/test/com/android/ahat/SiteHandlerTest.java
similarity index 100%
rename from tools/ahat/test/SiteHandlerTest.java
rename to tools/ahat/src/test/com/android/ahat/SiteHandlerTest.java
diff --git a/tools/ahat/test/SiteTest.java b/tools/ahat/src/test/com/android/ahat/SiteTest.java
similarity index 100%
rename from tools/ahat/test/SiteTest.java
rename to tools/ahat/src/test/com/android/ahat/SiteTest.java
diff --git a/tools/ahat/test/TestDump.java b/tools/ahat/src/test/com/android/ahat/TestDump.java
similarity index 100%
rename from tools/ahat/test/TestDump.java
rename to tools/ahat/src/test/com/android/ahat/TestDump.java
diff --git a/tools/ahat/test/TestHandler.java b/tools/ahat/src/test/com/android/ahat/TestHandler.java
similarity index 100%
rename from tools/ahat/test/TestHandler.java
rename to tools/ahat/src/test/com/android/ahat/TestHandler.java
diff --git a/tools/ahat/test/Tests.java b/tools/ahat/src/test/com/android/ahat/Tests.java
similarity index 100%
rename from tools/ahat/test/Tests.java
rename to tools/ahat/src/test/com/android/ahat/Tests.java
diff --git a/tools/ahat/test-dump/README.txt b/tools/ahat/test-dump/README.txt
deleted file mode 100644
index e7ea584..0000000
--- a/tools/ahat/test-dump/README.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-Main.java - A program used to generate a heap dump used for tests.
-L.hprof - A version of the test dump generated on Android L,
-          with one of the ROOT_DEBUGGER records manually changed to a
-          ROOT_FINALIZING record.
-O.hprof - A version of the test dump generated on Android O.
-RI.hprof - A version of the test dump generated on the reference implementation.
diff --git a/tools/art b/tools/art
index 15993dd..1c603d4 100644
--- a/tools/art
+++ b/tools/art
@@ -81,6 +81,8 @@
   -d                       Use the debug ART library (libartd.so).
   --debug                  Equivalent to -d.
   --gdb                    Launch the Android Runtime in gdb.
+  --gdbserver <comms>      Launch the Android Runtime in gdbserver using the
+                           supplied communication channel.
   --help                   Display usage message.
   --invoke-with <program>  Launch the Android Runtime in <program>.
   --perf                   Launch the Android Runtime with perf recording.
@@ -220,6 +222,11 @@
   echo "$image_location"
 }
 
+# If android logging is not explicitly set, only print warnings and errors.
+if [ -z "$ANDROID_LOG_TAGS" ]; then
+  ANDROID_LOG_TAGS='*:w'
+fi
+
 # Runs dalvikvm, returns its exit code.
 # (Oat directories are cleaned up in between runs)
 function run_art() {
@@ -229,15 +236,16 @@
   # First cleanup any left-over 'oat' files from the last time dalvikvm was run.
   cleanup_oat_directory_for_classpath "$@"
   # Run dalvikvm.
-  verbose_run ANDROID_DATA=$ANDROID_DATA               \
-              ANDROID_ROOT=$ANDROID_ROOT               \
-              LD_LIBRARY_PATH=$LD_LIBRARY_PATH         \
-              PATH=$ANDROID_ROOT/bin:$PATH             \
-              LD_USE_LOAD_BIAS=1                       \
-              $LAUNCH_WRAPPER $ART_BINARY_PATH $lib    \
-              -XXlib:$LIBART                           \
-              -Xnorelocate                             \
-              -Ximage:"$image_location"                \
+  verbose_run ANDROID_DATA="$ANDROID_DATA"                  \
+              ANDROID_ROOT="$ANDROID_ROOT"                  \
+              LD_LIBRARY_PATH="$LD_LIBRARY_PATH"            \
+              PATH="$ANDROID_ROOT/bin:$PATH"                \
+              LD_USE_LOAD_BIAS=1                            \
+              ANDROID_LOG_TAGS="$ANDROID_LOG_TAGS"          \
+              $LAUNCH_WRAPPER $ART_BINARY_PATH $lib         \
+              -XXlib:"$LIBART"                              \
+              -Xnorelocate                                  \
+              -Ximage:"$image_location"                     \
               "$@"
   ret=$?
 
@@ -271,6 +279,10 @@
     # Expect that debug mode wants all checks.
     EXTRA_OPTIONS+=(-XX:SlowDebug=true)
     ;;
+  --gdbserver)
+    LAUNCH_WRAPPER="gdbserver $2"
+    shift
+    ;;
   --gdb)
     LIBART="libartd.so"
     LAUNCH_WRAPPER="gdb --args"
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index ab604b2..d1ea15e 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -66,13 +66,16 @@
   common_targets="$common_targets ${out_dir}/host/linux-x86/bin/jack"
 fi
 
+# Allow to build successfully in master-art.
+extra_args=SOONG_ALLOW_MISSING_DEPENDENCIES=true
+
 if [[ $mode == "host" ]]; then
-  make_command="make $j_arg $showcommands build-art-host-tests $common_targets dx-tests"
+  make_command="make $j_arg $extra_args $showcommands build-art-host-tests $common_targets dx-tests"
   make_command+=" ${out_dir}/host/linux-x86/lib/libjavacoretests.so "
   make_command+=" ${out_dir}/host/linux-x86/lib64/libjavacoretests.so"
   make_command+=" libwrapagentpropertiesd libwrapagentproperties"
 elif [[ $mode == "target" ]]; then
-  make_command="make $j_arg $showcommands build-art-target-tests $common_targets"
+  make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
   make_command+=" libjavacrypto libjavacoretests libnetd_client linker toybox toolbox sh"
   make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
   make_command+=" ${out_dir}/target/product/${TARGET_PRODUCT}/system/etc/public.libraries.txt"
diff --git a/tools/libjdwp_art_failures.txt b/tools/libjdwp_art_failures.txt
index 57d3ce7..1812177 100644
--- a/tools/libjdwp_art_failures.txt
+++ b/tools/libjdwp_art_failures.txt
@@ -48,7 +48,7 @@
   name: "org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test#testVMDeathRequest"
 },
 {
-  description: "Test fails with INTERNAL error due to proxy frame!",
+  description: "Test fails with OPAQUE_FRAME error due to attempting a GetLocalReference on a proxy frame instead of GetLocalInstance!",
   result: EXEC_FAILED,
   bug: 66903662,
   name: "org.apache.harmony.jpda.tests.jdwp.StackFrame.ProxyThisObjectTest#testThisObject"
@@ -71,33 +71,6 @@
            "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExit",
            "org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExitWithReturnValue" ]
 },
-/* TODO Investigate these failures more closely */
-{
-  description: "Tests that fail when run on the chromium buildbots against the prebuilt libjdwp.so in certain configurations",
-  result: EXEC_FAILED,
-  bug: 67497270,
-  names: [
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEvents003Test#testCombinedEvents003_01",
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEventsTest#testCombinedEvents_01",
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEventsTest#testCombinedEvents_02",
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEventsTest#testCombinedEvents_03",
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEventsTest#testCombinedEvents_04",
-    "org.apache.harmony.jpda.tests.jdwp.Events.CombinedEventsTest#testCombinedEvents_06",
-    "org.apache.harmony.jpda.tests.jdwp.Events.VMDeathTest#testVMDeathEvent",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.ClassPrepareTest#testClassPrepare001",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.ExceptionTest#testException001",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.FieldAccessTest#testFieldAccess001",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.FieldModificationTest#testFieldModification001",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.SingleStepTest#testSingleStep001",
-    "org.apache.harmony.jpda.tests.jdwp.MultiSession.VMDeathTest#testVMDeathRequest",
-    "org.apache.harmony.jpda.tests.jdwp.ReferenceType.SignatureWithGenericTest#testSignatureWithGeneric001",
-    "org.apache.harmony.jpda.tests.jdwp.StackFrame.GetValues002Test#testGetValues005_Int2",
-    "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.SetDefaultStratumTest#testSetDefaultStratum001",
-    "org.apache.harmony.jpda.tests.jdwp.ThreadReference.StatusTest#testStatus001",
-    "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.AllClassesTest#testAllClasses002",
-    "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.AllClassesWithGenericTest#testAllClassesWithGeneric001"
-  ]
-},
 /* TODO Categorize these failures more. */
 {
   description: "Tests that fail on both ART and RI. These tests are likely incorrect",
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index d0e35ac..cee75df 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -43,12 +43,14 @@
 image_compiler_option=""
 plugin=""
 debug="no"
+explicit_debug="no"
 verbose="no"
 image="-Ximage:/data/art-test/core.art"
 with_jdwp_path=""
 agent_wrapper=""
 vm_args=""
 # By default, we run the whole JDWP test suite.
+has_specific_test="no"
 test="org.apache.harmony.jpda.tests.share.AllTests"
 mode="target"
 # Use JIT compiling by default.
@@ -61,6 +63,9 @@
 # continuous testing. This value can be adjusted to fit the configuration of the host machine(s).
 jdwp_test_timeout=10000
 
+gdb_target=
+has_gdb="no"
+
 while true; do
   if [[ "$1" == "--mode=host" ]]; then
     mode="host"
@@ -107,7 +112,14 @@
     # Remove the --no-jit from the arguments.
     args=${args/$1}
     shift
+  elif [[ $1 == "--no-debug" ]]; then
+    explicit_debug="yes"
+    debug="no"
+    # Remove the --no-debug from the arguments.
+    args=${args/$1}
+    shift
   elif [[ $1 == "--debug" ]]; then
+    explicit_debug="yes"
     debug="yes"
     # Remove the --debug from the arguments.
     args=${args/$1}
@@ -117,10 +129,20 @@
     # Remove the --verbose from the arguments.
     args=${args/$1}
     shift
+  elif [[ $1 == "--gdbserver" ]]; then
+    # Remove the --gdbserver from the arguments.
+    args=${args/$1}
+    has_gdb="yes"
+    shift
+    gdb_target=$1
+    # Remove the target from the arguments.
+    args=${args/$1}
+    shift
   elif [[ $1 == "--test" ]]; then
     # Remove the --test from the arguments.
     args=${args/$1}
     shift
+    has_specific_test="yes"
     test=$1
     # Remove the test from the arguments.
     args=${args/$1}
@@ -147,6 +169,12 @@
   fi
 done
 
+if [[ $has_gdb = "yes" ]]; then
+  if [[ $explicit_debug = "no" ]]; then
+    debug="yes"
+  fi
+fi
+
 if [[ $mode == "ri" ]]; then
   using_jack="false"
   if [[ "x$with_jdwp_path" != "x" ]]; then
@@ -156,11 +184,25 @@
   if [[ "x$image" != "x" ]]; then
     echo "Cannot use -Ximage: with --mode=jvm"
     exit 1
+  elif [[ $has_gdb = "yes" ]]; then
+    echo "Cannot use --gdbserver with --mode=jvm"
+    exit 1
   elif [[ $debug == "yes" ]]; then
     echo "Cannot use --debug with --mode=jvm"
     exit 1
   fi
 else
+  if [[ $has_gdb = "yes" ]]; then
+    if [[ $mode == "target" ]]; then
+      echo "Cannot use --gdbserver with --mode=target"
+      exit 1
+    else
+      art_debugee="$art_debugee --gdbserver $gdb_target"
+      # The tests absolutely require some timeout. We set a ~2 week timeout since we can kill the
+      # test with gdb if it goes on too long.
+      jdwp_test_timeout="1000000000"
+    fi
+  fi
   if [[ "x$with_jdwp_path" != "x" ]]; then
     vm_args="${vm_args} --vm-arg -Djpda.settings.debuggeeAgentArgument=-agentpath:${agent_wrapper}"
     vm_args="${vm_args} --vm-arg -Djpda.settings.debuggeeAgentName=${with_jdwp_path}"
diff --git a/tools/wrapagentproperties/wrapagentproperties.cc b/tools/wrapagentproperties/wrapagentproperties.cc
index dca6270..67d5279 100644
--- a/tools/wrapagentproperties/wrapagentproperties.cc
+++ b/tools/wrapagentproperties/wrapagentproperties.cc
@@ -45,7 +45,6 @@
 
 struct Unloader {
   AgentUnloadFunction unload;
-  void* dlclose_handle;
 };
 static std::vector<Unloader> unload_functions;
 
@@ -71,7 +70,6 @@
       std::lock_guard<std::mutex> lk(unload_mutex);
       unload_functions.push_back({
         reinterpret_cast<AgentUnloadFunction>(dlsym(dlopen_handle, kOnUnload)),
-        dlopen_handle
       });
     }
     attach = reinterpret_cast<AgentLoadFunction>(dlsym(dlopen_handle, kOnAttach));
@@ -337,7 +335,7 @@
   std::lock_guard<std::mutex> lk(unload_mutex);
   for (const Unloader& u : unload_functions) {
     u.unload(jvm);
-    dlclose(u.dlclose_handle);
+    // Don't dlclose since some agents expect to still have code loaded after this.
   }
   unload_functions.clear();
 }