JDevlieghere created this revision.
JDevlieghere added a reviewer: labath.
Herald added a subscriber: abidh.
JDevlieghere added a parent revision: D77588: [lldb/Reproducers] Make it 
possible to capture reproducers for the Python test suite..

Support inline replay as described in the RFC [1] on lldb-dev. This extends the 
LLDB_RECORD macros to re-invoke the current function with arguments 
deserialized from the reproducer. This relies on the function being called in 
the exact same order as during replay. It uses the same mechanism to toggle the 
API boundary as during recording, which guarantees that only boundary crossing 
calls are replayed.

Another major change is that before this patch we could ignore the result of an 
API call, because we only cared about the observable behavior. Now we need to 
be able to return the replayed result to the SWIG bindings.

We reuse a lot of the recording infrastructure, which can be a little confusing 
at first. I'm open to renaming these things in a future patch, but I refrained 
from doing so here to make it easier to review.

[1] http://lists.llvm.org/pipermail/lldb-dev/2020-April/016100.html


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D77602

Files:
  lldb/include/lldb/Utility/Reproducer.h
  lldb/include/lldb/Utility/ReproducerInstrumentation.h
  lldb/source/API/SBReproducer.cpp
  lldb/source/API/SBReproducerPrivate.h
  lldb/source/Utility/Reproducer.cpp
  lldb/source/Utility/ReproducerInstrumentation.cpp

Index: lldb/source/Utility/ReproducerInstrumentation.cpp
===================================================================
--- lldb/source/Utility/ReproducerInstrumentation.cpp
+++ lldb/source/Utility/ReproducerInstrumentation.cpp
@@ -117,6 +117,39 @@
   return m_ids[id].second.ToString();
 }
 
+/// Extract the method name from the given signature.
+static llvm::StringRef GetMethodName(llvm::StringRef signature) {
+  auto pos = signature.find('(');
+  if (pos == llvm::StringRef::npos)
+    return {};
+
+  llvm::StringRef temp = signature.substr(0, pos);
+  pos = temp.rfind("::");
+  if (pos == llvm::StringRef::npos)
+    return {};
+
+  return temp.substr(pos);
+}
+
+void Registry::CheckSignature(llvm::StringRef expected, unsigned id) {
+  std::string actual = GetSignature(id);
+
+  llvm::StringRef expected_method = GetMethodName(expected);
+  llvm::StringRef actual_method = GetMethodName(actual);
+
+  /// This check is an approximation but will catch divergences eventually.
+  if (expected_method.empty() || actual_method.empty() ||
+      expected_method != actual_method) {
+    llvm::errs() << "Reproducer expected signature: '" << expected << "'\n";
+    llvm::errs() << "Reproducer actual signature:   '" << actual << "'\n";
+    llvm::report_fatal_error(
+        "Detected reproducer replay divergence. Refusing to continue.");
+  }
+#ifdef LLDB_REPRO_INSTR_TRACE
+  llvm::errs() << "Replaying " << id << ": " << actual << "\n";
+#endif
+}
+
 Replayer *Registry::GetReplayer(unsigned id) {
   assert(m_ids.count(id) != 0 && "ID not in registry");
   return m_ids[id].first;
Index: lldb/source/Utility/Reproducer.cpp
===================================================================
--- lldb/source/Utility/Reproducer.cpp
+++ lldb/source/Utility/Reproducer.cpp
@@ -228,7 +228,8 @@
 }
 
 Loader::Loader(FileSpec root)
-    : m_root(MakeAbsolute(std::move(root))), m_loaded(false) {}
+    : m_root(MakeAbsolute(std::move(root))), m_loaded(false),
+      m_api_replay(false) {}
 
 llvm::Error Loader::LoadIndex() {
   if (m_loaded)
Index: lldb/source/API/SBReproducerPrivate.h
===================================================================
--- lldb/source/API/SBReproducerPrivate.h
+++ lldb/source/API/SBReproducerPrivate.h
@@ -55,6 +55,17 @@
   SBRegistry m_registry;
 };
 
