Merge "Revert "Test for jit deadlock""
diff --git a/build/Android.bp b/build/Android.bp
index 62f71ff..5f64c2d 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -18,16 +18,28 @@
 }
 
 art_clang_tidy_errors = [
-    // Protect scoped things like MutexLock.
-    "bugprone-unused-raii",
+    "bugprone-lambda-function-name",
+    "bugprone-unused-raii",  // Protect scoped things like MutexLock.
+    "bugprone-virtual-near-miss",
+    "modernize-use-bool-literals",
+    "modernize-use-nullptr",
+    "performance-faster-string-find",
     "performance-for-range-copy",
+    "performance-implicit-conversion-in-loop",
     "performance-unnecessary-copy-initialization",
     "performance-unnecessary-value-param",
     "misc-unused-using-decls",
 ]
 // Should be: strings.Join(art_clang_tidy_errors, ",").
-art_clang_tidy_errors_str = "bugprone-unused-raii"
+art_clang_tidy_errors_str = "bugprone-lambda-function-name"
+        + ",bugprone-unused-raii"
+        + ",bugprone-virtual-near-miss"
+        + ",modernize-redundant-void-arg"
+        + ",modernize-use-bool-literals"
+        + ",modernize-use-nullptr"
+        + ",performance-faster-string-find"
         + ",performance-for-range-copy"
+        + ",performance-implicit-conversion-in-loop"
         + ",performance-unnecessary-copy-initialization"
         + ",performance-unnecessary-value-param"
         + ",misc-unused-using-decls"
@@ -44,6 +56,11 @@
     // No exceptions.
     "-misc-noexcept-move-constructor",
     "-performance-noexcept-move-constructor",
+    // "Modernization" we don't agree with.
+    "-modernize-use-auto",
+    "-modernize-return-braced-init-list",
+    "-modernize-use-default-member-init",
+    "-modernize-pass-by-value",
 ]
 
 art_global_defaults {
diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h
index 165fc60..8b395a0 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.h
+++ b/compiler/jni/quick/mips/calling_convention_mips.h
@@ -87,7 +87,7 @@
  private:
   // Padding to ensure longs and doubles are not split in o32.
   size_t padding_;
-  size_t use_fp_arg_registers_;
+  bool use_fp_arg_registers_;
 
   DISALLOW_COPY_AND_ASSIGN(MipsJniCallingConvention);
 };
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index e84896b..d440cf3 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -197,7 +197,7 @@
     return GetNumberOfJitStringRoots() + GetNumberOfJitClassRoots();
   }
 
-  void EmitJitRoots(Handle<mirror::ObjectArray<mirror::Object>> roots)
+  void EmitJitRoots(/*out*/std::vector<Handle<mirror::Object>>* roots)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
@@ -230,29 +230,31 @@
 };
 
 void CodeGenerator::CodeGenerationData::EmitJitRoots(
-    Handle<mirror::ObjectArray<mirror::Object>> roots) {
-  DCHECK_EQ(static_cast<size_t>(roots->GetLength()), GetNumberOfJitRoots());
+    /*out*/std::vector<Handle<mirror::Object>>* roots) {
+  DCHECK(roots->empty());
+  roots->reserve(GetNumberOfJitRoots());
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   size_t index = 0;
   for (auto& entry : jit_string_roots_) {
     // Update the `roots` with the string, and replace the address temporarily
     // stored to the index in the table.
     uint64_t address = entry.second;
-    roots->Set(index, reinterpret_cast<StackReference<mirror::String>*>(address)->AsMirrorPtr());
-    DCHECK(roots->Get(index) != nullptr);
+    roots->emplace_back(reinterpret_cast<StackReference<mirror::Object>*>(address));
+    DCHECK(roots->back() != nullptr);
+    DCHECK(roots->back()->IsString());
     entry.second = index;
     // Ensure the string is strongly interned. This is a requirement on how the JIT
     // handles strings. b/32995596
-    class_linker->GetInternTable()->InternStrong(
-        reinterpret_cast<mirror::String*>(roots->Get(index)));
+    class_linker->GetInternTable()->InternStrong(roots->back()->AsString());
     ++index;
   }
   for (auto& entry : jit_class_roots_) {
     // Update the `roots` with the class, and replace the address temporarily
     // stored to the index in the table.
     uint64_t address = entry.second;
-    roots->Set(index, reinterpret_cast<StackReference<mirror::Class>*>(address)->AsMirrorPtr());
-    DCHECK(roots->Get(index) != nullptr);
+    roots->emplace_back(reinterpret_cast<StackReference<mirror::Object>*>(address));
+    DCHECK(roots->back() != nullptr);
+    DCHECK(roots->back()->IsClass());
     entry.second = index;
     ++index;
   }
@@ -1645,8 +1647,8 @@
 }
 
 void CodeGenerator::EmitJitRoots(uint8_t* code,
-                                 Handle<mirror::ObjectArray<mirror::Object>> roots,
-                                 const uint8_t* roots_data) {
+                                 const uint8_t* roots_data,
+                                 /*out*/std::vector<Handle<mirror::Object>>* roots) {
   code_generation_data_->EmitJitRoots(roots);
   EmitJitRootPatches(code, roots_data);
 }
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index e77d621..4e73e0b 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -356,8 +356,8 @@
   // Fills the `literals` array with literals collected during code generation.
   // Also emits literal patches.
   void EmitJitRoots(uint8_t* code,
-                    Handle<mirror::ObjectArray<mirror::Object>> roots,
-                    const uint8_t* roots_data)
+                    const uint8_t* roots_data,
+                    /*out*/std::vector<Handle<mirror::Object>>* roots)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   bool IsLeafMethod() const {
@@ -622,7 +622,7 @@
   // otherwise return a fall-back info that should be used instead.
   virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) = 0;
+      ArtMethod* method) = 0;
 
   // Generate a call to a static or direct method.
   virtual void GenerateStaticOrDirectCall(
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d56f7aa..25eadcd 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4053,7 +4053,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+      ArtMethod* method ATTRIBUTE_UNUSED) {
   // On ARM64 we support all dispatch types.
   return desired_dispatch_info;
 }
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 2e7a20b..1ba58b1 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -557,7 +557,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   void GenerateStaticOrDirectCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 3580975..d5149b3 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -8650,7 +8650,7 @@
 // otherwise return a fall-back info that should be used instead.
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch(
     const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-    HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+    ArtMethod* method ATTRIBUTE_UNUSED) {
   return desired_dispatch_info;
 }
 
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 33502d4..5edca87 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -547,7 +547,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   void GenerateStaticOrDirectCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index d74a7a7..1cf5515 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -7964,7 +7964,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+      ArtMethod* method ATTRIBUTE_UNUSED) {
   return desired_dispatch_info;
 }
 
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index bf95893..5080731 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -563,7 +563,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   void GenerateStaticOrDirectCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 7c89808..27534b0 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -6059,7 +6059,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+      ArtMethod* method ATTRIBUTE_UNUSED) {
   // On MIPS64 we support all dispatch types.
   return desired_dispatch_info;
 }
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index ddc154d..52f3a62 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -541,7 +541,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   void GenerateStaticOrDirectCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6a27081..6c77232 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4785,7 +4785,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+      ArtMethod* method ATTRIBUTE_UNUSED) {
   return desired_dispatch_info;
 }
 
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 6154771..93b0461 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -410,7 +410,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   // Generate a call to a static or direct method.
   void GenerateStaticOrDirectCall(
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 489652b..39d9789 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -978,7 +978,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
+      ArtMethod* method ATTRIBUTE_UNUSED) {
   return desired_dispatch_info;
 }
 
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index f77a5c8..1e71397 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -409,7 +409,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      HInvokeStaticOrDirect* invoke) override;
+      ArtMethod* method) override;
 
   void GenerateStaticOrDirectCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 3ba7414..1be96fb 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -2022,13 +2022,11 @@
   // optimization that could lead to a HDeoptimize. The following optimizations do not.
   HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner");
   HConstantFolding fold(callee_graph, "constant_folding$inliner");
-  HSharpening sharpening(callee_graph, codegen_);
   InstructionSimplifier simplify(callee_graph, codegen_, inline_stats_);
   IntrinsicsRecognizer intrinsics(callee_graph, inline_stats_);
 
   HOptimization* optimizations[] = {
     &intrinsics,
-    &sharpening,
     &simplify,
     &fold,
     &dce,
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 034761d..72b6748 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -978,11 +978,8 @@
       }
     }
 
-    HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
-        HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall,
-        HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
-        0u
-    };
+    HInvokeStaticOrDirect::DispatchInfo dispatch_info =
+        HSharpening::SharpenInvokeStaticOrDirect(resolved_method, code_generator_);
     MethodReference target_method(resolved_method->GetDexFile(),
                                   resolved_method->GetDexMethodIndex());
     invoke = new (allocator_) HInvokeStaticOrDirect(allocator_,
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index bb96c21..ad50bb8 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1317,7 +1317,7 @@
   }
 
   HNeg* neg = left_is_neg ? left->AsNeg() : right->AsNeg();
-  if ((left_is_neg ^ right_is_neg) && neg->HasOnlyOneNonEnvironmentUse()) {
+  if (left_is_neg != right_is_neg && neg->HasOnlyOneNonEnvironmentUse()) {
     // Replace code looking like
     //    NEG tmp, b
     //    ADD dst, a, tmp
@@ -2290,7 +2290,7 @@
       // the invoke, as we would need to look it up in the current dex file, and it
       // is unlikely that it exists. The most usual situation for such typed
       // arraycopy methods is a direct pointer to the boot image.
-      HSharpening::SharpenInvokeStaticOrDirect(invoke, codegen_);
+      invoke->SetDispatchInfo(HSharpening::SharpenInvokeStaticOrDirect(method, codegen_));
     }
   }
 }
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index bc59fcf..38e4c89 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -1092,7 +1092,8 @@
     assembler->MaybeUnpoisonHeapReference(tmp);
   }
   __ Subs(tmp, tmp, expected);
-  __ B(ne, failure, (failure == loop_exit) ? kNear : kBranchWithoutHint);
+  static_cast<vixl32::MacroAssembler*>(assembler->GetVIXLAssembler())->
+      B(ne, failure, /* hint= */ (failure == loop_exit) ? kNear : kBranchWithoutHint);
   if (type == DataType::Type::kReference) {
     assembler->MaybePoisonHeapReference(value);
   }
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index 142ddb5..75466a3 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -84,8 +84,6 @@
       return HDeadCodeElimination::kDeadCodeEliminationPassName;
     case OptimizationPass::kInliner:
       return HInliner::kInlinerPassName;
-    case OptimizationPass::kSharpening:
-      return HSharpening::kSharpeningPassName;
     case OptimizationPass::kSelectGenerator:
       return HSelectGenerator::kSelectGeneratorPassName;
     case OptimizationPass::kInstructionSimplifier:
@@ -148,7 +146,6 @@
   X(OptimizationPass::kLoopOptimization);
   X(OptimizationPass::kScheduling);
   X(OptimizationPass::kSelectGenerator);
-  X(OptimizationPass::kSharpening);
   X(OptimizationPass::kSideEffectsAnalysis);
 #ifdef ART_ENABLE_CODEGEN_arm
   X(OptimizationPass::kInstructionSimplifierArm);
@@ -264,9 +261,6 @@
                                        pass_name);
         break;
       }
-      case OptimizationPass::kSharpening:
-        opt = new (allocator) HSharpening(graph, codegen, pass_name);
-        break;
       case OptimizationPass::kSelectGenerator:
         opt = new (allocator) HSelectGenerator(graph, handles, stats, pass_name);
         break;
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 88b283c..c258d51 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -84,7 +84,6 @@
   kLoopOptimization,
   kScheduling,
   kSelectGenerator,
-  kSharpening,
   kSideEffectsAnalysis,
 #ifdef ART_ENABLE_CODEGEN_arm
   kInstructionSimplifierArm,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index ff1207a..9ae025b 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -624,7 +624,6 @@
   OptimizationDef optimizations[] = {
     // Initial optimizations.
     OptDef(OptimizationPass::kIntrinsicsRecognizer),
-    OptDef(OptimizationPass::kSharpening),
     OptDef(OptimizationPass::kConstantFolding),
     OptDef(OptimizationPass::kInstructionSimplifier),
     OptDef(OptimizationPass::kDeadCodeElimination,
@@ -1219,7 +1218,7 @@
     const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
     JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
         compiler_options, access_flags, method_idx, *dex_file);
-    ScopedNullHandle<mirror::ObjectArray<mirror::Object>> roots;
+    std::vector<Handle<mirror::Object>> roots;
     ArenaSet<ArtMethod*, std::less<ArtMethod*>> cha_single_implementation_list(
         allocator.Adapter(kArenaAllocCHA));
     ArenaStack arena_stack(runtime->GetJitArenaPool());
@@ -1321,19 +1320,6 @@
 
   ScopedArenaVector<uint8_t> stack_map = codegen->BuildStackMaps(code_item);
   size_t number_of_roots = codegen->GetNumberOfJitRoots();
-  // We allocate an object array to ensure the JIT roots that we will collect in EmitJitRoots
-  // will be visible by the GC between EmitLiterals and CommitCode. Once CommitCode is
-  // executed, this array is not needed.
-  Handle<mirror::ObjectArray<mirror::Object>> roots(
-      hs.NewHandle(mirror::ObjectArray<mirror::Object>::Alloc(
-          self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(), number_of_roots)));
-  if (roots == nullptr) {
-    // Out of memory, just clear the exception to avoid any Java exception uncaught problems.
-    MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit);
-    DCHECK(self->IsExceptionPending());
-    self->ClearException();
-    return false;
-  }
   uint8_t* stack_map_data = nullptr;
   uint8_t* roots_data = nullptr;
   uint32_t data_size = code_cache->ReserveData(self,
@@ -1347,7 +1333,14 @@
     return false;
   }
   memcpy(stack_map_data, stack_map.data(), stack_map.size());
-  codegen->EmitJitRoots(code_allocator.GetData(), roots, roots_data);
+  std::vector<Handle<mirror::Object>> roots;
+  codegen->EmitJitRoots(code_allocator.GetData(), roots_data, &roots);
+  // The root Handle<>s filled by the codegen reference entries in the VariableSizedHandleScope.
+  DCHECK(std::all_of(roots.begin(),
+                     roots.end(),
+                     [&handles](Handle<mirror::Object> root){
+                       return handles.Contains(root.GetReference());
+                     }));
 
   const void* code = code_cache->CommitCode(
       self,
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index db6a760..be5304c 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -872,9 +872,9 @@
   // Create an interval with lifetime holes.
   static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
   LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one);
