[Target] Decouple ObjCLanguageRuntime from LanguageRuntime

Summary:
ObjCLanguageRuntime was being pulled into LanguageRuntime because of
Breakpoint Preconditions. If we move BreakpointPrecondition out of Breakpoint,
we can extend the LanguageRuntime plugin interface so that LanguageRuntimes
can give us a BreakpointPrecondition for exceptions.

Differential Revision: https://reviews.llvm.org/D63181

llvm-svn: 364098
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
index 0ebba59..3c38419 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -11,6 +11,7 @@
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointPrecondition.h"
 #include "lldb/Breakpoint/BreakpointResolver.h"
 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
 #include "lldb/Core/Address.h"
@@ -995,21 +996,6 @@
   return m_precondition_sp->EvaluatePrecondition(context);
 }
 
-bool Breakpoint::BreakpointPrecondition::EvaluatePrecondition(
-    StoppointCallbackContext &context) {
-  return true;
-}
-
-void Breakpoint::BreakpointPrecondition::GetDescription(
-    Stream &stream, lldb::DescriptionLevel level) {}
-
-Status
-Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options) {
-  Status error;
-  error.SetErrorString("Base breakpoint precondition has no options.");
-  return error;
-}
-
 void Breakpoint::SendBreakpointChangedEvent(
     lldb::BreakpointEventType eventKind) {
   if (!m_being_created && !IsInternal() &&
diff --git a/lldb/source/Breakpoint/BreakpointPrecondition.cpp b/lldb/source/Breakpoint/BreakpointPrecondition.cpp
new file mode 100644
index 0000000..a387c75
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointPrecondition.cpp
@@ -0,0 +1,26 @@
+//===-- BreakpointPrecondition.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointPrecondition.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+
+bool BreakpointPrecondition::EvaluatePrecondition(
+    StoppointCallbackContext &context) {
+  return false;
+}
+
+void BreakpointPrecondition::GetDescription(Stream &stream,
+                                            lldb::DescriptionLevel level) {}
+
+Status BreakpointPrecondition::ConfigurePrecondition(Args &args) {
+  Status error;
+  error.SetErrorString("Base breakpoint precondition has no options.");
+  return error;
+}
diff --git a/lldb/source/Breakpoint/CMakeLists.txt b/lldb/source/Breakpoint/CMakeLists.txt
index 439946c..a7c0baf 100644
--- a/lldb/source/Breakpoint/CMakeLists.txt
+++ b/lldb/source/Breakpoint/CMakeLists.txt
@@ -8,6 +8,7 @@
   BreakpointLocationList.cpp
   BreakpointName.cpp
   BreakpointOptions.cpp
+  BreakpointPrecondition.cpp
   BreakpointResolver.cpp
   BreakpointResolverAddress.cpp
   BreakpointResolverFileLine.cpp
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index cf940dd7..24cadcd 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -828,6 +828,7 @@
   std::string description;
   LanguageRuntimeCreateInstance create_callback;
   LanguageRuntimeGetCommandObject command_callback;
+  LanguageRuntimeGetExceptionPrecondition precondition_callback;
 };
 
 typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances;
@@ -845,7 +846,8 @@
 bool PluginManager::RegisterPlugin(
     ConstString name, const char *description,
     LanguageRuntimeCreateInstance create_callback,
-    LanguageRuntimeGetCommandObject command_callback) {
+    LanguageRuntimeGetCommandObject command_callback,
+    LanguageRuntimeGetExceptionPrecondition precondition_callback) {
   if (create_callback) {
     LanguageRuntimeInstance instance;
     assert((bool)name);
@@ -854,6 +856,7 @@
       instance.description = description;
     instance.create_callback = create_callback;
     instance.command_callback = command_callback;
+    instance.precondition_callback = precondition_callback;
     std::lock_guard<std::recursive_mutex> guard(GetLanguageRuntimeMutex());
     GetLanguageRuntimeInstances().push_back(instance);
   }
@@ -895,6 +898,15 @@
   return nullptr;
 }
 
+LanguageRuntimeGetExceptionPrecondition
+PluginManager::GetLanguageRuntimeGetExceptionPreconditionAtIndex(uint32_t idx) {
+  std::lock_guard<std::recursive_mutex> guard(GetLanguageRuntimeMutex());
+  LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances();
+  if (idx < instances.size())
+    return instances[idx].precondition_callback;
+  return nullptr;
+}
+
 LanguageRuntimeCreateInstance
 PluginManager::GetLanguageRuntimeCreateCallbackForPluginName(
     ConstString name) {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 49d18c3..c8884fd5 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -85,7 +85,8 @@
 void AppleObjCRuntimeV1::Initialize() {
   PluginManager::RegisterPlugin(
       GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1",
-      CreateInstance);
+      CreateInstance,
+      /*command_callback = */ nullptr, GetBreakpointExceptionPrecondition);
 }
 
 void AppleObjCRuntimeV1::Terminate() {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 64dab7e..c849a54 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -806,7 +806,8 @@
       CreateInstance,
       [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
         return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));
-      });
+      },
+      GetBreakpointExceptionPrecondition);
 }
 
 void AppleObjCRuntimeV2::Terminate() {
diff --git a/lldb/source/Target/LanguageRuntime.cpp b/lldb/source/Target/LanguageRuntime.cpp
index a75f008..dd44158 100644
--- a/lldb/source/Target/LanguageRuntime.cpp
+++ b/lldb/source/Target/LanguageRuntime.cpp
@@ -11,7 +11,6 @@
 #include "lldb/Core/SearchFilter.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Target/Language.h"
-#include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Target.h"
 
 using namespace lldb;
@@ -224,19 +223,24 @@
 
 LanguageRuntime::~LanguageRuntime() = default;
 
-Breakpoint::BreakpointPreconditionSP
-LanguageRuntime::CreateExceptionPrecondition(lldb::LanguageType language,
-                                             bool catch_bp, bool throw_bp) {
-  switch (language) {
-  case eLanguageTypeObjC:
-    if (throw_bp)
-      return Breakpoint::BreakpointPreconditionSP(
-          new ObjCLanguageRuntime::ObjCExceptionPrecondition());
-    break;
-  default:
-    break;
+BreakpointPreconditionSP
+LanguageRuntime::GetExceptionPrecondition(LanguageType language,
+                                          bool throw_bp) {
+  LanguageRuntimeCreateInstance create_callback;
+  for (uint32_t idx = 0;
+       (create_callback =
+            PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
+       nullptr;
+       idx++) {
+    if (auto precondition_callback =
+            PluginManager::GetLanguageRuntimeGetExceptionPreconditionAtIndex(
+                idx)) {
+      if (BreakpointPreconditionSP precond =
+              precondition_callback(language, throw_bp))
+        return precond;
+    }
   }
-  return Breakpoint::BreakpointPreconditionSP();
+  return BreakpointPreconditionSP();
 }
 
 BreakpointSP LanguageRuntime::CreateExceptionBreakpoint(
@@ -252,10 +256,8 @@
       target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware,
                               resolve_indirect_functions));
   if (exc_breakpt_sp) {
-    Breakpoint::BreakpointPreconditionSP precondition_sp =
-        CreateExceptionPrecondition(language, catch_bp, throw_bp);
-    if (precondition_sp)
-      exc_breakpt_sp->SetPrecondition(precondition_sp);
+    if (auto precond = GetExceptionPrecondition(language, throw_bp))
+      exc_breakpt_sp->SetPrecondition(precond);
 
     if (is_internal)
       exc_breakpt_sp->SetBreakpointKind("exception");
@@ -292,4 +294,3 @@
     }
   }
 }
-
diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp
index 3084b70e..ef059a8 100644
--- a/lldb/source/Target/ObjCLanguageRuntime.cpp
+++ b/lldb/source/Target/ObjCLanguageRuntime.cpp
@@ -375,6 +375,18 @@
   return found;
 }
 