+class ReplayData {
+public:
+  ReplayData(llvm::StringRef buffer) : m_registry(), m_deserializer(buffer) {}
+  Deserializer &GetDeserializer() { return m_deserializer; }
+  Registry &GetRegistry() { return m_registry; }
+
+private:
+  SBRegistry m_registry;
+  Deserializer m_deserializer;
+};
+
 inline InstrumentationData GetInstrumentationData() {
   if (!lldb_private::repro::Reproducer::Initialized())
     return {};
@@ -64,6 +75,17 @@
     return {p.GetSerializer(), p.GetRegistry()};
   }
 
+  if (auto *l = lldb_private::repro::Reproducer::Instance().GetLoader()) {
+    if (l->IsAPIReplay()) {
+      FileSpec file = l->GetFile<SBProvider::Info>();
+      static auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
+      if (!error_or_file)
+        return {};
+      static ReplayData r((*error_or_file)->getBuffer());
+      return {r.GetDeserializer(), r.GetRegistry()};
+    }
+  }
+
   return {};
 }
 
Index: lldb/source/API/SBReproducer.cpp
===================================================================
--- lldb/source/API/SBReproducer.cpp
+++ lldb/source/API/SBReproducer.cpp
@@ -130,6 +130,8 @@
     error = llvm::toString(std::move(e));
     return error.c_str();
   }
+  repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
+  loader->SetAPIReplay(true);
   return nullptr;
 }
 
Index: lldb/include/lldb/Utility/ReproducerInstrumentation.h
===================================================================
--- lldb/include/lldb/Utility/ReproducerInstrumentation.h
+++ lldb/include/lldb/Utility/ReproducerInstrumentation.h
@@ -122,19 +122,39 @@
                                           stringify_args(__VA_ARGS__));        \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::construct<Class Signature>::doit,   \
-                     __VA_ARGS__);                                             \
-    _recorder.RecordResult(this, false);                                       \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::construct<Class Signature>::doit, \
+                       __VA_ARGS__);                                           \
+      _recorder.RecordResult(this, false);                                     \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        lldb_private::repro::replay_construct<Class Signature>::doit(          \
+            _recorder, *_deserializer, _data.GetRegistry(),                    \
+            LLVM_PRETTY_FUNCTION);                                             \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class)                                 \
   lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION);               \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::construct<Class()>::doit);          \