-  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
-  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 7));
-  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 6));
+  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
+  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 7));
+  first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 6));
 
   locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
   locations->SetOut(Location::RequiresRegister());
@@ -895,9 +895,9 @@
   // before lifetime position 6 yet.
   static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
   LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three);
-  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
-  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 4));
-  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 3));
+  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
+  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 4));
+  third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 3));
   locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
   locations->SetOut(Location::RequiresRegister());
   third = third->SplitAt(3);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 5c2f57e..c864951 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -35,22 +35,6 @@
 
 namespace art {
 
-bool HSharpening::Run() {
-  // We don't care about the order of the blocks here.
-  for (HBasicBlock* block : graph_->GetReversePostOrder()) {
-    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      HInstruction* instruction = it.Current();
-      if (instruction->IsInvokeStaticOrDirect()) {
-        SharpenInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect(), codegen_);
-      }
-      // TODO: Move the sharpening of invoke-virtual/-interface/-super from HGraphBuilder
-      //       here. Rewrite it to avoid the CompilerDriver's reliance on verifier data
-      //       because we know the type better when inlining.
-    }
-  }
-  return true;
-}
-
 static bool IsInBootImage(ArtMethod* method) {
   const std::vector<gc::space::ImageSpace*>& image_spaces =
       Runtime::Current()->GetHeap()->GetBootImageSpaces();
@@ -72,17 +56,14 @@
   return compiler_options.IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
 }
 
-void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke,
-                                              CodeGenerator* codegen) {
-  if (invoke->IsStringInit()) {
-    // Not using the dex cache arrays. But we could still try to use a better dispatch...
-    // TODO: Use direct_method and direct_code for the appropriate StringFactory method.
-    return;
+HInvokeStaticOrDirect::DispatchInfo HSharpening::SharpenInvokeStaticOrDirect(
+    ArtMethod* callee, CodeGenerator* codegen) {
+  if (kIsDebugBuild) {
+    ScopedObjectAccess soa(Thread::Current());  // Required for GetDeclaringClass below.
+    DCHECK(callee != nullptr);
+    DCHECK(!(callee->IsConstructor() && callee->GetDeclaringClass()->IsStringClass()));
   }
 
-  ArtMethod* callee = invoke->GetResolvedMethod();
-  DCHECK(callee != nullptr);
-
   HInvokeStaticOrDirect::MethodLoadKind method_load_kind;
   HInvokeStaticOrDirect::CodePtrLocation code_ptr_location;
   uint64_t method_load_data = 0u;
@@ -141,9 +122,7 @@
   HInvokeStaticOrDirect::DispatchInfo desired_dispatch_info = {
       method_load_kind, code_ptr_location, method_load_data
   };
-  HInvokeStaticOrDirect::DispatchInfo dispatch_info =
-      codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke);
-  invoke->SetDispatchInfo(dispatch_info);
+  return codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, callee);
 }
 
 HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h
index dc55eea..b818672 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -25,24 +25,13 @@
 class CodeGenerator;
 class DexCompilationUnit;
 
-// Optimization that tries to improve the way we dispatch methods and access types,
-// fields, etc. Besides actual method sharpening based on receiver type (for example
-// virtual->direct), this includes selecting the best available dispatch for
-// invoke-static/-direct based on code generator support.
-class HSharpening : public HOptimization {
+// Utility methods that try to improve the way we dispatch methods, and access
+// types and strings.
+class HSharpening {
  public:
-  HSharpening(HGraph* graph,
-              CodeGenerator* codegen,
-              const char* name = kSharpeningPassName)
-      : HOptimization(graph, name),
-        codegen_(codegen) { }
-
-  bool Run() override;
-
-  static constexpr const char* kSharpeningPassName = "sharpening";
-
-  // Used by Sharpening and InstructionSimplifier.
-  static void SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, CodeGenerator* codegen);
+  // Used by the builder and InstructionSimplifier.
+  static HInvokeStaticOrDirect::DispatchInfo SharpenInvokeStaticOrDirect(
+      ArtMethod* callee, CodeGenerator* codegen);
 
   // Used by the builder and the inliner.
   static HLoadClass::LoadKind ComputeLoadClassKind(HLoadClass* load_class,
@@ -61,9 +50,6 @@
                                 CodeGenerator* codegen,
                                 const DexCompilationUnit& dex_compilation_unit,
                                 VariableSizedHandleScope* handles);
-
- private:
-  CodeGenerator* codegen_;
 };
 
 }  // namespace art
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index c0b6f98..1ba535f 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -3610,7 +3610,7 @@
     label->LinkTo(branch_id);
   }
   // Reserve space for the branch.
-  while (length--) {
+  for (; length != 0u; --length) {
     Nop();
   }
 }
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 5b1c5d9..6df9562 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -2889,7 +2889,7 @@
     label->LinkTo(branch_id);
   }
   // Reserve space for the branch.
-  while (length--) {
+  for (; length != 0u; --length) {
     Nop();
   }
 }
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 523c90b..306b73f 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -424,7 +424,7 @@
     return verifier_deps_->dex_deps_.size();
   }
 
