Merge "ART: Change lock dumping"
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 500fc4a..40a5370 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -174,7 +174,6 @@
       }
     }
 
-    timer_.reset(new CumulativeLogger("Compilation times"));
     CreateCompilerDriver(compiler_kind_, instruction_set);
   }
 }
@@ -193,9 +192,6 @@
                                             GetCompiledClasses(),
                                             GetCompiledMethods(),
                                             number_of_threads,
-                                            /* dump_stats */ true,
-                                            /* dump_passes */ true,
-                                            timer_.get(),
                                             /* swap_fd */ -1,
                                             GetProfileCompilationInfo()));
   // We typically don't generate an image in unit tests, disable this optimization by default.
@@ -227,7 +223,6 @@
 }
 
 void CommonCompilerTest::TearDown() {
-  timer_.reset();
   compiler_driver_.reset();
   callbacks_.reset();
   verification_results_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index bcda41a..05fdc97 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -106,7 +106,6 @@
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<VerificationResults> verification_results_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
-  std::unique_ptr<CumulativeLogger> timer_;
   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
 
 
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index de481ca..0769561 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -37,9 +37,6 @@
                         /* compiled_classes */ nullptr,
                         /* compiled_methods */ nullptr,
                         /* thread_count */ 1u,
-                        /* dump_stats */ false,
-                        /* dump_passes */ false,
-                        /* timer */ nullptr,
                         /* swap_fd */ -1,
                         /* profile_compilation_info */ nullptr);
   CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index fd7ae9f..0ca3c8f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -282,9 +282,6 @@
     std::unordered_set<std::string>* compiled_classes,
     std::unordered_set<std::string>* compiled_methods,
     size_t thread_count,
-    bool dump_stats,
-    bool dump_passes,
-    CumulativeLogger* timer,
     int swap_fd,
     const ProfileCompilationInfo* profile_compilation_info)
     : compiler_options_(compiler_options),
@@ -303,9 +300,6 @@
       had_hard_verifier_failure_(false),
       parallel_thread_count_(thread_count),
       stats_(new AOTCompilationStats),
-      dump_stats_(dump_stats),
-      dump_passes_(dump_passes),
-      timings_logger_(timer),
       compiler_context_(nullptr),
       support_boot_image_fixup_(true),
       compiled_method_storage_(swap_fd),
@@ -396,7 +390,7 @@
   if (GetCompilerOptions().IsAnyCompilationEnabled()) {
     Compile(class_loader, dex_files, timings);
   }
-  if (dump_stats_) {
+  if (GetCompilerOptions().GetDumpStats()) {
     stats_->Dump();
   }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index da4a580..d2141e8 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -97,9 +97,6 @@
                  std::unordered_set<std::string>* compiled_classes,
                  std::unordered_set<std::string>* compiled_methods,
                  size_t thread_count,
-                 bool dump_stats,
-                 bool dump_passes,
-                 CumulativeLogger* timer,
                  int swap_fd,
                  const ProfileCompilationInfo* profile_compilation_info);
 
@@ -302,18 +299,6 @@
     return parallel_thread_count_;
   }
 
-  bool GetDumpStats() const {
-    return dump_stats_;
-  }
-
-  bool GetDumpPasses() const {
-    return dump_passes_;
-  }
-
-  CumulativeLogger* GetTimingsLogger() const {
-    return timings_logger_;
-  }
-
   void SetDedupeEnabled(bool dedupe_enabled) {
     compiled_method_storage_.SetDedupeEnabled(dedupe_enabled);
   }
@@ -536,11 +521,6 @@
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
 
-  bool dump_stats_;
-  const bool dump_passes_;
-
-  CumulativeLogger* const timings_logger_;
-
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 032763c..c0a9a05 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -49,6 +49,8 @@
       implicit_so_checks_(true),
       implicit_suspend_checks_(false),
       compile_pic_(false),