-    _recorder.RecordResult(this, false);                                       \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::construct<Class()>::doit);        \
+      _recorder.RecordResult(this, false);                                     \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        lldb_private::repro::replay_construct<Class()>::doit(                  \
+            _recorder, *_deserializer, _data.GetRegistry(),                    \
+            LLVM_PRETTY_FUNCTION);                                             \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...)              \
@@ -142,10 +162,22 @@
                                           stringify_args(*this, __VA_ARGS__)); \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::invoke<Result(                      \
-                         Class::*) Signature>::method<(&Class::Method)>::doit, \
-                     this, __VA_ARGS__);                                       \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(                                                        \
+          *_serializer, _data.GetRegistry(),                                   \
+          &lldb_private::repro::invoke<Result(Class::*) Signature>::method<(   \
+              &Class::Method)>::doit,                                          \
+          this, __VA_ARGS__);                                                  \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result(Class::*) Signature>::       \
+            method<&Class::Method>::doit(_recorder, *_deserializer,            \
+                                         _data.GetRegistry(),                  \
+                                         LLVM_PRETTY_FUNCTION);                \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD_CONST(Result, Class, Method, Signature, ...)        \
@@ -153,11 +185,22 @@
                                           stringify_args(*this, __VA_ARGS__)); \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(                                                          \
-        _data.GetSerializer(), _data.GetRegistry(),                            \
-        &lldb_private::repro::invoke<Result(                                   \
-            Class::*) Signature const>::method_const<(&Class::Method)>::doit,  \
-        this, __VA_ARGS__);                                                    \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(                                                        \
+          *_serializer, _data.GetRegistry(),                                   \
+          &lldb_private::repro::invoke<Result(Class::*) Signature const>::     \
+              method_const<(&Class::Method)>::doit,                            \
+          this, __VA_ARGS__);                                                  \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result(Class::*) Signature const>:: \
+            method_const<&Class::Method>::doit(_recorder, *_deserializer,      \
+                                               _data.GetRegistry(),            \
+                                               LLVM_PRETTY_FUNCTION);          \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD_NO_ARGS(Result, Class, Method)                      \
@@ -165,10 +208,20 @@
                                           stringify_args(*this));              \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::invoke<Result (                     \
-                         Class::*)()>::method<(&Class::Method)>::doit,         \
-                     this);                                                    \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::invoke<Result (                   \
+                           Class::*)()>::method<(&Class::Method)>::doit,       \
+                       this);                                                  \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result (Class::*)()>::method<       \
+            &Class::Method>::doit(_recorder, *_deserializer,                   \
+                                  _data.GetRegistry(), LLVM_PRETTY_FUNCTION);  \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD_CONST_NO_ARGS(Result, Class, Method)                \
@@ -176,11 +229,22 @@
                                           stringify_args(*this));              \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(                                                          \
-        _data.GetSerializer(), _data.GetRegistry(),                            \
-        &lldb_private::repro::invoke<Result (                                  \
-            Class::*)() const>::method_const<(&Class::Method)>::doit,          \
-        this);                                                                 \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(                                                        \
+          *_serializer, _data.GetRegistry(),                                   \
+          &lldb_private::repro::invoke<Result (                                \
+              Class::*)() const>::method_const<(&Class::Method)>::doit,        \
+          this);                                                               \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result (Class::*)() const>::        \
+            method_const<(&Class::Method)>::doit(_recorder, *_deserializer,    \
+                                                 _data.GetRegistry(),          \
+                                                 LLVM_PRETTY_FUNCTION);        \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_STATIC_METHOD(Result, Class, Method, Signature, ...)       \
@@ -188,17 +252,38 @@
                                           stringify_args(__VA_ARGS__));        \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     static_cast<Result(*) Signature>(&Class::Method),         \
-                     __VA_ARGS__);                                             \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       static_cast<Result(*) Signature>(&Class::Method),       \
+                       __VA_ARGS__);                                           \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result(*) Signature>::              \
+            method_static<(&Class::Method)>::doit(_recorder, *_deserializer,   \
+                                                  _data.GetRegistry(),         \
+                                                  LLVM_PRETTY_FUNCTION);       \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method)               \
   lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION);               \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     static_cast<Result (*)()>(&Class::Method));               \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       static_cast<Result (*)()>(&Class::Method));             \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::replay<Result (*)()>::method_static<(      \
+            &Class::Method)>::doit(_recorder, *_deserializer,                  \
+                                   _data.GetRegistry(), LLVM_PRETTY_FUNCTION); \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true);
@@ -242,17 +327,19 @@
   }
 
   /// Adds a pointer to an object to the mapping for the given index.