+lldb::BreakpointPreconditionSP
+ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language,
+                                                        bool throw_bp) {
+  if (language != eLanguageTypeObjC)
+    return lldb::BreakpointPreconditionSP();
+  if (!throw_bp)
+    return lldb::BreakpointPreconditionSP();
+  BreakpointPreconditionSP precondition_sp(
+      new ObjCLanguageRuntime::ObjCExceptionPrecondition());
+  return precondition_sp;
+}
+
 // Exception breakpoint Precondition class for ObjC:
 void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
     const char *class_name) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 7f68b28..5e83ca0 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -11,6 +11,7 @@
 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
 #include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/BreakpointPrecondition.h"
 #include "lldb/Breakpoint/BreakpointResolver.h"
 #include "lldb/Breakpoint/BreakpointResolverAddress.h"
 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
@@ -573,8 +574,7 @@
   BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint(
       *this, language, catch_bp, throw_bp, internal);
   if (exc_bkpt_sp && additional_args) {
-    Breakpoint::BreakpointPreconditionSP precondition_sp =
-        exc_bkpt_sp->GetPrecondition();
+    BreakpointPreconditionSP precondition_sp = exc_bkpt_sp->GetPrecondition();
     if (precondition_sp && additional_args) {
       if (error)
         *error = precondition_sp->ConfigurePrecondition(*additional_args);