+      dump_timings_(false),
+      dump_stats_(false),
       verbose_methods_(),
       abort_on_hard_verifier_failure_(false),
       abort_on_soft_verifier_failure_(false),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index a71f61a..3f66029 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -266,6 +266,14 @@
     return passes_to_run_;
   }
 
+  bool GetDumpTimings() const {
+    return dump_timings_;
+  }
+
+  bool GetDumpStats() const {
+    return dump_stats_;
+  }
+
  private:
   bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
   void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
@@ -303,6 +311,8 @@
   bool implicit_so_checks_;
   bool implicit_suspend_checks_;
   bool compile_pic_;
+  bool dump_timings_;
+  bool dump_stats_;
 
   // Vector of methods to have verbose output enabled for.
   std::vector<std::string> verbose_methods_;
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index e28d499..f97ab08 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -78,6 +78,14 @@
   map.AssignIfExists(Base::VerboseMethods, &options->verbose_methods_);
   options->deduplicate_code_ = map.GetOrDefault(Base::DeduplicateCode);
 
+  if (map.Exists(Base::DumpTimings)) {
+    options->dump_timings_ = true;
+  }
+
+  if (map.Exists(Base::DumpStats)) {
+    options->dump_stats_ = true;
+  }
+
   return true;
 }
 
@@ -129,6 +137,12 @@
           .WithValueMap({{"false", false}, {"true", true}})
           .IntoKey(Map::DeduplicateCode)
 
+      .Define({"--dump-timings"})
+          .IntoKey(Map::DumpTimings)
+
+      .Define({"--dump-stats"})
+          .IntoKey(Map::DumpStats)
+
       .Define("--debuggable")
           .IntoKey(Map::Debuggable)
 
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index cccd618..2c56fd7 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -58,5 +58,7 @@
 COMPILER_OPTIONS_KEY (std::string,                 RegisterAllocationStrategy)
 COMPILER_OPTIONS_KEY (ParseStringList<','>,        VerboseMethods)
 COMPILER_OPTIONS_KEY (bool,                        DeduplicateCode,        true)
+COMPILER_OPTIONS_KEY (Unit,                        DumpTimings)
+COMPILER_OPTIONS_KEY (Unit,                        DumpStats)
 
 #undef COMPILER_OPTIONS_KEY
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 0c82d60..f33c5e1 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -130,7 +130,6 @@
   if (instruction_set_features_ == nullptr) {
     instruction_set_features_ = InstructionSetFeatures::FromCppDefines();
   }
-  cumulative_logger_.reset(new CumulativeLogger("jit times"));
   compiler_driver_.reset(new CompilerDriver(
       compiler_options_.get(),
       /* verification_results */ nullptr,
@@ -141,9 +140,6 @@
       /* compiled_classes */ nullptr,
       /* compiled_methods */ nullptr,
       /* thread_count */ 1,
-      /* dump_stats */ false,
-      /* dump_passes */ false,
-      cumulative_logger_.get(),
       /* swap_fd */ -1,
       /* profile_compilation_info */ nullptr));
   // Disable dedupe so we can remove compiled methods.
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index 1e1838e..31dc9e2 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -48,7 +48,6 @@
 
  private:
   std::unique_ptr<CompilerOptions> compiler_options_;
-  std::unique_ptr<CumulativeLogger> cumulative_logger_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
   std::unique_ptr<JitLogger> jit_logger_;
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 6297dd0..9e9d14a 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -52,9 +52,6 @@
                 /* compiled_classes */ nullptr,
                 /* compiled_methods */ nullptr,
                 /* thread_count */ 1u,
-                /* dump_stats */ false,
-                /* dump_passes */ false,
-                /* timer */ nullptr,
                 /* swap_fd */ -1,
                 /* profile_compilation_info */ nullptr),
         error_msg_(),
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 210607f..7719924 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -104,7 +104,8 @@
   return kCanThrow;
 }
 
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
   //
   // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