-  size_t HasEachKindOfRecord() {
+  bool HasEachKindOfRecord() {
     bool has_strings = false;
     bool has_assignability = false;
     bool has_classes = false;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index e2db11f..e89de84 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -2405,7 +2405,7 @@
   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
                 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
-    return 0;
+    return false;
   }
   DCHECK_OFFSET();
 
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index 3e576c8..d15bbda 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -17,12 +17,12 @@
 
 cc_defaults {
     name: "dexdump_defaults",
+    defaults: ["art_defaults"],
     srcs: [
         "dexdump_cfg.cc",
         "dexdump_main.cc",
         "dexdump.cc",
     ],
-    cflags: ["-Wall", "-Werror"],
 }
 
 art_cc_binary {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 95d88be..f09d448 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -331,7 +331,7 @@
  * NULL-terminated.
  */
 static void asciify(char* out, const unsigned char* data, size_t len) {
-  while (len--) {
+  for (; len != 0u; --len) {
     if (*data < 0x20) {
       // Could do more here, but we don't need them yet.
       switch (*data) {
@@ -1800,18 +1800,18 @@
   // Iterate over all classes.
   char* package = nullptr;
   const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
-  for (u4 i = 0; i < classDefsSize; i++) {
-    dumpClass(pDexFile, i, &package);
+  for (u4 j = 0; j < classDefsSize; j++) {
+    dumpClass(pDexFile, j, &package);
   }  // for
 
   // Iterate over all method handles.
-  for (u4 i = 0; i < pDexFile->NumMethodHandles(); ++i) {
-    dumpMethodHandle(pDexFile, i);
+  for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
+    dumpMethodHandle(pDexFile, j);
   }  // for
 
   // Iterate over all call site ids.
-  for (u4 i = 0; i < pDexFile->NumCallSiteIds(); ++i) {
-    dumpCallSite(pDexFile, i);
+  for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
+    dumpCallSite(pDexFile, j);
   }  // for
 
   // Free the last package allocated.
diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc
index f4a3866..cf0d113 100644
--- a/dexdump/dexdump_main.cc
+++ b/dexdump/dexdump_main.cc
@@ -37,7 +37,7 @@
 /*
  * Shows usage.
  */
-static void usage(void) {
+static void usage() {
   LOG(ERROR) << "Copyright (C) 2007 The Android Open Source Project\n";
   LOG(ERROR) << gProgName << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-j] [-l layout] [-o outfile]"
                   " dexfile...\n";
@@ -64,7 +64,7 @@
   gOptions.verbose = true;
 
   // Parse all arguments.
-  while (1) {
+  while (true) {
     const int ic = getopt(argc, argv, "acdefghijl:o:");
     if (ic < 0) {
       break;  // done
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index b539f5d..1b8412d 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -247,7 +247,7 @@
  * NULL-terminated.
  */
 static void Asciify(char* out, const unsigned char* data, size_t len) {
-  while (len--) {
+  for (; len != 0u; --len) {
     if (*data < 0x20) {
       // Could do more here, but we don't need them yet.
       switch (*data) {
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 9f73347..a851cfa 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -42,7 +42,7 @@
 /*
  * Shows usage.
  */
-static void Usage(void) {
+static void Usage() {
   LOG(ERROR) << "Copyright (C) 2016 The Android Open Source Project\n";
   LOG(ERROR) << kProgramName
              << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
@@ -85,7 +85,7 @@
   bool want_usage = false;
 
   // Parse all arguments.
-  while (1) {
+  while (true) {
     const int ic = getopt(argc, argv, "abcdefghil:o:p:stuvw:x:");
     if (ic < 0) {
       break;  // done
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
index bd521ac..217a024 100644
--- a/dexlist/Android.bp
+++ b/dexlist/Android.bp
@@ -14,18 +14,14 @@
 
 art_cc_binary {
     name: "dexlist",
+    defaults: ["art_defaults"],
     host_supported: true,
     srcs: ["dexlist.cc"],
-    cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libdexfile",
         "libartbase",
         "libbase"
     ],
-    // TODO: fix b/72216369 and remove the need for this.
-    include_dirs: [
-        "art/runtime"  // dex utils.
-    ],
 }
 
 art_cc_test {
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index c2514a1..23be19d 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -197,7 +197,7 @@
 /*
  * Shows usage.
  */
-static void usage(void) {
+static void usage() {
   LOG(ERROR) << "Copyright (C) 2007 The Android Open Source Project\n";
   LOG(ERROR) << gProgName << ": [-m p.c.m] [-o outfile] dexfile...";
   LOG(ERROR) << "";
@@ -212,7 +212,7 @@
   memset(&gOptions, 0, sizeof(gOptions));
 
   // Parse all arguments.
-  while (1) {
+  while (true) {
     const int ic = getopt(argc, argv, "o:m:");
     if (ic < 0) {
       break;  // done
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 51b3d75..1b2e8d7 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -762,7 +762,8 @@
 
     std::unordered_set<size_t> dirty_members;
     // Examine the members comprising the ArtMethod, computing which members are dirty.
-    for (const std::pair<size_t, MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
+    for (const std::pair<const size_t,
+                         MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
       const size_t offset = p.first;
       if (memcmp(base_ptr + offset, remote_bytes + offset, p.second.size_) != 0) {
         dirty_members.insert(p.first);
@@ -788,7 +789,8 @@
   void DumpDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
     DumpSamplesAndOffsetCount();
     os_ << "      offset to field map:\n";
-    for (const std::pair<size_t, MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
+    for (const std::pair<const size_t,
+                         MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
       const size_t offset = p.first;
       const size_t size = p.second.size_;
       os_ << StringPrintf("        %zu-%zu: ", offset, offset + size - 1)
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 1b603b5..19f1532 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -29,6 +29,8 @@
         "base/hex_dump.cc",
         "base/logging.cc",
         "base/malloc_arena_pool.cc",
+        "base/membarrier.cc",
+        "base/memfd.cc",
         "base/memory_region.cc",
         "base/mem_map.cc",
         // "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong
@@ -186,6 +188,8 @@
         "base/indenter_test.cc",
         "base/leb128_test.cc",
         "base/logging_test.cc",
+        "base/memfd_test.cc",
+        "base/membarrier_test.cc",
         "base/memory_region_test.cc",
         "base/mem_map_test.cc",
         "base/safe_copy_test.cc",
diff --git a/libartbase/base/membarrier.cc b/libartbase/base/membarrier.cc
new file mode 100644
index 0000000..490dbf3
--- /dev/null
+++ b/libartbase/base/membarrier.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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 "membarrier.h"
+
+#include <errno.h>
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "macros.h"
+
+#if defined(__BIONIC__)
+
+#include <atomic>
+#include <android/get_device_api_level.h>
+#include <linux/membarrier.h>
+
+#define CHECK_MEMBARRIER_CMD(art_value, membarrier_value) \
+  static_assert(static_cast<int>(art_value) == membarrier_value, "Bad value for " # art_value)
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kQuery, MEMBARRIER_CMD_QUERY);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kGlobal, MEMBARRIER_CMD_SHARED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kRegisterPrivateExpedited,
+                     MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+#undef CHECK_MEMBARRIER_CMD
+
+#endif  // __BIONIC
+
+namespace art {
+
+#if defined(__NR_membarrier)
+
+int membarrier(MembarrierCommand command) {
+#if defined(__BIONIC__)
+  // Avoid calling membarrier on older Android versions where membarrier may be barred by secomp
+  // causing the current process to be killed. The probing here could be considered expensive so
+  // endeavour not to repeat too often.
+  static int api_level = android_get_device_api_level();
+  if (api_level < __ANDROID_API_Q__) {
+    errno = ENOSYS;
+    return -1;
+  }
+#endif  // __BIONIC__
+  return syscall(__NR_membarrier, static_cast<int>(command), 0);
+}
+
+#else  // __NR_membarrier
+
+int membarrier(MembarrierCommand command ATTRIBUTE_UNUSED) {
+  // In principle this could be supported on linux, but Android's prebuilt glibc does not include
+  // the system call number defintions (b/111199492).
+  errno = ENOSYS;
+  return -1;
+}
+
+#endif  // __NR_membarrier
+
+}  // namespace art
diff --git a/libartbase/base/membarrier.h b/libartbase/base/membarrier.h
new file mode 100644
index 0000000..f829fc1
--- /dev/null
+++ b/libartbase/base/membarrier.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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_LIBARTBASE_BASE_MEMBARRIER_H_
+#define ART_LIBARTBASE_BASE_MEMBARRIER_H_
+
+namespace art {
+  // Command types for the linux membarrier system call. Different Linux installation may include
+  // different subsets of these commands (at the same codepoints).
+  //
+  // Hardcoding these values is temporary until bionic and prebuilts glibc have an up to date
+  // linux/membarrier.h. The order and values follow the current linux definitions.
+  enum class MembarrierCommand : int  {
+    // MEMBARRIER_CMD_QUERY
+    kQuery = 0,
+    // MEMBARRIER_CMD_GLOBAL
+    kGlobal = (1 << 0),
+    // MEMBARRIER_CMD_GLOBAL_EXPEDITED
+    kGlobalExpedited = (1 << 1),
+    // MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED
+    kRegisterGlobalExpedited = (1 << 2),
+    // MEMBARRIER_CMD_PRIVATE_EXPEDITED
+    kPrivateExpedited = (1 << 3),
+    // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
+    kRegisterPrivateExpedited = (1 << 4),
+    // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
+    kPrivateExpeditedSyncCore = (1 << 5),
+    // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
+    kRegisterPrivateExpeditedSyncCore = (1 << 6)
+  };
+
+  // Call membarrier(2) if available on platform and return result. This method can fail if the
+  // command is not supported by the kernel. The underlying system call is linux specific.
+  int membarrier(MembarrierCommand command);
+
+}  // namespace art
+
+#endif  // ART_LIBARTBASE_BASE_MEMBARRIER_H_
diff --git a/libartbase/base/membarrier_test.cc b/libartbase/base/membarrier_test.cc
new file mode 100644
index 0000000..3eedf14
--- /dev/null
+++ b/libartbase/base/membarrier_test.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 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 <gtest/gtest.h>
+
+#include "membarrier.h"
+
+class ScopedErrnoCleaner {
+ public:
+  ScopedErrnoCleaner() { errno = 0; }
+  ~ScopedErrnoCleaner() { errno = 0; }
+};
+
+bool HasMembarrier(art::MembarrierCommand cmd) {
+  ScopedErrnoCleaner errno_cleaner;
+  int supported_cmds = art::membarrier(art::MembarrierCommand::kQuery);
+  return (supported_cmds > 0) && ((supported_cmds & static_cast<int>(cmd)) != 0);
+}
+
+TEST(membarrier, query) {
+  ScopedErrnoCleaner errno_cleaner;
+  int supported = art::membarrier(art::MembarrierCommand::kQuery);
+  if (errno == 0) {
+    ASSERT_LE(0, supported);
+  } else {
+    ASSERT_TRUE(errno == ENOSYS && supported == -1);
+  }
+}
+
+TEST(membarrier, global_barrier) {
+  if (!HasMembarrier(art::MembarrierCommand::kGlobal)) {
+    GTEST_LOG_(INFO) << "MembarrierCommand::kGlobal not supported, skipping test.";
+    return;
+  }
+  ASSERT_EQ(0, art::membarrier(art::MembarrierCommand::kGlobal));
+}
+
+static const char* MembarrierCommandToName(art::MembarrierCommand cmd) {
+#define CASE_VALUE(x) case (x): return #x;
+  switch (cmd) {
+    CASE_VALUE(art::MembarrierCommand::kQuery);
+    CASE_VALUE(art::MembarrierCommand::kGlobal);
+    CASE_VALUE(art::MembarrierCommand::kGlobalExpedited);
+    CASE_VALUE(art::MembarrierCommand::kRegisterGlobalExpedited);
+    CASE_VALUE(art::MembarrierCommand::kPrivateExpedited);
+    CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpedited);
+    CASE_VALUE(art::MembarrierCommand::kPrivateExpeditedSyncCore);
+    CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore);
+  }
+}
+
+static void TestRegisterAndBarrierCommands(art::MembarrierCommand membarrier_cmd_register,
+                                           art::MembarrierCommand membarrier_cmd_barrier) {
+  if (!HasMembarrier(membarrier_cmd_register)) {
+    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register)
+        << " not supported, skipping test.";
+    return;
+  }
+  if (!HasMembarrier(membarrier_cmd_barrier)) {
+    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier)
+        << " not supported, skipping test.";
+    return;
+  }
+
+  ScopedErrnoCleaner errno_cleaner;
+
+  // Check barrier use without prior registration.
+  if (membarrier_cmd_register == art::MembarrierCommand::kRegisterGlobalExpedited) {
+    // Global barrier use is always okay.
+    ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier));
+  } else {
+    // Private barrier should fail.
+    ASSERT_EQ(-1, art::membarrier(membarrier_cmd_barrier));
+    ASSERT_EQ(EPERM, errno);
+    errno = 0;
+  }
+
+  // Check registration for barrier succeeds.
+  ASSERT_EQ(0, art::membarrier(membarrier_cmd_register));
+
+  // Check barrier use after registration succeeds.
+  ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier));
+}
+
+TEST(membarrier, global_expedited) {
+  TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterGlobalExpedited,
+                                 art::MembarrierCommand::kGlobalExpedited);
+}
+
+TEST(membarrier, private_expedited) {
+  TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpedited,
+                                 art::MembarrierCommand::kPrivateExpedited);
+}
+
+TEST(membarrier, private_expedited_sync_core) {
+  TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore,
+                                 art::MembarrierCommand::kPrivateExpeditedSyncCore);
+}
diff --git a/libartbase/base/memfd.cc b/libartbase/base/memfd.cc
new file mode 100644
index 0000000..1afcd7b
--- /dev/null
+++ b/libartbase/base/memfd.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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 "memfd.h"
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "macros.h"
+
+// When building for linux host, glibc in prebuilts does not include memfd_create system call
+// number. As a temporary testing measure, we add the definition here.
+#if defined(__linux__) && !defined(__NR_memfd_create)
+#if defined(__x86_64__)
+#define __NR_memfd_create 319
+#elif defined(__i386__)
+#define __NR_memfd_create 356
+#endif  // defined(__i386__)
+#endif  // defined(__linux__) && !defined(__NR_memfd_create)
+
+namespace art {
+
+#if defined(__NR_memfd_create)
+
+int memfd_create(const char* name, unsigned int flags) {
+  return syscall(__NR_memfd_create, name, flags);
+}
+
+#else  // __NR_memfd_create
+
+int memfd_create(const char* name ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) {
+  errno = ENOSYS;
+  return -1;
+}
+
+#endif  // __NR_memfd_create
+
+}  // namespace art
diff --git a/libartbase/base/memfd.h b/libartbase/base/memfd.h
new file mode 100644
index 0000000..4367198
--- /dev/null
+++ b/libartbase/base/memfd.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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_LIBARTBASE_BASE_MEMFD_H_
+#define ART_LIBARTBASE_BASE_MEMFD_H_
+
+namespace art {
+
+  // Call memfd(2) if available on platform and return result.
+int memfd_create(const char* name, unsigned int flags);
+
+}  // namespace art
+
+#endif  // ART_LIBARTBASE_BASE_MEMFD_H_
diff --git a/libartbase/base/memfd_test.cc b/libartbase/base/memfd_test.cc
new file mode 100644
index 0000000..1edf3a1
--- /dev/null
+++ b/libartbase/base/memfd_test.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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 <gtest/gtest.h>
+
+#include "memfd.h"
+
+TEST(memfd, basic) {
+  errno = 0;
+  int fd = art::memfd_create("memfd_create_test", 0);
+  if (fd < 0) {
+    ASSERT_EQ(ENOSYS, errno);
+    GTEST_LOG_(INFO) << "memfd_create not supported, skipping test.";
+    return;
+  }
+  ASSERT_TRUE(close(fd) == 0 || errno != EBADF);
+}
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 74cc5b9..2242fe8 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -213,42 +213,4 @@
   }
 }
 
-bool FlushInstructionPipeline() {
-  // membarrier(2) is only supported for target builds (b/111199492).
-#if defined(__BIONIC__)
-  static constexpr int kSyncCoreMask =
-      MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE |
-      MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE;
-  static bool have_probed = false;
-  static bool have_sync_core = false;
-
-  if (UNLIKELY(!have_probed)) {
-    // Probe membarrier(2) commands supported by kernel.
-    int commands = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
-    if (commands >= 0) {
-      have_sync_core = (commands & kSyncCoreMask) == kSyncCoreMask;
-      if (have_sync_core) {
-        // Register with kernel that we'll be using the private expedited sync core command.
-        CheckedCall(syscall,
-                    "membarrier register sync core",
-                    __NR_membarrier,
-                    MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
-                    0);
-      }
-    }
-    have_probed = true;
-  }
-
-  if (have_sync_core) {
-    CheckedCall(syscall,
-                "membarrier sync core",
-                __NR_membarrier,
-                MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
-                0);
-    return true;
-  }
-#endif  // defined(__BIONIC__)
-  return false;
-}
-
 }  // namespace art
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index d85960d..e6a0459 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -162,9 +162,6 @@
   __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
 }
 
-// Flush instruction pipeline. Returns true on success, false if feature is unsupported.
-bool FlushInstructionPipeline();
-
 template <typename T>
 constexpr PointerSize ConvertToPointerSize(T any) {
   if (any == 4 || any == 8) {
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index fd011c8..f273c84 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -866,7 +866,7 @@
 bool DexFileVerifier::CheckEncodedArray() {
   DECODE_UNSIGNED_CHECKED_FROM(ptr_, size);
 
-  while (size--) {
+  for (; size != 0u; --size) {
     if (!CheckEncodedValue()) {
       failure_reason_ = StringPrintf("Bad encoded_array value: %s", failure_reason_.c_str());
       return false;
@@ -1304,7 +1304,7 @@
   }
 
   uint32_t last_addr = 0;
-  while (try_items_size--) {
+  for (; try_items_size != 0u; --try_items_size) {
     if (UNLIKELY(try_items->start_addr_ < last_addr)) {
       ErrorStringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
       return false;
@@ -1884,7 +1884,7 @@
   ptr_ = begin_;
 
   // Check the items listed in the map.
-  while (count--) {
+  for (; count != 0u; --count) {
     const size_t current_offset = offset;
     uint32_t section_offset = item->offset_;
     uint32_t section_count = item->size_;
@@ -2554,7 +2554,7 @@
   const DexFile::AnnotationSetRefItem* item = list->list_;
   uint32_t count = list->size_;
 
-  while (count--) {
+  for (; count != 0u; --count) {
     if (item->annotations_off_ != 0 &&
         !CheckOffsetToTypeMap(item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
       return false;
@@ -2839,7 +2839,7 @@
   uint32_t count = map->size_;
 
   // Cross check the items listed in the map.
-  while (count--) {
+  for (; count != 0u; --count) {
     uint32_t section_offset = item->offset_;
     uint32_t section_count = item->size_;
     DexFile::MapItemType type = static_cast<DexFile::MapItemType>(item->type_);
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 9b70e62..f5e08da 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -23,12 +23,15 @@
 #include <unistd.h>
 #include <zlib.h>
 
+#include <algorithm>
 #include <cerrno>
 #include <climits>
 #include <cstdlib>
+#include <iostream>
+#include <numeric>
+#include <random>
 #include <string>
 #include <vector>
-#include <iostream>
 
 #include "android-base/file.h"
 
@@ -1872,43 +1875,42 @@
     uint16_t method_percentage,
     uint16_t class_percentage,
     uint32_t random_seed) {
-  std::srand(random_seed);
   ProfileCompilationInfo info;
+  std::default_random_engine rng(random_seed);
+  auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
+    CHECK_LE(take, out_of);
+    std::vector<uint32_t> vec(out_of);
+    std::iota(vec.begin(), vec.end(), 0u);
+    std::shuffle(vec.begin(), vec.end(), rng);
+    vec.erase(vec.begin() + take, vec.end());
+    std::sort(vec.begin(), vec.end());
+    return vec;
+  };
   for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
     const std::string& location = dex_file->GetLocation();
     uint32_t checksum = dex_file->GetLocationChecksum();
 
     uint32_t number_of_classes = dex_file->NumClassDefs();
     uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
-    uint32_t class_start_index = rand() % number_of_classes;
-    for (uint32_t i = 0; i < number_of_classes && classes_required_in_profile; ++i) {
-      if (number_of_classes - i == classes_required_in_profile ||
-          std::rand() % (number_of_classes - i - classes_required_in_profile) == 0) {
-        uint32_t class_index = (i + class_start_index) % number_of_classes;
-        info.AddClassIndex(location,
-                           checksum,
-                           dex_file->GetClassDef(class_index).class_idx_,
-                           dex_file->NumMethodIds());
-        classes_required_in_profile--;
-      }
+    for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
+                                                      number_of_classes)) {
+      info.AddClassIndex(location,
+                         checksum,
+                         dex_file->GetClassDef(class_index).class_idx_,
+                         dex_file->NumMethodIds());
     }
 
     uint32_t number_of_methods = dex_file->NumMethodIds();
     uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
-    uint32_t method_start_index = rand() % number_of_methods;
-    for (uint32_t i = 0; i < number_of_methods && methods_required_in_profile; ++i) {
-      if (number_of_methods - i == methods_required_in_profile ||
-          std::rand() % (number_of_methods - i - methods_required_in_profile) == 0) {
-        uint32_t method_index = (method_start_index + i) % number_of_methods;
-        // Alternate between startup and post startup.
-        uint32_t flags = MethodHotness::kFlagHot;
-        flags |= ((method_index & 1) != 0)
-            ? MethodHotness::kFlagPostStartup
-            : MethodHotness::kFlagStartup;
-        info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
-                            MethodReference(dex_file.get(), method_index));
-        methods_required_in_profile--;
-      }
+    for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
+                                                       number_of_methods)) {
+      // Alternate between startup and post startup.
+      uint32_t flags = MethodHotness::kFlagHot;
+      flags |= ((method_index & 1) != 0)
+                   ? MethodHotness::kFlagPostStartup
+                   : MethodHotness::kFlagStartup;
+      info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
+                          MethodReference(dex_file.get(), method_index));
     }
   }
   return info.Save(fd);
diff --git a/patchoat/patchoat_test.cc b/patchoat/patchoat_test.cc
index 6492b96..79ae987 100644
--- a/patchoat/patchoat_test.cc
+++ b/patchoat/patchoat_test.cc
@@ -405,7 +405,7 @@
   std::vector<std::string> patchoat_image_shortened_basenames(patchoat_image_basenames.size());
   for (size_t i = 0; i < patchoat_image_basenames.size(); i++) {
     patchoat_image_shortened_basenames[i] =
-        patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of("@") + 1);
+        patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of('@') + 1);
   }
   ASSERT_EQ(dex2oat_image_basenames, patchoat_image_shortened_basenames);
 
@@ -515,16 +515,16 @@
     std::vector<std::string> rel_shortened_basenames(rel_basenames.size());
     std::vector<std::string> relocated_image_shortened_basenames(relocated_image_basenames.size());
     for (size_t i = 0; i < rel_basenames.size(); i++) {
-      rel_shortened_basenames[i] = rel_basenames[i].substr(rel_basenames[i].find_last_of("@") + 1);
+      rel_shortened_basenames[i] = rel_basenames[i].substr(rel_basenames[i].find_last_of('@') + 1);
       rel_shortened_basenames[i] =
-          rel_shortened_basenames[i].substr(0, rel_shortened_basenames[i].find("."));
+          rel_shortened_basenames[i].substr(0, rel_shortened_basenames[i].find('.'));
     }
     for (size_t i = 0; i < relocated_image_basenames.size(); i++) {
       relocated_image_shortened_basenames[i] =
-          relocated_image_basenames[i].substr(relocated_image_basenames[i].find_last_of("@") + 1);
+          relocated_image_basenames[i].substr(relocated_image_basenames[i].find_last_of('@') + 1);
       relocated_image_shortened_basenames[i] =
           relocated_image_shortened_basenames[i].substr(
-              0, relocated_image_shortened_basenames[i].find("."));
+              0, relocated_image_shortened_basenames[i].find('.'));
     }
     ASSERT_EQ(rel_shortened_basenames, relocated_image_shortened_basenames);
   }
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 51cfd43..b50a430 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -209,7 +209,7 @@
     case DexFile::kDexAnnotationArray:
     {
       uint32_t size = DecodeUnsignedLeb128(&annotation);
-      while (size--) {
+      for (; size != 0u; --size) {
         if (!SkipAnnotationValue(dex_file, &annotation)) {
           return false;
         }
@@ -221,7 +221,7 @@
     {
       DecodeUnsignedLeb128(&annotation);  // unused type_index
       uint32_t size = DecodeUnsignedLeb128(&annotation);
-      while (size--) {
+      for (; size != 0u; --size) {
         DecodeUnsignedLeb128(&annotation);  // unused element_name_index
         if (!SkipAnnotationValue(dex_file, &annotation)) {
           return false;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 8f064a3..ee4a0f4 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1029,9 +1029,7 @@
       if (obj->IsClass<kVerifyNone>()) {
         mirror::Class* as_klass = obj->AsClass<kVerifyNone>();
         FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_);
-        as_klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(as_klass,
-                                                                        pointer_size_,
-                                                                        visitor);
+        as_klass->FixupNativePointers<kVerifyNone>(as_klass, pointer_size_, visitor);
         // Deal with the pointer arrays. Use the helper function since multiple classes can reference
         // the same arrays.
         mirror::PointerArray* const vtable = as_klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index e6043c6..9245f1e 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -346,7 +346,7 @@
   if (!HaveFullPacket()) {
     /* read some more, looping until we have data */
     errno = 0;
-    while (1) {
+    while (true) {
       int selCount;
       fd_set readfds;
       int maxfd = -1;
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 29fa160..b8b0e16 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -383,7 +383,7 @@
   if (!HaveFullPacket()) {
     /* read some more, looping until we have data */
     errno = 0;
-    while (1) {
+    while (true) {
       int selCount;
       fd_set readfds;
       int maxfd = -1;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index bcbdc3b..33d228f 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -23,6 +23,7 @@
 #include "base/enums.h"
 #include "base/histogram-inl.h"
 #include "base/logging.h"  // For VLOG.
+#include "base/membarrier.h"
 #include "base/mem_map.h"
 #include "base/quasi_atomic.h"
 #include "base/stl_util.h"
@@ -187,6 +188,11 @@
     return nullptr;
   }
 
+  // Register for membarrier expedited sync core if JIT will be generating code.
+  if (!used_only_for_profile_data) {
+    art::membarrier(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore);
+  }
+
   // Decide how we should map the code and data sections.
   // If we use the code cache just for profiling we do not need to map the code section as
   // executable.
@@ -411,7 +417,7 @@
                                   size_t code_size,
                                   size_t data_size,
                                   bool osr,
-                                  Handle<mirror::ObjectArray<mirror::Object>> roots,
+                                  const std::vector<Handle<mirror::Object>>& roots,
                                   bool has_should_deoptimize_flag,
                                   const ArenaSet<ArtMethod*>& cha_single_implementation_list) {
   uint8_t* result = CommitCodeInternal(self,
@@ -477,18 +483,16 @@
   return stack_map_data - ComputeRootTableSize(GetNumberOfRoots(stack_map_data));
 }
 
-static void DCheckRootsAreValid(Handle<mirror::ObjectArray<mirror::Object>> roots)
+static void DCheckRootsAreValid(const std::vector<Handle<mirror::Object>>& roots)
     REQUIRES(!Locks::intern_table_lock_) REQUIRES_SHARED(Locks::mutator_lock_) {
   if (!kIsDebugBuild) {
     return;
   }
-  const uint32_t length = roots->GetLength();
   // Put all roots in `roots_data`.
-  for (uint32_t i = 0; i < length; ++i) {
-    ObjPtr<mirror::Object> object = roots->Get(i);
+  for (Handle<mirror::Object> object : roots) {
     // Ensure the string is strongly interned. b/32995596
     if (object->IsString()) {
-      ObjPtr<mirror::String> str = ObjPtr<mirror::String>::DownCast(object);
+      ObjPtr<mirror::String> str = object->AsString();
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr);
     }
@@ -496,12 +500,12 @@
 }
 
 void JitCodeCache::FillRootTable(uint8_t* roots_data,
-                                 Handle<mirror::ObjectArray<mirror::Object>> roots) {
+                                 const std::vector<Handle<mirror::Object>>& roots) {
   GcRoot<mirror::Object>* gc_roots = reinterpret_cast<GcRoot<mirror::Object>*>(roots_data);
-  const uint32_t length = roots->GetLength();
+  const uint32_t length = roots.size();
   // Put all roots in `roots_data`.
   for (uint32_t i = 0; i < length; ++i) {
-    ObjPtr<mirror::Object> object = roots->Get(i);
+    ObjPtr<mirror::Object> object = roots[i].Get();
     gc_roots[i] = GcRoot<mirror::Object>(object);
   }
 }
@@ -757,7 +761,7 @@
                                           size_t code_size,
                                           size_t data_size,
                                           bool osr,
-                                          Handle<mirror::ObjectArray<mirror::Object>> roots,
+                                          const std::vector<Handle<mirror::Object>>& roots,
                                           bool has_should_deoptimize_flag,
                                           const ArenaSet<ArtMethod*>&
                                               cha_single_implementation_list) {
@@ -809,9 +813,8 @@
     // shootdown (incidentally invalidating the CPU pipelines by sending an IPI to all cores to
     // notify them of the TLB invalidation). Some architectures, notably ARM and ARM64, have
     // hardware support that broadcasts TLB invalidations and so their kernels have no software
-    // based TLB shootdown. FlushInstructionPipeline() is a wrapper around the Linux
-    // membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED) syscall which does the appropriate flushing.
-    FlushInstructionPipeline();
+    // based TLB shootdown.
+    art::membarrier(art::MembarrierCommand::kPrivateExpeditedSyncCore);
 
     DCHECK(!Runtime::Current()->IsAotCompiler());
     if (has_should_deoptimize_flag) {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index a4a0f8f..e2aa01c 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -141,7 +141,7 @@
                       size_t code_size,
                       size_t data_size,
                       bool osr,
-                      Handle<mirror::ObjectArray<mirror::Object>> roots,
+                      const std::vector<Handle<mirror::Object>>& roots,
                       bool has_should_deoptimize_flag,
                       const ArenaSet<ArtMethod*>& cha_single_implementation_list)
       REQUIRES_SHARED(Locks::mutator_lock_)
@@ -297,14 +297,14 @@
                               size_t code_size,
                               size_t data_size,
                               bool osr,
-                              Handle<mirror::ObjectArray<mirror::Object>> roots,
+                              const std::vector<Handle<mirror::Object>>& roots,
                               bool has_should_deoptimize_flag,
                               const ArenaSet<ArtMethod*>& cha_single_implementation_list)
       REQUIRES(!lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Adds the given roots to the roots_data. Only a member for annotalysis.
-  void FillRootTable(uint8_t* roots_data, Handle<mirror::ObjectArray<mirror::Object>> roots)
+  void FillRootTable(uint8_t* roots_data, const std::vector<Handle<mirror::Object>>& roots)
       REQUIRES(lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 8bdd561..a31a9144 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -189,8 +189,9 @@
   T GetElementPtrSize(uint32_t idx, PointerSize ptr_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template<VerifyObjectFlags kVerifyFlags = kVerifyNone>
   void** ElementAddress(size_t index, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK_LT(index, static_cast<size_t>(GetLength()));
+    DCHECK_LT(index, static_cast<size_t>(GetLength<kVerifyFlags>()));
     return reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(this) +
                                     Array::DataOffset(static_cast<size_t>(ptr_size)).Uint32Value() +
                                     static_cast<size_t>(ptr_size) * index);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 33822d1..df70fab 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -251,18 +251,14 @@
                                           uint32_t num_direct,
                                           uint32_t num_virtual) {
   DCHECK_LE(num_direct + num_virtual, (new_methods == nullptr) ? 0 : new_methods->size());
-  SetMethodsPtrInternal(new_methods);
+  SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, methods_),
+                    static_cast<uint64_t>(reinterpret_cast<uintptr_t>(new_methods)));
   SetFieldShort<false>(OFFSET_OF_OBJECT_MEMBER(Class, copied_methods_offset_),
                     dchecked_integral_cast<uint16_t>(num_direct + num_virtual));
   SetFieldShort<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_offset_),
                        dchecked_integral_cast<uint16_t>(num_direct));
 }
 
-inline void Class::SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods) {
-  SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, methods_),
-                    static_cast<uint64_t>(reinterpret_cast<uintptr_t>(new_methods)));
-}
-
 template<VerifyObjectFlags kVerifyFlags>
 inline ArtMethod* Class::GetVirtualMethod(size_t i, PointerSize pointer_size) {
   CheckPointerSize(pointer_size);
@@ -1069,49 +1065,42 @@
   return arr != nullptr ? arr->size() : 0u;
 }
 
-template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor>
+template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor>
+inline void Class::FixupNativePointer(
+    Class* dest, PointerSize pointer_size, const Visitor& visitor, MemberOffset member_offset) {
+  void** address =
+      reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(dest) + member_offset.Uint32Value());
+  T old_value = GetFieldPtrWithSize<T, kVerifyFlags>(member_offset, pointer_size);
+  T new_value = visitor(old_value, address);
+  if (old_value != new_value) {
+    dest->SetFieldPtrWithSize</* kTransactionActive */ false,
+                              /* kCheckTransaction */ true,
+                              kVerifyNone>(member_offset, new_value, pointer_size);
+  }
+}
+
+template <VerifyObjectFlags kVerifyFlags, typename Visitor>
 inline void Class::FixupNativePointers(Class* dest,
                                        PointerSize pointer_size,
                                        const Visitor& visitor) {
-  auto dest_address_fn = [dest](MemberOffset offset) {
-    return reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(dest) + offset.Uint32Value());
-  };
   // Update the field arrays.
-  LengthPrefixedArray<ArtField>* const sfields = GetSFieldsPtr();
-  void** sfields_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, sfields_));
-  LengthPrefixedArray<ArtField>* const new_sfields = visitor(sfields, sfields_dest_address);
-  if (sfields != new_sfields) {
-    dest->SetSFieldsPtrUnchecked(new_sfields);
-  }
-  LengthPrefixedArray<ArtField>* const ifields = GetIFieldsPtr();
-  void** ifields_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
-  LengthPrefixedArray<ArtField>* const new_ifields = visitor(ifields, ifields_dest_address);
-  if (ifields != new_ifields) {
-    dest->SetIFieldsPtrUnchecked(new_ifields);
-  }
+  FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>(
+      dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, sfields_));
+  FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>(
+      dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
   // Update method array.
-  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
-  void** methods_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, methods_));
-  LengthPrefixedArray<ArtMethod>* new_methods = visitor(methods, methods_dest_address);
-  if (methods != new_methods) {
-    dest->SetMethodsPtrInternal(new_methods);
-  }
+  FixupNativePointer<LengthPrefixedArray<ArtMethod>*, kVerifyFlags>(
+      dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, methods_));
   // Fix up embedded tables.
   if (!IsTemp<kVerifyNone>() && ShouldHaveEmbeddedVTable<kVerifyNone>()) {
-    for (int32_t i = 0, count = GetEmbeddedVTableLength(); i < count; ++i) {
-      ArtMethod* method = GetEmbeddedVTableEntry(i, pointer_size);
-      void** method_dest_addr = dest_address_fn(EmbeddedVTableEntryOffset(i, pointer_size));
-      ArtMethod* new_method = visitor(method, method_dest_addr);
-      if (method != new_method) {
-        dest->SetEmbeddedVTableEntryUnchecked(i, new_method, pointer_size);
-      }
+    for (int32_t i = 0, count = GetEmbeddedVTableLength<kVerifyFlags>(); i < count; ++i) {
+      FixupNativePointer<ArtMethod*, kVerifyFlags>(
+          dest, pointer_size, visitor, EmbeddedVTableEntryOffset(i, pointer_size));
     }
   }
   if (!IsTemp<kVerifyNone>() && ShouldHaveImt<kVerifyNone>()) {
-    ImTable* imt = GetImt(pointer_size);
-    void** imt_dest_addr = dest_address_fn(ImtPtrOffset(pointer_size));
-    ImTable* new_imt = visitor(imt, imt_dest_addr);
-    dest->SetImt(new_imt, pointer_size);
+    FixupNativePointer<ImTable*, kVerifyFlags>(
+        dest, pointer_size, visitor, ImtPtrOffset(pointer_size));
   }
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 3d434f1..f640d3b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1263,14 +1263,14 @@
   // the corresponding entry in dest if visitor(obj) != obj to prevent dirty memory. Dest should be
   // initialized to a copy of *this to prevent issues. Does not visit the ArtMethod and ArtField
   // roots.
-  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-            ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
-            typename Visitor>
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename Visitor>
   void FixupNativePointers(Class* dest, PointerSize pointer_size, const Visitor& visitor)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods)
+  template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor>
+  void FixupNativePointer(
+      Class* dest, PointerSize pointer_size, const Visitor& visitor, MemberOffset member_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE static ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked(
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index ed0beaf..22ccd20 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -401,12 +401,14 @@
     return GetField32<kVerifyFlags>(NumResolvedTypesOffset());
   }
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   size_t NumResolvedMethods() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return GetField32(NumResolvedMethodsOffset());
+    return GetField32<kVerifyFlags>(NumResolvedMethodsOffset());
   }
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   size_t NumResolvedFields() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return GetField32(NumResolvedFieldsOffset());
+    return GetField32<kVerifyFlags>(NumResolvedFieldsOffset());
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h
index 9e3c9af..3d4c5a7 100644
--- a/runtime/mirror/iftable.h
+++ b/runtime/mirror/iftable.h
@@ -39,9 +39,15 @@
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  PointerArray* GetMethodArrayOrNull(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) {
+    return down_cast<PointerArray*>(
+        Get<kVerifyFlags, kReadBarrierOption>((i * kMax) + kMethodArray));
+  }
+
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   PointerArray* GetMethodArray(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) {
-    auto* method_array = down_cast<PointerArray*>(Get<kVerifyFlags, kReadBarrierOption>(
-        (i * kMax) + kMethodArray));
+    PointerArray* method_array = GetMethodArrayOrNull<kVerifyFlags, kReadBarrierOption>(i);
     DCHECK(method_array != nullptr);
     return method_array;
   }
@@ -49,9 +55,8 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t GetMethodArrayCount(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) {
-    auto* method_array = down_cast<PointerArray*>(
-        Get<kVerifyFlags, kReadBarrierOption>((i * kMax) + kMethodArray));
-    return method_array == nullptr ? 0u : method_array->GetLength();
+    PointerArray* method_array = GetMethodArrayOrNull<kVerifyFlags, kReadBarrierOption>(i);
+    return method_array == nullptr ? 0u : method_array->GetLength<kVerifyFlags>();
   }
 
   void SetMethodArray(int32_t i, ObjPtr<PointerArray> arr) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 1d2f47f..7d101bf 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -67,7 +67,7 @@
 
 template<class T> template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline T* ObjectArray<T>::Get(int32_t i) {
-  if (!CheckIsValidIndex(i)) {
+  if (!CheckIsValidIndex<kVerifyFlags>(i)) {
     DCHECK(Thread::Current()->IsExceptionPending());
     return nullptr;
   }
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index 864e1ea..903826a 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1033,7 +1033,7 @@
                                                                CASMode::kStrong,
                                                                std::memory_order_seq_cst);
       }
-      StoreResult(cas_result, result);
+      StoreResult(static_cast<uint8_t>(cas_result), result);
       break;
     }
     case VarHandle::AccessMode::kWeakCompareAndSet:
@@ -1058,7 +1058,7 @@
             CASMode::kWeak,
             std::memory_order_seq_cst);
       }
-      StoreResult(cas_result, result);
+      StoreResult(static_cast<uint8_t>(cas_result), result);
       break;
     }
     case VarHandle::AccessMode::kCompareAndExchange:
diff --git a/test/089-many-methods/check b/test/089-many-methods/check
index 1f71e8e..e09a291 100755
--- a/test/089-many-methods/check
+++ b/test/089-many-methods/check
@@ -14,5 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-grep Error "$2" > "$2.tmp"
-diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
+EXPECTED_ERROR="Cannot fit requested classes in a single dex"
+if ! grep -q "$EXPECTED_ERROR" "$2"; then
+  exit 1
+else
+  exit 0
+fi
diff --git a/test/089-many-methods/expected.txt b/test/089-many-methods/expected.txt
index bb6ba3c..b75bde4 100644
--- a/test/089-many-methods/expected.txt
+++ b/test/089-many-methods/expected.txt
@@ -1 +1 @@
-Error: Cannot fit requested classes in a single dex file (# fields: 131000 > 65536)
+See the 'check' script for the expectation!
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index e16fa69..b1bc51e 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -26,7 +26,7 @@
   /// CHECK-START: void Main.invokeStaticInlined() builder (after)
   /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
   /// CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
-  /// CHECK-DAG:                           InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
+  /// CHECK-DAG:                           InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>]
 
   /// CHECK-START: void Main.invokeStaticInlined() inliner (after)
   /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
@@ -69,7 +69,7 @@
   /// CHECK-START: void Main.invokeStaticNotInlined() builder (after)
   /// CHECK:         <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
   /// CHECK:         <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
-  /// CHECK:                               InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
+  /// CHECK:                               InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>]
 
   /// CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
   /// CHECK:         <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 746887f..0bceffd 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -41,10 +41,7 @@
     return x;
   }
 
-  /// CHECK-START: int Main.testSimple(int) sharpening (before)
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:RuntimeCall
-
-  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testSimple(int) sharpening (after)
+  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testSimple(int) builder (after)
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
   /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (before)
@@ -59,11 +56,7 @@
     return $noinline$foo(x);
   }
 
-  /// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before)
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:RuntimeCall
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:RuntimeCall
-
-  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testDiamond(boolean, int) sharpening (after)
+  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testDiamond(boolean, int) builder (after)
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
@@ -194,18 +187,12 @@
   }
 
   /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) builder (after)
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:RuntimeCall
-
-  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) sharpening (after)
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BootImageRelRo
   public static String $noinline$toHexString(int value) {
     return Integer.toString(value, 16);
   }
 
   /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) builder (after)
-  /// CHECK:                InvokeStaticOrDirect method_load_kind:RuntimeCall
-
-  /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) sharpening (after)
   /// CHECK:                InvokeStaticOrDirect method_load_kind:BssEntry
 
   /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (before)
diff --git a/test/565-checker-rotate/smali/Main2.smali b/test/565-checker-rotate/smali/Main2.smali
index ca5027e..98eaf11 100644
--- a/test/565-checker-rotate/smali/Main2.smali
+++ b/test/565-checker-rotate/smali/Main2.smali
@@ -16,13 +16,12 @@
 .super Ljava/lang/Object;
 
 ## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
-## CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
 ## CHECK:         <<ArgVal:z\d+>>  ParameterValue
 ## CHECK:         <<ArgDist:i\d+>> ParameterValue
 ## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
 ## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
 ## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
 ## CHECK-DAG:                      Return [<<Result>>]
 
 ## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
@@ -92,14 +91,13 @@
 .end method
 
 ## CHECK-START: int Main2.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
-## CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
 ## CHECK:         <<ArgVal:z\d+>>  ParameterValue
 ## CHECK:         <<ArgDist:i\d+>> ParameterValue
 ## CHECK-DAG:     <<Zero:i\d+>>    IntConstant 0
 ## CHECK-DAG:     <<One:i\d+>>     IntConstant 1
 ## CHECK-DAG:     <<Val:i\d+>>     Phi [<<One>>,<<Zero>>]
-## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
-## CHECK-DAG:                     Return [<<Result>>]
+## CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<Val>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
+## CHECK-DAG:                      Return [<<Result>>]
 
 ## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after)
 ## CHECK:         <<ArgVal:z\d+>>  ParameterValue
diff --git a/test/565-checker-rotate/src-art/Main.java b/test/565-checker-rotate/src-art/Main.java
index b9e1315..f6f281b 100644
--- a/test/565-checker-rotate/src-art/Main.java
+++ b/test/565-checker-rotate/src-art/Main.java
@@ -21,10 +21,9 @@
   private static Class main2;
 
   /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
@@ -42,10 +41,9 @@
   }
 
   /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
@@ -63,10 +61,9 @@
   }
 
   /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
@@ -84,10 +81,9 @@
   }
 
   /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
@@ -105,10 +101,9 @@
   }
 
   /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:LongRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
@@ -126,10 +121,9 @@
   }
 
   /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:b\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
@@ -146,10 +140,9 @@
   }
 
   /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:s\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
@@ -166,10 +159,9 @@
   }
 
   /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:c\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
@@ -186,10 +178,9 @@
   }
 
   /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
@@ -206,10 +197,9 @@
   }
 
   /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:j\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:i\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
+  /// CHECK-DAG:     <<Result:j\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:LongRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
@@ -227,10 +217,9 @@
 
 
   /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
@@ -248,10 +237,9 @@
   }
 
   /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK:         <<ArgVal:i\d+>>  ParameterValue
   /// CHECK:         <<ArgDist:b\d+>> ParameterValue
-  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight
   /// CHECK-DAG:                      Return [<<Result>>]
 
   /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
diff --git a/test/566-checker-signum/smali/Main2.smali b/test/566-checker-signum/smali/Main2.smali
index d99ad86..ec63cf8 100644
--- a/test/566-checker-signum/smali/Main2.smali
+++ b/test/566-checker-signum/smali/Main2.smali
@@ -16,11 +16,10 @@
 .super Ljava/lang/Object;
 
 ## CHECK-START: int Main2.signBoolean(boolean) intrinsics_recognition (after)
-## CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
 ## CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
 ## CHECK-DAG:     <<One:i\d+>>    IntConstant 1
 ## CHECK-DAG:     <<Phi:i\d+>>    Phi [<<One>>,<<Zero>>]
-## CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<Phi>>,<<Method>>] intrinsic:IntegerSignum
+## CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<Phi>>{{(,[ij]\d+)?}}] intrinsic:IntegerSignum
 ## CHECK-DAG:                     Return [<<Result>>]
 
 ## CHECK-START: int Main2.signBoolean(boolean) instruction_simplifier (after)
diff --git a/test/567-checker-compare/smali/Smali.smali b/test/567-checker-compare/smali/Smali.smali
index 8fc39f1..94b1f13 100644
--- a/test/567-checker-compare/smali/Smali.smali
+++ b/test/567-checker-compare/smali/Smali.smali
@@ -16,12 +16,11 @@
 .super Ljava/lang/Object;
 
 ##  CHECK-START: int Smali.compareBooleans(boolean, boolean) intrinsics_recognition (after)
-##  CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
 ##  CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
 ##  CHECK-DAG:     <<One:i\d+>>    IntConstant 1
 ##  CHECK-DAG:     <<PhiX:i\d+>>   Phi [<<One>>,<<Zero>>]
 ##  CHECK-DAG:     <<PhiY:i\d+>>   Phi [<<One>>,<<Zero>>]
-##  CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<PhiX>>,<<PhiY>>,<<Method>>] intrinsic:IntegerCompare
+##  CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<PhiX>>,<<PhiY>>{{(,[ij]\d+)?}}] intrinsic:IntegerCompare
 ##  CHECK-DAG:                     Return [<<Result>>]
 
 ##  CHECK-START: int Smali.compareBooleans(boolean, boolean) instruction_simplifier (after)
diff --git a/test/567-checker-compare/src/Main.java b/test/567-checker-compare/src/Main.java
index abfaf9f..f43ac30 100644
--- a/test/567-checker-compare/src/Main.java
+++ b/test/567-checker-compare/src/Main.java
@@ -22,9 +22,8 @@
 
   /// CHECK-START: void Main.$opt$noinline$testReplaceInputWithItself(int) intrinsics_recognition (after)
   /// CHECK-DAG:     <<ArgX:i\d+>>   ParameterValue
-  /// CHECK-DAG:     <<Method:[ij]\d+>> CurrentMethod
   /// CHECK-DAG:     <<Zero:i\d+>>   IntConstant 0
-  /// CHECK-DAG:     <<Cmp:i\d+>>    InvokeStaticOrDirect [<<ArgX>>,<<Zero>>,<<Method>>] intrinsic:IntegerCompare
+  /// CHECK-DAG:     <<Cmp:i\d+>>    InvokeStaticOrDirect [<<ArgX>>,<<Zero>>{{(,[ij]\d+)?}}] intrinsic:IntegerCompare
   /// CHECK-DAG:                     GreaterThanOrEqual [<<Cmp>>,<<Zero>>]
 
   /// CHECK-START: void Main.$opt$noinline$testReplaceInputWithItself(int) instruction_simplifier (after)
diff --git a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
index f74e88f..bd90fe7 100644
--- a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
+++ b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
@@ -210,14 +210,12 @@
 .end method
 
 ## CHECK-START: int SmaliTests.longToIntOfBoolean() builder (after)
-## CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
 ## CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
-## CHECK-DAG:     <<ZToJ:j\d+>>          InvokeStaticOrDirect [<<Sget>>,<<Method>>]
+## CHECK-DAG:     <<ZToJ:j\d+>>          InvokeStaticOrDirect [<<Sget>>{{(,[ij]\d+)?}}]
 ## CHECK-DAG:     <<JToI:i\d+>>          TypeConversion [<<ZToJ>>]
 ## CHECK-DAG:                            Return [<<JToI>>]
 
 ## CHECK-START: int SmaliTests.longToIntOfBoolean() inliner (after)
-## CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
 ## CHECK-DAG:     <<Zero:i\d+>>          IntConstant 0
 ## CHECK-DAG:     <<One:i\d+>>           IntConstant 1
 ## CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
@@ -228,7 +226,6 @@
 ## CHECK-DAG:                            Return [<<JToI>>]
 
 ## CHECK-START: int SmaliTests.longToIntOfBoolean() select_generator (after)
-## CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
 ## CHECK-DAG:     <<Zero:i\d+>>          IntConstant 0
 ## CHECK-DAG:     <<One:i\d+>>           IntConstant 1
 ## CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
@@ -236,7 +233,6 @@
 ## CHECK-DAG:                            Return [<<Sel>>]
 
 ## CHECK-START: int SmaliTests.longToIntOfBoolean() instruction_simplifier$after_bce (after)
-## CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
 ## CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
 ## CHECK-DAG:                            Return [<<Sget>>]
 .method public static longToIntOfBoolean()I
diff --git a/test/593-checker-boolean-2-integral-conv/src/Main.java b/test/593-checker-boolean-2-integral-conv/src/Main.java
index fdc0919..b085c42 100644
--- a/test/593-checker-boolean-2-integral-conv/src/Main.java
+++ b/test/593-checker-boolean-2-integral-conv/src/Main.java
@@ -100,14 +100,12 @@
   }
 
   /// CHECK-START: int Main.longToIntOfBoolean() builder (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
   /// CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
-  /// CHECK-DAG:     <<ZToJ:j\d+>>          InvokeStaticOrDirect [<<Sget>>,<<Method>>]
+  /// CHECK-DAG:     <<ZToJ:j\d+>>          InvokeStaticOrDirect [<<Sget>>{{(,[ij]\d+)?}}]
   /// CHECK-DAG:     <<JToI:i\d+>>          TypeConversion [<<ZToJ>>]
   /// CHECK-DAG:                            Return [<<JToI>>]
 
   /// CHECK-START: int Main.longToIntOfBoolean() inliner (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
   /// CHECK-DAG:     <<Zero:j\d+>>          LongConstant 0
   /// CHECK-DAG:     <<One:j\d+>>           LongConstant 1
   /// CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
@@ -123,7 +121,6 @@
   /// CHECK-NOT:                            Phi
 
   /// CHECK-START: int Main.longToIntOfBoolean() select_generator (after)
-  /// CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
   /// CHECK-DAG:     <<Zero:j\d+>>          LongConstant 0
   /// CHECK-DAG:     <<One:j\d+>>           LongConstant 1
   /// CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
@@ -135,7 +132,6 @@
   // TODO: Re-enable checks below after simplifier is updated to handle this pattern: b/63064517
 
   // CHECK-START: int Main.longToIntOfBoolean() instruction_simplifier$after_bce (after)
-  // CHECK-DAG:     <<Method:[ij]\d+>>     CurrentMethod
   // CHECK-DAG:     <<Sget:z\d+>>          StaticFieldGet
   // CHECK-DAG:                            Return [<<Sget>>]
 
diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java
index d995923..3d45b86 100644
--- a/test/602-deoptimizeable/src/Main.java
+++ b/test/602-deoptimizeable/src/Main.java
@@ -126,6 +126,9 @@
                     assertIsManaged();
                     map.put(new DummyObject(10), Long.valueOf(100));
                     assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
+                    if (map.get(new DummyObject(10)) == null) {
+                        System.out.println("Expected map to contain DummyObject(10)");
+                    }
                 } catch (Exception e) {
                     e.printStackTrace(System.out);
                 }
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index bd58ae3..de55440 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -17,7 +17,7 @@
 COMPILE_FLAGS=""
 DALVIKVM="dalvikvm32"
 DEBUGGER="n"
-WITH_AGENT=""
+WITH_AGENT=()
 DEBUGGER_AGENT=""
 WRAP_DEBUGGER_AGENT="n"
 DEV_MODE="n"
@@ -232,7 +232,7 @@
     elif [ "x$1" = "x--with-agent" ]; then
         shift
         USE_JVMTI="y"
-        WITH_AGENT="$1"
+        WITH_AGENT+=("$1")
         shift
     elif [ "x$1" = "x--debug-wrap-agent" ]; then
         WRAP_DEBUGGER_AGENT="y"
@@ -454,9 +454,9 @@
   DEBUGGER_OPTS="-agentpath:${AGENTPATH}=transport=dt_socket,address=$PORT,server=y,suspend=y"
 fi
 
-if [ "x$WITH_AGENT" != "x" ]; then
-  FLAGS="${FLAGS} -agentpath:${WITH_AGENT}"
-fi
+for agent in "${WITH_AGENT[@]}"; do
+  FLAGS="${FLAGS} -agentpath:${agent}"
+done
 
 if [ "$USE_JVMTI" = "y" ]; then
   if [ "$USE_JVM" = "n" ]; then
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 426bbaf..f0b88e9 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -13,9 +13,7 @@
     },
     {
         "tests": "080-oom-fragmentation",
-        "description": ["Disable 080-oom-fragmentation for GSS GC due to lack of",
-		        "support for allocations larger than 32MB."],
-	"env_vars": {"ART_DEFAULT_GC_TYPE": "GSS"},
+        "description": "Disable 080-oom-fragmentation due to flakes.",
         "bug": "http://b/33795328"
     },
     {
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 84490bf..ad72945 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -1,23 +1,23 @@
 target_config = {
 
-# Configuration syntax:
-#
-#   Required keys: (Use one or more of these)
-#    * golem - specify a golem machine-type to build, e.g. android-armv8
-#              (uses art/tools/golem/build-target.sh)
-#    * make - specify a make target to build, e.g. build-art-host
-#    * run-test - runs the tests in art/test/ directory with testrunner.py,
-#                 specify a list of arguments to pass to testrunner.py
-#
-#   Optional keys: (Use any of these)
-#    * env - Add additional environment variable to the current environment.
-#
-# *** IMPORTANT ***:
-#    This configuration is used by the android build server. Targets must not be renamed
-#    or removed.
-#
+    # Configuration syntax:
+    #
+    #   Required keys: (Use one or more of these)
+    #    * golem - specify a golem machine-type to build, e.g. android-armv8
+    #              (uses art/tools/golem/build-target.sh)
+    #    * make - specify a make target to build, e.g. build-art-host
+    #    * run-test - runs the tests in art/test/ directory with testrunner.py,
+    #                 specify a list of arguments to pass to testrunner.py
+    #
+    #   Optional keys: (Use any of these)
+    #    * env - Add additional environment variable to the current environment.
+    #
+    # *** IMPORTANT ***:
+    #    This configuration is used by the android build server. Targets must not be renamed
+    #    or removed.
+    #
 
-##########################################
+    ##########################################
 
     # General ART configurations.
     # Calls make and testrunner both.
@@ -56,27 +56,26 @@
     },
     'art-gcstress-gcverify': {
         # Do not exercise '--interpreter', '--optimizing', nor '--jit' in this
-        # configuration, as they are covered by the 'art-interpreter-gcstress',
-        # 'art-optimizing-gcstress' and 'art-jit-gcstress' configurations below.
+        # configuration, as they are covered by the
+        # 'art-interpreter-gcstress-gcverify',
+        # 'art-optimizing-gcstress-gcverify' and 'art-jit-gcstress-gcverify'
+        # configurations below.
         'run-test': ['--interp-ac',
                      '--speed-profile',
                      '--gcstress',
                      '--gcverify']
     },
-    # Rename this configuration as 'art-interpreter-gcstress-gcverify' (b/62611253).
-    'art-interpreter-gcstress' : {
+    'art-interpreter-gcstress-gcverify' : {
         'run-test' : ['--interpreter',
                       '--gcstress',
                       '--gcverify']
     },
-    # Rename this configuration as 'art-optimizing-gcstress-gcverify' (b/62611253).
-    'art-optimizing-gcstress' : {
+    'art-optimizing-gcstress-gcverify' : {
         'run-test' : ['--optimizing',
                       '--gcstress',
                       '--gcverify']
     },
-    # Rename this configuration as 'art-jit-gcstress-gcverify' (b/62611253).
-    'art-jit-gcstress' : {
+    'art-jit-gcstress-gcverify' : {
         'run-test' : ['--jit',
                       '--gcstress',
                       '--gcverify']
@@ -86,22 +85,9 @@
                       '--gcstress',
                       '--runtime-option=-Xjitthreshold:0']
     },
-    # TODO: Rename or repurpose this configuration as
-    # 'art-read-barrier-heap-poisoning' (b/62611253).
-    'art-read-barrier' : {
+    'art-read-barrier-heap-poisoning' : {
         'run-test': ['--interpreter',
-                  '--optimizing'],
-        'env' : {
-            'ART_HEAP_POISONING' : 'true'
-        }
-    },
-    # TODO: Remove or disable this configuration, as it is now covered
-    # by 'art-interpreter-gcstress' and 'art-optimizing-gcstress' --
-    # except for heap poisoning, but that's fine (b/62611253).
-    'art-read-barrier-gcstress' : {
-        'run-test' : ['--interpreter',
-                      '--optimizing',
-                      '--gcstress'],
+                     '--optimizing'],
         'env' : {
             'ART_HEAP_POISONING' : 'true'
         }
@@ -122,6 +108,9 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
+    # TODO: Consider removing this configuration when it is no longer used by
+    # any continuous testing target (b/62611253), as the SS collector overlaps
+    # with the CC collector, since both move objects.
     'art-ss-gc' : {
         'run-test' : ['--interpreter',
                       '--optimizing',
@@ -131,6 +120,7 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
+    # TODO: Remove this configuration (b/62611253) when the GSS collector is removed (b/73295078).
     'art-gss-gc' : {
         'run-test' : ['--interpreter',
                       '--optimizing',
@@ -140,6 +130,9 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
+    # TODO: Consider removing this configuration when it is no longer used by
+    # any continuous testing target (b/62611253), as the SS collector overlaps
+    # with the CC collector, since both move objects.
     'art-ss-gc-tlab' : {
         'run-test' : ['--interpreter',
                       '--optimizing',
@@ -150,6 +143,7 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
+    # TODO: Remove this configuration (b/62611253) when the GSS collector is removed (b/73295078).
     'art-gss-gc-tlab' : {
         'run-test' : ['--interpreter',
                       '--optimizing',
@@ -180,12 +174,6 @@
         'run-test' : ['--interpreter',
                       '--no-image']
     },
-    'art-relocate-no-patchoat' : {
-        'run-test' : ['--relocate-npatchoat']
-    },
-    'art-no-dex2oat' : {
-        # Deprecated configuration.
-    },
     'art-heap-poisoning' : {
         'run-test' : ['--interpreter',
                       '--optimizing',
@@ -226,6 +214,9 @@
             'ART_HEAP_POISONING' : 'true'
         }
     },
+    # TODO: Consider removing this configuration when it is no longer used by
+    # any continuous testing target (b/62611253), as the SS collector overlaps
+    # with the CC collector, since both move objects.
     'art-gtest-ss-gc': {
         'make' :  'test-art-host-gtest',
         'env': {
@@ -235,6 +226,7 @@
             'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'none'
         }
     },
+    # TODO: Remove this configuration (b/62611253) when the GSS collector is removed (b/73295078).
     'art-gtest-gss-gc': {
         'make' :  'test-art-host-gtest',
         'env' : {
@@ -242,6 +234,9 @@
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
+    # TODO: Consider removing this configuration when it is no longer used by
+    # any continuous testing target (b/62611253), as the SS collector overlaps
+    # with the CC collector, since both move objects.
     'art-gtest-ss-gc-tlab': {
         'make' :  'test-art-host-gtest',
         'env': {
@@ -250,6 +245,7 @@
             'ART_USE_READ_BARRIER' : 'false',
         }
     },
+    # TODO: Remove this configuration (b/62611253) when the GSS collector is removed (b/73295078).
     'art-gtest-gss-gc-tlab': {
         'make' :  'test-art-host-gtest',
         'env': {
@@ -273,10 +269,10 @@
         }
     },
 
-   # ASAN (host) configurations.
+    # ASAN (host) configurations.
 
-   # These configurations need detect_leaks=0 to work in non-setup environments like build bots,
-   # as our build tools leak. b/37751350
+    # These configurations need detect_leaks=0 to work in non-setup environments like build bots,
+    # as our build tools leak. b/37751350
 
     'art-gtest-asan': {
         'make' : 'test-art-host-gtest',
@@ -306,11 +302,11 @@
         }
     },
 
-   # ART Golem build targets used by go/lem (continuous ART benchmarking),
-   # (art-opt-cc is used by default since it mimics the default preopt config),
-   #
-   # calls golem/build-target.sh which builds a golem tarball of the target name,
-   #     e.g. 'golem: android-armv7' produces an 'android-armv7.tar.gz' upon success.
+    # ART Golem build targets used by go/lem (continuous ART benchmarking),
+    # (art-opt-cc is used by default since it mimics the default preopt config),
+    #
+    # calls golem/build-target.sh which builds a golem tarball of the target name,
+    #     e.g. 'golem: android-armv7' produces an 'android-armv7.tar.gz' upon success.
 
     'art-golem-android-armv7': {
         'golem' : 'android-armv7'
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 7aa994a..c82b314 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -73,6 +73,7 @@
     method public com.android.ahat.heapdump.AhatInstance getAssociatedBitmapInstance();
     method public com.android.ahat.heapdump.AhatClassObj getAssociatedClassForOverhead();
     method public com.android.ahat.heapdump.AhatInstance getBaseline();
+    method public java.lang.String getBinderProxyInterfaceName();
     method public java.lang.String getClassName();
     method public com.android.ahat.heapdump.AhatClassObj getClassObj();
     method public java.lang.String getDexCacheLocation(int);
diff --git a/tools/ahat/src/main/com/android/ahat/Summarizer.java b/tools/ahat/src/main/com/android/ahat/Summarizer.java
index ab88c04..877ecf4 100644
--- a/tools/ahat/src/main/com/android/ahat/Summarizer.java
+++ b/tools/ahat/src/main/com/android/ahat/Summarizer.java
@@ -112,6 +112,13 @@
       formatted.append(" overhead for ");
       formatted.append(summarize(cls));
     }
+
+    // Annotate BinderProxy with its interface name.
+    String binderInterface = inst.getBinderProxyInterfaceName();
+    if (binderInterface != null) {
+        formatted.appendFormat(" for %s", binderInterface);
+    }
+
     return formatted;
   }
 
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
index 0511798..141bdd9 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
@@ -145,6 +145,21 @@
     return null;
   }
 
+  @Override public String getBinderProxyInterfaceName() {
+    if (isInstanceOfClass("android.os.BinderProxy")) {
+      for (AhatInstance inst : getReverseReferences()) {
+        String className = inst.getClassName();
+        if (className.endsWith("$Stub$Proxy")) {
+          Value value = inst.getField("mRemote");
+          if (value != null && value.asAhatInstance() == this) {
+            return className.substring(0, className.lastIndexOf("$Stub$Proxy"));
+          }
+        }
+      }
+    }
+    return null;
+  }
+
   @Override public AhatInstance getAssociatedBitmapInstance() {
     return getBitmapInfo() == null ? null : this;
   }
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index c85a057..3aae11e 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -490,6 +490,17 @@
   }
 
   /**
+   * Returns the name of the Binder proxy interface associated with this object. Only applies to
+   * instances of android.os.BinderProxy. If this is an instance of BinderProxy,
+   * returns the fully qualified binder interface name, otherwise returns null.
+   *
+   * @return the name of the binder interface associated with this object
+   */
+  public String getBinderProxyInterfaceName() {
+    return null;
+  }
+
+  /**
    * Returns the android.graphics.Bitmap instance associated with this object.
    * Instances of android.graphics.Bitmap return themselves. If this is a
    * byte[] array containing pixel data for an instance of
diff --git a/tools/ahat/src/test-dump/DumpedStuff.java b/tools/ahat/src/test-dump/DumpedStuff.java
index 804a3a3..50b8878 100644
--- a/tools/ahat/src/test-dump/DumpedStuff.java
+++ b/tools/ahat/src/test-dump/DumpedStuff.java
@@ -124,6 +124,35 @@
     }
   }
 
+  private static class IDumpedManager {
+    public static class Stub {
+      public static class Proxy {
+        android.os.IBinder mRemote;
+        Proxy(android.os.IBinder binderProxy) {
+          mRemote = binderProxy;
+        }
+      }
+    }
+  }
+
+  private static class IBinderInterfaceImpostor {
+    public static class Stub {
+      public static class Proxy {
+        android.os.IBinder mFakeRemote = new android.os.BinderProxy();
+        Proxy(android.os.IBinder binderProxy) {
+          mFakeRemote = binderProxy;
+        }
+      }
+    }
+  }
+
+  private static class BinderProxyCarrier {
+    android.os.IBinder mRemote;
+    BinderProxyCarrier(android.os.IBinder binderProxy) {
+      mRemote = binderProxy;
+    }
+  }
+
   public String basicString = "hello, world";
   public String nonAscii = "Sigma (Æ©) is not ASCII";
   public String embeddedZero = "embedded\0...";  // Non-ASCII for string compression purposes.
@@ -158,6 +187,12 @@
   public int[] modifiedArray;
   public Object objectAllocatedAtKnownSite;
   public Object objectAllocatedAtKnownSubSite;
+  public android.os.IBinder correctBinderProxy = new android.os.BinderProxy();
+  public android.os.IBinder imposedBinderProxy = new android.os.BinderProxy();
+  public android.os.IBinder carriedBinderProxy = new android.os.BinderProxy();
+  Object correctBinderProxyObject = new IDumpedManager.Stub.Proxy(correctBinderProxy);
+  Object impostorBinderProxyObject = new IBinderInterfaceImpostor.Stub.Proxy(imposedBinderProxy);
+  Object carrierBinderProxyObject = new BinderProxyCarrier(carriedBinderProxy);
 
   // Allocate those objects that we need to not be GC'd before taking the heap
   // dump.
diff --git a/tools/ahat/src/test-dump/android/os/BinderProxy.java b/tools/ahat/src/test-dump/android/os/BinderProxy.java
new file mode 100644
index 0000000..5f35c61
--- /dev/null
+++ b/tools/ahat/src/test-dump/android/os/BinderProxy.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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 android.os;
+
+/** Fake android.os.BinderProxy class that does absolutely nothing. */
+public class BinderProxy implements IBinder {}
diff --git a/tools/ahat/src/test-dump/android/os/IBinder.java b/tools/ahat/src/test-dump/android/os/IBinder.java
new file mode 100644
index 0000000..6f01468
--- /dev/null
+++ b/tools/ahat/src/test-dump/android/os/IBinder.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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 android.os;
+
+/** Fake android.os.IBinder that means nothing. */
+public interface IBinder {}
diff --git a/tools/ahat/src/test/com/android/ahat/InstanceTest.java b/tools/ahat/src/test/com/android/ahat/InstanceTest.java
index 196eb1e..57aa31f 100644
--- a/tools/ahat/src/test/com/android/ahat/InstanceTest.java
+++ b/tools/ahat/src/test/com/android/ahat/InstanceTest.java
@@ -549,4 +549,18 @@
     // Other kinds of objects should not have associated classes for overhead.
     assertNull(cls.getAssociatedClassForOverhead());
   }
+
+  @Test
+  public void binderProxy() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatInstance correctObj = dump.getDumpedAhatInstance("correctBinderProxy");
+    assertEquals("DumpedStuff$IDumpedManager", correctObj.getBinderProxyInterfaceName());
+
+    AhatInstance imposedObj = dump.getDumpedAhatInstance("imposedBinderProxy");
+    assertNull(imposedObj.getBinderProxyInterfaceName());
+
+    AhatInstance carriedObj = dump.getDumpedAhatInstance("carriedBinderProxy");
+    assertNull(carriedObj.getBinderProxyInterfaceName());
+  }
 }
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 3ef78d5..4c9fd96 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -216,16 +216,6 @@
   names: ["libcore.javax.crypto.spec.AlgorithmParametersTestGCM#testEncoding"]
 },
 {
-  description: "Tests fail because mockito can not read android.os.Build$VERSION",
-  result: EXEC_FAILED,
-  bug: 111704422,
-  names: ["libcore.java.lang.ThreadTest#testUncaughtExceptionPreHandler_calledBeforeDefaultHandler",
-          "libcore.java.lang.ThreadTest#testUncaughtExceptionPreHandler_noDefaultHandler",
-          "libcore.javax.crypto.CipherInputStreamTest#testCloseTwice",
-          "libcore.libcore.io.BlockGuardOsTest#test_android_getaddrinfo_networkPolicy",
-          "libcore.libcore.io.BlockGuardOsTest#test_checkNewMethodsInPosix"]
-},
-{
   description: "fdsan doesn't exist on the host",
   result: EXEC_FAILED,
   modes: [host],
@@ -233,6 +223,8 @@
   names: ["libcore.libcore.io.FdsanTest#testFileInputStream",
           "libcore.libcore.io.FdsanTest#testFileOutputStream",
           "libcore.libcore.io.FdsanTest#testRandomAccessFile",
-          "libcore.libcore.io.FdsanTest#testParcelFileDescriptor"]
+          "libcore.libcore.io.FdsanTest#testParcelFileDescriptor",
+          "libcore.libcore.io.FdsanTest#testDatagramSocket",
+          "libcore.libcore.io.FdsanTest#testSocket"]
 }
 ]
diff --git a/tools/ti-fast/README.md b/tools/ti-fast/README.md
index bc46882..a0a7dd7 100644
--- a/tools/ti-fast/README.md
+++ b/tools/ti-fast/README.md
@@ -21,6 +21,10 @@
   called. This behavior is static. The no-log methods have no branches and just
   immediately return.
 
+* If 'all' is one of the arguments all events the current runtime is capable of
+  providing will be listened for and all other arguments (excepting 'log') will
+  be ignored.
+
 * The event-names are the same names as are used in the jvmtiEventCallbacks
   struct.
 
diff --git a/tools/ti-fast/tifast.cc b/tools/ti-fast/tifast.cc
index b147add..85c433b 100644
--- a/tools/ti-fast/tifast.cc
+++ b/tools/ti-fast/tifast.cc
@@ -36,6 +36,13 @@
 // env.
 static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
 
+template <typename ...Args> static void Unused(Args... args ATTRIBUTE_UNUSED) {}
+
+// jthread is a typedef of jobject so we use this to allow the templates to distinguish them.
+struct jthreadContainer { jthread thread; };
+// jlocation is a typedef of jlong so use this to distinguish the less common jlong.
+struct jlongContainer { jlong val; };
+
 static void AddCapsForEvent(jvmtiEvent event, jvmtiCapabilities* caps) {
   switch (event) {
 #define DO_CASE(name, cap_name) \
@@ -63,59 +70,520 @@
 }
 
 // Setup for all supported events. Give a macro with fun(name, event_num, args)
-#define FOR_ALL_SUPPORTED_EVENTS(fun) \
-    fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation)) \
-    fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv*, JNIEnv*, jthread, jmethodID)) \
-    fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jboolean, jvalue)) \
-    fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, void*, void**)) \
-    fun(Exception, EVENT(EXCEPTION), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject, jmethodID, jlocation)) \
-    fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject)) \
-    fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv*, JNIEnv*, jthread)) \
-    fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv*, JNIEnv*, jthread)) \
-    fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \
-    fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \
-    fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv*, JNIEnv*, jclass, jobject, const char*, jobject, jint, const unsigned char*, jint*, unsigned char**)) \
-    fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv*, jmethodID, jint, const void*, jint, const jvmtiAddrLocationMap*, const void*)) \
-    fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv*, jmethodID, const void*)) \
-    fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv*, const char*, const void*, jint)) \
-    fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv*)) \
-    fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \
-    fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \
-    fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv*, JNIEnv*, jthread, jobject, jlong)) \
-    fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv*, JNIEnv*, jthread, jobject, jboolean)) \
-    fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv*, JNIEnv*, jint, const void*, const char*)) \
-    fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv*, JNIEnv*, jthread, jobject, jclass, jlong)) \
-    fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv*)) \
-    fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv*))
+#define FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \
+    fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc)) \
+    fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth), (jvmti, jni, jthreadContainer{.thread = thread}, meth)) \
+    fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jboolean jb, jvalue jv), (jvmti, jni, jthreadContainer{.thread = thread}, meth, jb, jv)) \
+    fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, void* v1, void** v2), (jvmti, jni, jthreadContainer{.thread = thread}, meth, v1, v2)) \
+    fun(Exception, EVENT(EXCEPTION), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth1, jlocation loc1, jobject obj, jmethodID meth2, jlocation loc2), (jvmti, jni, jthreadContainer{.thread = thread}, meth1, loc1, obj, meth2, loc2)) \
+    fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc, obj)) \
+    fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
+    fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \
+    fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass) ) \
+    fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass)) \
+    fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, jobject obj1, const char* c1, jobject obj2, jint i1, const unsigned char* c2, jint* ip1, unsigned char** cp1), (jvmti, jni, klass, obj1, c1, obj2, i1, c2, ip1, cp1)) \
+    fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
+    fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \
+    fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, jlongContainer{.val = l1})) \
+    fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jboolean b1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, b1)) \
+    fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv* jvmti, JNIEnv* jni, jint i1, const void* cv, const char* cc), (jvmti, jni, i1, cv, cc)) \
+    fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jclass klass, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, klass, jlongContainer{.val = l1})) \
 