-  template <typename T> void AddObjectForIndex(unsigned idx, T *object) {
+  template <typename T> T *AddObjectForIndex(unsigned idx, T *object) {
     AddObjectForIndexImpl(
         idx, static_cast<void *>(
                  const_cast<typename std::remove_const<T>::type *>(object)));
+    return object;
   }
 
   /// Adds a reference to an object to the mapping for the given index.
-  template <typename T> void AddObjectForIndex(unsigned idx, T &object) {
+  template <typename T> T &AddObjectForIndex(unsigned idx, T &object) {
     AddObjectForIndexImpl(
         idx, static_cast<void *>(
                  const_cast<typename std::remove_const<T>::type *>(&object)));
+    return object;
   }
 
 private:
@@ -321,20 +408,20 @@
   }
 
   /// Store the returned value in the index-to-object mapping.
-  template <typename T> void HandleReplayResult(const T &t) {
+  template <typename T> T &HandleReplayResult(const T &t) {
     unsigned result = Deserialize<unsigned>();
     if (is_trivially_serializable<T>::value)
-      return;
+      return const_cast<T &>(t);
     // We need to make a copy as the original object might go out of scope.
-    m_index_to_object.AddObjectForIndex(result, new T(t));
+    return *m_index_to_object.AddObjectForIndex(result, new T(t));
   }
 
   /// Store the returned value in the index-to-object mapping.
-  template <typename T> void HandleReplayResult(T *t) {
+  template <typename T> T *HandleReplayResult(T *t) {
     unsigned result = Deserialize<unsigned>();
     if (is_trivially_serializable<T>::value)
-      return;
-    m_index_to_object.AddObjectForIndex(result, t);
+      return t;
+    return m_index_to_object.AddObjectForIndex(result, t);
   }
 
   /// All returned types are recorded, even when the function returns a void.
@@ -442,7 +529,11 @@
   DefaultReplayer(Result (*f)(Args...)) : Replayer(), f(f) {}
 
   void operator()(Deserializer &deserializer) const override {
-    deserializer.HandleReplayResult(
+    Replay(deserializer);
+  }
+
+  Result Replay(Deserializer &deserializer) const {
+    return deserializer.HandleReplayResult(
         DeserializationHelper<Args...>::template deserialized<Result>::doit(
             deserializer, f));
   }
@@ -457,6 +548,10 @@
   DefaultReplayer(void (*f)(Args...)) : Replayer(), f(f) {}
 
   void operator()(Deserializer &deserializer) const override {
+    Replay(deserializer);
+  }
+
+  void Replay(Deserializer &deserializer) const {
     DeserializationHelper<Args...>::template deserialized<void>::doit(
         deserializer, f);
     deserializer.HandleReplayResultVoid();
@@ -515,15 +610,19 @@
   /// Returns the ID for a given function address.
   unsigned GetID(uintptr_t addr);
 
+  /// Get the replayer matching the given ID.
+  Replayer *GetReplayer(unsigned id);
+
+  std::string GetSignature(unsigned id);
+
+  void CheckSignature(llvm::StringRef signature, unsigned id);
+
 protected:
   /// Register the given replayer for a function (and the ID mapping).
   void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
                   SignatureStr signature);
 
 private:
-  std::string GetSignature(unsigned id);
-  Replayer *GetReplayer(unsigned id);
-
   /// Mapping of function addresses to replayers and their ID.
   std::map<uintptr_t, std::pair<std::unique_ptr<Replayer>, unsigned>>
       m_replayers;
@@ -675,17 +774,27 @@
 
 class InstrumentationData {
 public:
-  InstrumentationData() : m_serializer(nullptr), m_registry(nullptr){};
+  InstrumentationData()
+      : m_serializer(nullptr), m_deserializer(nullptr), m_registry(nullptr){};
   InstrumentationData(Serializer &serializer, Registry &registry)
-      : m_serializer(&serializer), m_registry(&registry){};
-
-  Serializer &GetSerializer() { return *m_serializer; }
+      : m_serializer(&serializer), m_deserializer(nullptr),
+        m_registry(&registry){};
+  InstrumentationData(Deserializer &deserializer, Registry &registry)
+      : m_serializer(nullptr), m_deserializer(&deserializer),
+        m_registry(&registry){};
+
+  Serializer *GetSerializer() { return m_serializer; }
+  Deserializer *GetDeserializer() { return m_deserializer; }
   Registry &GetRegistry() { return *m_registry; }
 
-  operator bool() { return m_serializer != nullptr && m_registry != nullptr; }
+  operator bool() {
+    return (m_serializer != nullptr || m_deserializer != nullptr) &&
+           m_registry != nullptr;
+  }
 
 private:
   Serializer *m_serializer;
+  Deserializer *m_deserializer;
   Registry *m_registry;
 };
 
@@ -773,14 +882,22 @@
     return std::forward<Result>(r);
   }
 
+  template <typename Result>
+  Result ReplayResult(Result &&r, bool update_boundary) {
+    if (update_boundary)
+      UpdateBoundary();
+    return std::forward<Result>(r);
+  }
+
+  bool ShouldCapture() { return m_local_boundary; }
+
 private:
+  template <typename T> friend struct replay;
   void UpdateBoundary() {
     if (m_local_boundary)
       g_global_boundary = false;
   }
 
-  bool ShouldCapture() { return m_local_boundary; }
-
 #ifdef LLDB_REPRO_INSTR_TRACE
   void Log(unsigned id) {
     llvm::errs() << "Recording " << id << ": " << m_pretty_func << " ("
@@ -804,6 +921,107 @@
   static bool g_global_boundary;
 };
 
+template <typename Signature> struct replay_construct;
+template <typename Class, typename... Args>
+struct replay_construct<Class(Args...)> {
+  static Class *doit(Recorder &recorder, Deserializer &deserializer,
+                     Registry &registry, llvm::StringRef signature) {
+
+    unsigned id = deserializer.Deserialize<unsigned>();
+    registry.CheckSignature(signature, id);
+    return recorder.ReplayResult(
+        static_cast<DefaultReplayer<Class *(Args...)> *>(
+            registry.GetReplayer(id))
+            ->Replay(deserializer),
+        false);
+  }
+};
+
+template <typename Signature> struct replay;
+
+template <typename Result, typename Class, typename... Args>
+struct replay<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {
+    static Result doit(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Class *, Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename Result, typename Class, typename... Args>
+struct replay<Result (Class::*)(Args...) const> {
+  template <Result (Class::*m)(Args...) const> struct method_const {
+    static Result doit(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Class *, Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename Result, typename... Args>
+struct replay<Result (*)(Args...)> {
+  template <Result (*m)(Args...)> struct method_static {
+    static Result doit(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct replay<void (Class::*)(Args...)> {
+  template <void (Class::*m)(Args...)> struct method {
+    static void doit(Recorder &recorder, Deserializer &deserializer,
+                     Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      registry.GetReplayer(id)->operator()(deserializer);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct replay<void (Class::*)(Args...) const> {
+  template <void (Class::*m)(Args...) const> struct method_const {
+    static void doit(Recorder &recorder, Deserializer &deserializer,
+                     Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      registry.GetReplayer(id)->operator()(deserializer);
+    }
+  };
+};
+
+template <typename... Args> struct replay<void (*)(Args...)> {
+  template <void (*m)(Args...)> struct method_static {
+    static void doit(Recorder &recorder, Deserializer &deserializer,
+                     Registry &registry, llvm::StringRef signature) {
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckSignature(signature, id);
+      registry.GetReplayer(id)->operator()(deserializer);
+    }
+  };
+};
+
 template <typename Signature> struct char_ptr_redirect;
 template <typename Result, typename Class>
 struct char_ptr_redirect<Result (Class::*)(char *, size_t) const> {
Index: lldb/include/lldb/Utility/Reproducer.h
===================================================================
--- lldb/include/lldb/Utility/Reproducer.h
+++ lldb/include/lldb/Utility/Reproducer.h
@@ -309,12 +309,17 @@
 
   const FileSpec &GetRoot() const { return m_root; }
 
+  void SetAPIReplay(bool b) { m_api_replay = b; }
+
+  bool IsAPIReplay() const { return m_api_replay; }
+
 private:
   bool HasFile(llvm::StringRef file);
 
   FileSpec m_root;
   std::vector<std::string> m_files;
   bool m_loaded;
+  bool m_api_replay;
 };
 
 /// The reproducer enables clients to obtain access to the Generator and
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to