@@ -130,7 +131,6 @@
       }
       if (invoke_type == kVirtual) {
         ArtMethod* art_method = invoke->GetResolvedMethod();
-        ScopedObjectAccess soa(Thread::Current());
         return (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
       }
       return false;
@@ -139,26 +139,39 @@
       // Call might be devirtualized.
       return (invoke_type == kVirtual || invoke_type == kDirect);
 
-    default:
+    case kSuper:
+    case kInterface:
+    case kPolymorphic:
       return false;
   }
+  LOG(FATAL) << "Unknown intrinsic invoke type: " << intrinsic_type;
+  UNREACHABLE();
 }
 
 bool IntrinsicsRecognizer::Recognize(HInvoke* invoke, /*out*/ bool* wrong_invoke_type) {
   ArtMethod* art_method = invoke->GetResolvedMethod();
-  if (art_method != nullptr && art_method->IsIntrinsic()) {
-    Intrinsics intrinsic = static_cast<Intrinsics>(art_method->GetIntrinsic());
-    if (CheckInvokeType(intrinsic, invoke)) {
-      invoke->SetIntrinsic(intrinsic,
-                           NeedsEnvironmentOrCache(intrinsic),
-                           GetSideEffects(intrinsic),
-                           GetExceptions(intrinsic));
-     return true;
-    } else {
-      *wrong_invoke_type = true;
-    }
+  *wrong_invoke_type = false;
+  if (art_method == nullptr || !art_method->IsIntrinsic()) {
+    return false;
   }
-  return false;
+
+  // TODO: b/65872996 The intent is that polymorphic signature methods should
+  // be compiler intrinsics. At present, they are only interpreter intrinsics.
+  if (art_method->IsPolymorphicSignature()) {
+    return false;
+  }
+
+  Intrinsics intrinsic = static_cast<Intrinsics>(art_method->GetIntrinsic());
+  if (CheckInvokeType(intrinsic, invoke) == false) {
+    *wrong_invoke_type = true;
+    return false;
+  }
+
+  invoke->SetIntrinsic(intrinsic,
+                       NeedsEnvironmentOrCache(intrinsic),
+                       GetSideEffects(intrinsic),
+                       GetExceptions(intrinsic));
+  return true;
 }
 
 void IntrinsicsRecognizer::Run() {
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 8088ab2..c07a990 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -46,8 +46,9 @@
 
   // Static helper that recognizes intrinsic call. Returns true on success.
   // If it fails due to invoke type mismatch, wrong_invoke_type is set.
-  // Useful to recognize intrinsics on invidual calls outside this full pass.
-  static bool Recognize(HInvoke* invoke, /*out*/ bool* wrong_invoke_type);
+  // Useful to recognize intrinsics on individual calls outside this full pass.
+  static bool Recognize(HInvoke* invoke, /*out*/ bool* wrong_invoke_type)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index b6d3294..73c72fc 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -112,7 +112,7 @@
                Mutex& dump_mutex)
       : graph_(graph),
         cached_method_name_(),
-        timing_logger_enabled_(compiler_driver->GetDumpPasses()),
+        timing_logger_enabled_(compiler_driver->GetCompilerOptions().GetDumpTimings()),
         timing_logger_(timing_logger_enabled_ ? GetMethodName() : "", true, true),
         disasm_info_(graph->GetAllocator()),
         visualizer_oss_(),
@@ -407,7 +407,7 @@
         driver->GetCompilerOptions().GetDumpCfgAppend() ? std::ofstream::app : std::ofstream::out;
     visualizer_output_.reset(new std::ofstream(cfg_file_name, cfg_file_mode));
   }
-  if (driver->GetDumpStats()) {
+  if (driver->GetCompilerOptions().GetDumpStats()) {
     compilation_stats_.reset(new OptimizingCompilerStats());
   }
 }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 8137fb1..27bec1d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -628,10 +628,6 @@
       opened_dex_files_maps_(),
       opened_dex_files_(),
       no_inline_from_dex_files_(),