-#define GENERATE_EMPTY_FUNCTION(name, number, args) \
-    static void JNICALL empty ## name  args { }
+#define FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun) \
+    fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv* jvmti, jmethodID meth, jint i1, const void* cv1, jint i2, const jvmtiAddrLocationMap* alm, const void* cv2), (jvmti, meth, i1, cv1, i2, alm, cv2)) \
+    fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv* jvmti, jmethodID meth, const void* cv1), (jvmti, meth, cv1)) \
+    fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv* jvmti, const char* cc, const void* cv, jint i1), (jvmti, cc, cv, i1)) \
+    fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv* jvmti), (jvmti)) \
+    fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv* jvmti), (jvmti)) \
+    fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv* jvmti), (jvmti))
+
+#define FOR_ALL_SUPPORTED_EVENTS(fun) \
+    FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \
+    FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun)
+
+static const jvmtiEvent kAllEvents[] = {
+#define GET_EVENT(a, event, b, c) event,
+FOR_ALL_SUPPORTED_EVENTS(GET_EVENT)
+#undef GET_EVENT
+};
+
+#define GENERATE_EMPTY_FUNCTION(name, number, args, argnames) \
+    static void JNICALL empty ## name  args { Unused argnames ; }
 FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION)
 #undef GENERATE_EMPTY_FUNCTION
 
 static jvmtiEventCallbacks kEmptyCallbacks {
-#define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args) \
+#define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args, argnames) \
     .name = empty ## name,
   FOR_ALL_SUPPORTED_EVENTS(CREATE_EMPTY_EVENT_CALLBACKS)
 #undef CREATE_EMPTY_EVENT_CALLBACKS
 };
 