-      dump_stats_(false),
-      dump_passes_(false),
-      dump_timing_(false),
-      dump_slow_timing_(kIsDebugBuild),
       avoid_storing_invocation_(false),
       swap_fd_(kInvalidFd),
       app_image_fd_(kInvalidFd),
@@ -1221,9 +1217,6 @@
     }
 
     AssignTrueIfExists(args, M::Host, &is_host_);
-    AssignTrueIfExists(args, M::DumpTiming, &dump_timing_);
-    AssignTrueIfExists(args, M::DumpPasses, &dump_passes_);
-    AssignTrueIfExists(args, M::DumpStats, &dump_stats_);
     AssignTrueIfExists(args, M::AvoidStoringInvocation, &avoid_storing_invocation_);
     AssignTrueIfExists(args, M::MultiImage, &multi_image_);
 
@@ -1726,7 +1719,6 @@
     ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
 
     TimingLogger::ScopedTiming t("dex2oat Compile", timings_);
-    compiler_phases_timings_.reset(new CumulativeLogger("compilation times"));
 
     // Find the dex files we should not inline from.
     std::vector<std::string> no_inline_filters;
@@ -1787,9 +1779,6 @@
                                      compiled_classes_.release(),
                                      compiled_methods_.release(),
                                      thread_count_,
-                                     dump_stats_,
-                                     dump_passes_,
-                                     compiler_phases_timings_.get(),
                                      swap_fd_,
                                      profile_compilation_info_.get()));
     driver_->SetDexFilesForOatFile(dex_files_);
@@ -2202,12 +2191,10 @@
   }
 
   void DumpTiming() {
-    if (dump_timing_ || (dump_slow_timing_ && timings_->GetTotalNs() > MsToNs(1000))) {
+    if (compiler_options_->GetDumpTimings() ||
+        (kIsDebugBuild && timings_->GetTotalNs() > MsToNs(1000))) {
       LOG(INFO) << Dumpable<TimingLogger>(*timings_);
     }
-    if (dump_passes_) {
-      LOG(INFO) << Dumpable<CumulativeLogger>(*driver_->GetTimingsLogger());
-    }
   }
 
   bool IsImage() const {
@@ -2842,10 +2829,6 @@
   // Note that this might contain pointers owned by class_loader_context_.
   std::vector<const DexFile*> no_inline_from_dex_files_;
 
-  bool dump_stats_;
-  bool dump_passes_;
-  bool dump_timing_;
-  bool dump_slow_timing_;
   bool avoid_storing_invocation_;
   std::string swap_file_name_;
   int swap_fd_;
@@ -2858,7 +2841,6 @@
   int profile_file_fd_;
   std::unique_ptr<ProfileCompilationInfo> profile_compilation_info_;
   TimingLogger* timings_;
-  std::unique_ptr<CumulativeLogger> compiler_phases_timings_;
   std::vector<std::vector<const DexFile*>> dex_files_per_oat_file_;
   std::unordered_map<const DexFile*, size_t> dex_file_oat_index_map_;
 
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 7f177b9..d9b4ea7 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -220,12 +220,6 @@
           .IntoKey(M::Backend)
       .Define("--host")
           .IntoKey(M::Host)
-      .Define("--dump-timing")
-          .IntoKey(M::DumpTiming)
-      .Define("--dump-passes")
-          .IntoKey(M::DumpPasses)
-      .Define("--dump-stats")
-          .IntoKey(M::DumpStats)
       .Define("--avoid-storing-invocation")
           .IntoKey(M::AvoidStoringInvocation)
       .Define("--very-large-app-threshold=_")
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index b8286e8..fec05cc 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -102,7 +102,6 @@
     callbacks_.reset(new QuickCompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp));
     callbacks_->SetVerificationResults(verification_results_.get());
     Runtime::Current()->SetCompilerCallbacks(callbacks_.get());
-    timer_.reset(new CumulativeLogger("Compilation times"));
     compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                               verification_results_.get(),
                                               compiler_kind,
@@ -112,9 +111,6 @@
                                               /* compiled_classes */ nullptr,
                                               /* compiled_methods */ nullptr,
                                               /* thread_count */ 2,
-                                              /* dump_stats */ true,
-                                              /* dump_passes */ true,
-                                              timer_.get(),
                                               /* swap_fd */ -1,
                                               /* profile_compilation_info */ nullptr));
   }
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index be4ebbc..05f9125 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -899,9 +899,9 @@
   }
 }
 
-static void SetupTraceListener(JvmtiMethodTraceListener* listener,
-                               ArtJvmtiEvent event,
-                               bool enable) {
+void EventHandler::SetupTraceListener(JvmtiMethodTraceListener* listener,
+                                      ArtJvmtiEvent event,
+                                      bool enable) {
   bool needs_full_deopt = EventNeedsFullDeopt(event);
   // Make sure we can deopt.
   {
@@ -921,8 +921,21 @@
   }
 
   // Add the actual listeners.
-  art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
   uint32_t new_events = GetInstrumentationEventsFor(event);
+  if (new_events == art::instrumentation::Instrumentation::kDexPcMoved) {
+    // Need to skip adding the listeners if the event is breakpoint/single-step since those events
+    // share the same art-instrumentation underlying event. We need to give them their own deopt
+    // request though so the test waits until here.
+    DCHECK(event == ArtJvmtiEvent::kBreakpoint || event == ArtJvmtiEvent::kSingleStep);
+    ArtJvmtiEvent other = event == ArtJvmtiEvent::kBreakpoint ? ArtJvmtiEvent::kSingleStep
+                                                              : ArtJvmtiEvent::kBreakpoint;
+    if (IsEventEnabledAnywhere(other)) {
+      // The event needs to be kept around/is already enabled by the other jvmti event that uses the
+      // same instrumentation event.
+      return;
+    }
+  }
+  art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
   art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
   art::gc::ScopedGCCriticalSection gcs(art::Thread::Current(),
                                        art::gc::kGcCauseInstrumentation,
@@ -1002,18 +1015,6 @@
     case ArtJvmtiEvent::kGarbageCollectionFinish:
       SetupGcPauseTracking(gc_pause_listener_.get(), event, enable);
       return;
-
-    case ArtJvmtiEvent::kBreakpoint:
-    case ArtJvmtiEvent::kSingleStep: {
-      ArtJvmtiEvent other = (event == ArtJvmtiEvent::kBreakpoint) ? ArtJvmtiEvent::kSingleStep
-                                                                  : ArtJvmtiEvent::kBreakpoint;
-      // We only need to do anything if there isn't already a listener installed/held-on by the
-      // other jvmti event that uses DexPcMoved.
-      if (!IsEventEnabledAnywhere(other)) {
-        SetupTraceListener(method_trace_listener_.get(), event, enable);
-      }
-      return;
-    }
     // FramePop can never be disabled once it's been turned on since we would either need to deal
     // with dangling pointers or have missed events.
     // TODO We really need to make this not the case anymore.
@@ -1030,6 +1031,8 @@
     case ArtJvmtiEvent::kFieldModification:
     case ArtJvmtiEvent::kException:
     case ArtJvmtiEvent::kExceptionCatch:
+    case ArtJvmtiEvent::kBreakpoint:
+    case ArtJvmtiEvent::kSingleStep:
       SetupTraceListener(method_trace_listener_.get(), event, enable);
       return;
     case ArtJvmtiEvent::kMonitorContendedEnter:
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index c73215f..b051366 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -234,6 +234,8 @@
       REQUIRES(!envs_lock_);
 
  private:
+  void SetupTraceListener(JvmtiMethodTraceListener* listener, ArtJvmtiEvent event, bool enable);
+
   template <ArtJvmtiEvent kEvent, typename ...Args>
   ALWAYS_INLINE
   inline std::vector<impl::EventHandlerFunc<kEvent>> CollectEvents(art::Thread* thread,
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 50913de..31abf94 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -95,10 +95,12 @@
   return method_index_;
 }
 
+template <ReadBarrierOption kReadBarrierOption>
 inline uint32_t ArtMethod::GetDexMethodIndex() {
   if (kCheckDeclaringClassState) {
-    CHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
-          GetDeclaringClass()->IsErroneous());
+    CHECK(IsRuntimeMethod() ||
+          GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() ||
+          GetDeclaringClass<kReadBarrierOption>()->IsErroneous());
   }
   return GetDexMethodIndexUnchecked();
 }
@@ -202,7 +204,14 @@
 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
   DCHECK(!IsProxyMethod());
   const DexFile* dex_file = GetDexFile();
-  return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
+  // Don't do a read barrier in the DCHECK() inside GetDexMethodIndex() as GetShorty()
+  // can be called when the declaring class is about to be unloaded and cannot be added
+  // to the mark stack (subsequent GC assertion would fail).
+  // It is safe to avoid the read barrier as the ArtMethod is constructed with a declaring
+  // Class already satisfying the DCHECK() inside GetDexMethodIndex(), so even if that copy
+  // of declaring class becomes a from-space object, it shall satisfy the DCHECK().
+  return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex<kWithoutReadBarrier>()),
+                                   out_length);
 }
 
 inline const Signature ArtMethod::GetSignature() {
@@ -319,7 +328,7 @@
 
 template <ReadBarrierOption kReadBarrierOption>
 inline mirror::DexCache* ArtMethod::GetDexCache() {
-  if (LIKELY(!IsObsolete())) {
+  if (LIKELY(!IsObsolete<kReadBarrierOption>())) {
     mirror::Class* klass = GetDeclaringClass<kReadBarrierOption>();
     return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>();
   } else {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 6c3bb10..0a592e0 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -242,8 +242,9 @@
     return (GetAccessFlags() & kAccDefault) != 0;
   }
 
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsObsolete() {
-    return (GetAccessFlags() & kAccObsoleteMethod) != 0;
+    return (GetAccessFlags<kReadBarrierOption>() & kAccObsoleteMethod) != 0;
   }
 
   void SetIsObsolete() {
@@ -376,6 +377,7 @@
   ALWAYS_INLINE uint32_t GetDexMethodIndexUnchecked() {
     return dex_method_index_;
   }
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   ALWAYS_INLINE uint32_t GetDexMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetDexMethodIndex(uint32_t new_idx) {
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 58b33be..66270fd 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -104,20 +104,6 @@
 }
 #endif
 
-// Currently we have to fall back to our own loader for the boot image when it's compiled PIC
-// because its base is zero. Thus in-process unwinding through it won't work. This is a helper
-// detecting this.
-#if __linux__
-static bool IsPicImage() {
-  std::vector<gc::space::ImageSpace*> image_spaces =
-      Runtime::Current()->GetHeap()->GetBootImageSpaces();
-  CHECK(!image_spaces.empty());  // We should be running with an image.
-  const OatFile* oat_file = image_spaces[0]->GetOatFile();
-  CHECK(oat_file != nullptr);     // We should have an oat file to go with the image.
-  return oat_file->IsPic();
-}
-#endif
-
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
     JNIEnv*,
     jobject,
@@ -125,11 +111,6 @@
     jint,
     jboolean) {
 #if __linux__
-  if (IsPicImage()) {
-    LOG(INFO) << "Image is pic, in-process unwinding check bypassed.";
-    return JNI_TRUE;
-  }
-
   // TODO: What to do on Valgrind?
 
   std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));