-#define GENERATE_LOG_FUNCTION(name, number, args) \
-    static void JNICALL log ## name  args { \
-      LOG(INFO) << "Got event " << #name ; \
+static void DeleteLocalRef(JNIEnv* env, jobject obj) {
+  if (obj != nullptr && env != nullptr) {
+    env->DeleteLocalRef(obj);
+  }
+}
+
+class ScopedThreadInfo {
+ public:
+  ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
+      : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
+    if (thread == nullptr) {
+      info_.name = const_cast<char*>("<NULLPTR>");
+    } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
+      info_.name = const_cast<char*>("<UNKNOWN THREAD>");
+    } else {
+      free_name_ = true;
     }
-FOR_ALL_SUPPORTED_EVENTS(GENERATE_LOG_FUNCTION)
+  }
+
+  ~ScopedThreadInfo() {
+    if (free_name_) {
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
+    }
+    DeleteLocalRef(env_, info_.thread_group);
+    DeleteLocalRef(env_, info_.context_class_loader);
+  }
+
+  const char* GetName() const {
+    return info_.name;
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  JNIEnv* env_;
+  bool free_name_;
+  jvmtiThreadInfo info_{};
+};
+
+class ScopedClassInfo {
+ public:
+  ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c) : jvmtienv_(jvmtienv), class_(c) {}
+
+  ~ScopedClassInfo() {
+    if (class_ != nullptr) {
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
+    }
+  }
+
+  bool Init(bool get_generic = true) {
+    if (class_ == nullptr) {
+      name_ = const_cast<char*>("<NONE>");
+      generic_ = const_cast<char*>("<NONE>");
+      return true;
+    } else {
+      jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
+      jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
+      char** gen_ptr = &generic_;
+      if (!get_generic) {
+        generic_ = nullptr;
+        gen_ptr = nullptr;
+      }
+      return jvmtienv_->GetClassSignature(class_, &name_, gen_ptr) == JVMTI_ERROR_NONE &&
+          ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
+          ret1 != JVMTI_ERROR_INVALID_CLASS &&
+          ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
+          ret2 != JVMTI_ERROR_INVALID_CLASS;
+    }
+  }
+
+  jclass GetClass() const {
+    return class_;
+  }
+
+  const char* GetName() const {
+    return name_;
+  }
+
+  const char* GetGeneric() const {
+    return generic_;
+  }
+
+  const char* GetSourceDebugExtension() const {
+    if (debug_ext_ == nullptr) {
+      return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
+    } else {
+      return debug_ext_;
+    }
+  }
+  const char* GetSourceFileName() const {
+    if (file_ == nullptr) {
+      return "<UNKNOWN_FILE>";
+    } else {
+      return file_;
+    }
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  jclass class_;
+  char* name_ = nullptr;
+  char* generic_ = nullptr;
+  char* file_ = nullptr;
+  char* debug_ext_ = nullptr;
+
+  friend std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& m);
+};
+
+class ScopedMethodInfo {
+ public:
+  ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
+      : jvmtienv_(jvmtienv), env_(env), method_(m) {}
+
+  ~ScopedMethodInfo() {
+    DeleteLocalRef(env_, declaring_class_);
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+  }
+
+  bool Init(bool get_generic = true) {
+    if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
+      return false;
+    }
+    class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
+    jint nlines;
+    jvmtiLineNumberEntry* lines;
+    jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
+    if (err == JVMTI_ERROR_NONE) {
+      if (nlines > 0) {
+        first_line_ = lines[0].line_number;
+      }
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
+               err != JVMTI_ERROR_NATIVE_METHOD) {
+      return false;
+    }
+    return class_info_->Init(get_generic) &&
+        (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
+  }
+
+  const ScopedClassInfo& GetDeclaringClassInfo() const {
+    return *class_info_;
+  }
+
+  jclass GetDeclaringClass() const {
+    return declaring_class_;
+  }
+
+  const char* GetName() const {
+    return name_;
+  }
+
+  const char* GetSignature() const {
+    return signature_;
+  }
+
+  const char* GetGeneric() const {
+    return generic_;
+  }
+
+  jint GetFirstLine() const {
+    return first_line_;
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  JNIEnv* env_;
+  jmethodID method_;
+  jclass declaring_class_ = nullptr;
+  std::unique_ptr<ScopedClassInfo> class_info_;
+  char* name_ = nullptr;
+  char* signature_ = nullptr;
+  char* generic_ = nullptr;
+  jint first_line_ = -1;
+
+  friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
+};
+
+std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& c) {
+  const char* generic = c.GetGeneric();
+  if (generic != nullptr) {
+    return os << c.GetName() << "<" << generic << ">" << " file: " << c.GetSourceFileName();
+  } else {
+    return os << c.GetName() << " file: " << c.GetSourceFileName();
+  }
+}
+
+std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
+  return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
+            << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
+            << m.GetFirstLine() << ")";
+}
+
+
+class LogPrinter {
+ public:
+  explicit LogPrinter(jvmtiEvent event) : event_(event) {}
+
+  template <typename ...Args> void PrintRestNoJNI(jvmtiEnv* jvmti, Args... args) {
+    PrintRest(jvmti, static_cast<JNIEnv*>(nullptr), args...);
+  }
+
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, JNIEnv* env, Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jlongContainer l,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jthreadContainer thr,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jboolean i,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jint i,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jclass klass,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jmethodID meth,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jlocation loc,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jint* ip,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             const void* loc,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             void* loc,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             void** loc,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             unsigned char** v,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             const unsigned char* v,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             const char* v,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             const jvmtiAddrLocationMap* v,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jvalue v,
+                                             Args... args);
+  template <typename ...Args> void PrintRest(jvmtiEnv* jvmti,
+                                             JNIEnv* env,
+                                             jobject v,
+                                             Args... args);
+
+  std::string GetResult() {
+    std::string out_str = stream.str();
+    return start_args + out_str;
+  }
+
+ private:
+  jvmtiEvent event_;
+  std::string start_args;
+  std::ostringstream stream;
+};
+
+// Base case
+template<> void LogPrinter::PrintRest(jvmtiEnv* jvmti ATTRIBUTE_UNUSED, JNIEnv* jni) {
+  if (jni == nullptr) {
+    start_args = "jvmtiEnv*";
+  } else {
+    start_args = "jvmtiEnv*, JNIEnv*";
+  }
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti,
+                           JNIEnv* jni,
+                           const jvmtiAddrLocationMap* v,
+                           Args... args) {
+  if (v != nullptr) {
+    stream << ", const jvmtiAddrLocationMap*[start_address: "
+           << v->start_address << ", location: " << v->location << "]";
+  } else {
+    stream << ", const jvmtiAddrLocationMap*[nullptr]";
+  }
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint* v, Args... args) {
+  stream << ", jint*[" << static_cast<const void*>(v) << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const void* v, Args... args) {
+  stream << ", const void*[" << v << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, unsigned char** v, Args... args) {
+  stream << ", unsigned char**[" << static_cast<const void*>(v) << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const unsigned char* v, Args... args) {
+  stream << ", const unsigned char*[" << static_cast<const void*>(v) << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const char* v, Args... args) {
+  stream << ", const char*[" << v << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jvalue v ATTRIBUTE_UNUSED, Args... args) {
+  stream << ", jvalue[<UNION>]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void** v, Args... args) {
+  stream << ", void**[" << v << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void* v, Args... args) {
+  stream << ", void*[" << v << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlongContainer l, Args... args) {
+  stream << ", jlong[" << l.val << ", hex: 0x" << std::hex << l.val << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlocation l, Args... args) {
+  stream << ", jlocation[" << l << ", hex: 0x" << std::hex << l << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jboolean b, Args... args) {
+  stream << ", jboolean[" << (b ? "true" : "false") << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint i, Args... args) {
+  stream << ", jint[" << i << ", hex: 0x" << std::hex << i << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jobject obj, Args... args) {
+  if (obj == nullptr) {
+    stream << ", jobject[nullptr]";
+  } else {
+    jni->PushLocalFrame(1);
+    jclass klass = jni->GetObjectClass(obj);
+    ScopedClassInfo sci(jvmti, klass);
+    if (sci.Init(event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
+      stream << ", jobject[type: " << sci << "]";
+    } else {
+      stream << ", jobject[type: TYPE UNKNOWN]";
+    }
+    jni->PopLocalFrame(nullptr);
+  }
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jthreadContainer thr, Args... args) {
+  ScopedThreadInfo sti(jvmti, jni, thr.thread);
+  stream << ", jthread[" << sti.GetName() << "]";
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, Args... args) {
+  ScopedClassInfo sci(jvmti, klass);
+  if (sci.Init(/*get_generic*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
+    stream << ", jclass[" << sci << "]";
+  } else {
+    stream << ", jclass[TYPE UNKNOWN]";
+  }
+  PrintRest(jvmti, jni, args...);
+}
+
+template<typename ...Args>
+void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jmethodID meth, Args... args) {
+  ScopedMethodInfo smi(jvmti, jni, meth);
+  if (smi.Init()) {
+    stream << ", jmethodID[" << smi << "]";
+  } else {
+    stream << ", jmethodID[METHOD UNKNOWN]";
+  }
+  PrintRest(jvmti, jni, args...);
+}
+
+#define GENERATE_LOG_FUNCTION_JNI(name, event, args, argnames) \
+    static void JNICALL log ## name  args { \
+      LogPrinter printer(event); \
+      printer.PrintRest argnames; \
+      LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
+    } \
+
+#define GENERATE_LOG_FUNCTION_NO_JNI(name, event, args, argnames) \
+    static void JNICALL log ## name  args { \
+      LogPrinter printer(event); \
+      printer.PrintRestNoJNI argnames; \
+      LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \
+    } \
+
+FOR_ALL_SUPPORTED_JNI_EVENTS(GENERATE_LOG_FUNCTION_JNI)
+FOR_ALL_SUPPORTED_NO_JNI_EVENTS(GENERATE_LOG_FUNCTION_NO_JNI)
 #undef GENERATE_LOG_FUNCTION
 
 static jvmtiEventCallbacks kLogCallbacks {
-#define CREATE_LOG_EVENT_CALLBACK(name, num, args) \
+#define CREATE_LOG_EVENT_CALLBACK(name, num, args, argnames) \
     .name = log ## name,
   FOR_ALL_SUPPORTED_EVENTS(CREATE_LOG_EVENT_CALLBACK)
 #undef CREATE_LOG_EVENT_CALLBACK
 };
 
+static std::string EventToName(jvmtiEvent desired_event) {
+#define CHECK_NAME(name, event, args, argnames) \
+  if (desired_event == event) { \
+    return #name; \
+  }
+  FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME);
+  LOG(FATAL) << "Unknown event " << desired_event;
+  __builtin_unreachable();
+#undef CHECK_NAME
+}
 static jvmtiEvent NameToEvent(const std::string& desired_name) {
-#define CHECK_NAME(name, event, args) \
+#define CHECK_NAME(name, event, args, argnames) \
   if (desired_name == #name) { \
     return event; \
   }
@@ -125,14 +593,46 @@
 #undef CHECK_NAME
 }
 
+#undef FOR_ALL_SUPPORTED_JNI_EVENTS
+#undef FOR_ALL_SUPPORTED_NO_JNI_EVENTS
 #undef FOR_ALL_SUPPORTED_EVENTS
-static std::vector<jvmtiEvent> GetRequestedEventList(const std::string& args) {
+
+static std::vector<jvmtiEvent> GetAllAvailableEvents(jvmtiEnv* jvmti) {
+  std::vector<jvmtiEvent> out;
+  jvmtiCapabilities caps{};
+  jvmti->GetPotentialCapabilities(&caps);
+  uint8_t caps_bytes[sizeof(caps)];
+  memcpy(caps_bytes, &caps, sizeof(caps));
+  for (jvmtiEvent e : kAllEvents) {
+    jvmtiCapabilities req{};
+    AddCapsForEvent(e, &req);
+    uint8_t req_bytes[sizeof(req)];
+    memcpy(req_bytes, &req, sizeof(req));
+    bool good = true;
+    for (size_t i = 0; i < sizeof(caps); i++) {
+      if ((req_bytes[i] & caps_bytes[i]) != req_bytes[i]) {
+        good = false;
+        break;
+      }
+    }
+    if (good) {
+      out.push_back(e);
+    } else {
+      LOG(WARNING) << "Unable to get capabilities for event " << EventToName(e);
+    }
+  }
+  return out;
+}
+
+static std::vector<jvmtiEvent> GetRequestedEventList(jvmtiEnv* jvmti, const std::string& args) {
   std::vector<jvmtiEvent> res;
   std::stringstream args_stream(args);
   std::string item;
   while (std::getline(args_stream, item, ',')) {
     if (item == "") {
       continue;
+    } else if (item == "all") {
+      return GetAllAvailableEvents(jvmti);
     }
     res.push_back(NameToEvent(item));
   }
@@ -168,12 +668,17 @@
     args = args.substr(3);
   }
 
-  std::vector<jvmtiEvent> events = GetRequestedEventList(args);
+  std::vector<jvmtiEvent> events = GetRequestedEventList(jvmti, args);
 
   jvmtiCapabilities caps{};
   for (jvmtiEvent e : events) {
     AddCapsForEvent(e, &caps);
   }
+  if (is_log) {
+    caps.can_get_line_numbers = 1;
+    caps.can_get_source_file_name = 1;
+    caps.can_get_source_debug_extension = 1;
+  }
   error = jvmti->AddCapabilities(&caps);
   if (error != JVMTI_ERROR_NONE) {
     LOG(ERROR) << "Unable to set caps";
diff --git a/tools/veridex/appcompat.sh b/tools/veridex/appcompat.sh
index 9a24d82..f57c8a4 100755
--- a/tools/veridex/appcompat.sh
+++ b/tools/veridex/appcompat.sh
@@ -45,8 +45,8 @@
 fi
 
 # Logic for setting out_dir from build/make/core/envsetup.mk:
-if [[ -z $OUT_DIR ]]; then
-  if [[ -z $OUT_DIR_COMMON_BASE ]]; then
+if [[ -z "${OUT_DIR}" ]]; then
+  if [[ -z "${OUT_DIR_COMMON_BASE}" ]]; then
     OUT=out
   else
     OUT=${OUT_DIR_COMMON_BASE}/${PWD##*/}
@@ -55,9 +55,11 @@
   OUT=${OUT_DIR}
 fi
 
-PACKAGING=${OUT}/target/common/obj/PACKAGING
+if [[ -z "${PACKAGING}" ]]; then
+  PACKAGING=${OUT}/target/common/obj/PACKAGING
+fi
 
-if [ -z "$ANDROID_HOST_OUT" ] ; then
+if [[ -z "${ANDROID_HOST_OUT}" ]]; then
   ANDROID_HOST_OUT=${OUT}/host/linux-x86
 fi
 
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index cf1167f..7206c7d 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -65,6 +65,16 @@
 VeriMethod VeriClass::loadClass_ = nullptr;
 VeriField VeriClass::sdkInt_ = nullptr;
 
+static const char* kDexFileOption = "--dex-file=";
+static const char* kStubsOption = "--core-stubs=";
+static const char* kWhitelistOption = "--whitelist=";
+static const char* kBlacklistOption = "--blacklist=";
+static const char* kDarkGreylistOption = "--dark-greylist=";
+static const char* kLightGreylistOption = "--light-greylist=";
+static const char* kImprecise = "--imprecise";
+static const char* kTargetSdkVersion = "--target-sdk-version=";
+static const char* kOnlyReportSdkUses = "--only-report-sdk-uses";
+
 struct VeridexOptions {
   const char* dex_file = nullptr;
   const char* core_stubs = nullptr;
@@ -90,16 +100,6 @@
   argv++;
   argc--;
 
-  static const char* kDexFileOption = "--dex-file=";
-  static const char* kStubsOption = "--core-stubs=";
-  static const char* kWhitelistOption = "--whitelist=";
-  static const char* kBlacklistOption = "--blacklist=";
-  static const char* kDarkGreylistOption = "--dark-greylist=";
-  static const char* kLightGreylistOption = "--light-greylist=";
-  static const char* kImprecise = "--imprecise";
-  static const char* kTargetSdkVersion = "--target-sdk-version=";
-  static const char* kOnlyReportSdkUses = "--only-report-sdk-uses";
-
   for (int i = 0; i < argc; ++i) {
     if (StartsWith(argv[i], kDexFileOption)) {
       options->dex_file = Substr(argv[i], strlen(kDexFileOption));
@@ -138,6 +138,12 @@
   static int Run(int argc, char** argv) {
     VeridexOptions options;
     ParseArgs(&options, argc, argv);
+
+    if (!options.dex_file) {
+      LOG(ERROR) << "Required argument '" << kDexFileOption << "' not provided.";
+      return 1;
+    }
+
     gTargetSdkVersion = options.target_sdk_version;
 
     std::vector<std::string> boot_content;
@@ -229,6 +235,9 @@
       options.blacklist = nullptr;
       options.dark_greylist = nullptr;
       options.light_greylist = nullptr;
+    } else {
+      // Otherwise, omit SDK uses.
+      options.whitelist = nullptr;
     }
 
     // Find and log uses of hidden APIs.
@@ -335,4 +344,3 @@
 int main(int argc, char** argv) {
   return art::Veridex::Run(argc, argv);
 }
-