JDevlieghere updated this revision to Diff 257491.
JDevlieghere marked an inline comment as done.
JDevlieghere added a comment.

Rebase


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77602/new/

https://reviews.llvm.org/D77602

Files:
  lldb/include/lldb/Utility/Reproducer.h
  lldb/include/lldb/Utility/ReproducerInstrumentation.h
  lldb/source/API/SBDebugger.cpp
  lldb/source/API/SBReproducerPrivate.h
  lldb/source/Utility/Reproducer.cpp
  lldb/source/Utility/ReproducerInstrumentation.cpp
  lldb/unittests/Utility/ReproducerInstrumentationTest.cpp

Index: lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
===================================================================
--- lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
+++ lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
@@ -52,23 +52,47 @@
 
 static llvm::Optional<TestingRegistry> g_registry;
 static llvm::Optional<Serializer> g_serializer;
+static llvm::Optional<Deserializer> g_deserializer;
 
 inline InstrumentationData GetTestInstrumentationData() {
+  assert(!(g_serializer && g_deserializer));
   if (g_serializer)
     return InstrumentationData(*g_serializer, *g_registry);
+  if (g_deserializer)
+    return InstrumentationData(*g_deserializer, *g_registry);
   return InstrumentationData();
 }
 
 class TestInstrumentationDataRAII {
-public:
+private:
   TestInstrumentationDataRAII(llvm::raw_string_ostream &os) {
     g_registry.emplace();
     g_serializer.emplace(os);
+    g_deserializer.reset();
   }
 
-  ~TestInstrumentationDataRAII() {
+  TestInstrumentationDataRAII(llvm::StringRef buffer) {
+    g_registry.emplace();
+    g_serializer.reset();
+    g_deserializer.emplace(buffer);
+  }
+
+public:
+  ~TestInstrumentationDataRAII() { Reset(); }
+
+  void Reset() {
     g_registry.reset();
     g_serializer.reset();
+    g_deserializer.reset();
+  }
+
+  static TestInstrumentationDataRAII
+  GetRecordingData(llvm::raw_string_ostream &os) {
+    return TestInstrumentationDataRAII(os);
+  }
+
+  static TestInstrumentationDataRAII GetReplayData(llvm::StringRef buffer) {
+    return TestInstrumentationDataRAII(buffer);
   }
 };
 
@@ -95,11 +119,17 @@
   InstrumentedFoo(const InstrumentedFoo &foo);
   InstrumentedFoo &operator=(const InstrumentedFoo &foo);
   void A(int a);
+  int GetA();
   void B(int &b) const;
+  int &GetB();
   int C(float *c);
+  float GetC();
   int D(const char *d) const;
+  void GetD(char *buffer, size_t length);
   static void E(double e);
+  double GetE();
   static int F();
+  bool GetF();
   void Validate() override;
   //// }
   virtual bool IsA(Class c) override { return c == Class::Foo; }
@@ -182,35 +212,71 @@
   m_a = a;
 }
 
+int InstrumentedFoo::GetA() {
+  LLDB_RECORD_METHOD_NO_ARGS(int, InstrumentedFoo, GetA);
+
+  return m_a;
+}
+
 void InstrumentedFoo::B(int &b) const {
   LLDB_RECORD_METHOD_CONST(void, InstrumentedFoo, B, (int &), b);
   m_called++;
   m_b = b;
 }
 
+int &InstrumentedFoo::GetB() {
+  LLDB_RECORD_METHOD_NO_ARGS(int &, InstrumentedFoo, GetB);
+
+  return m_b;
+}
+
 int InstrumentedFoo::C(float *c) {
   LLDB_RECORD_METHOD(int, InstrumentedFoo, C, (float *), c);
   m_c = *c;
   return 1;
 }
 
+float InstrumentedFoo::GetC() {
+  LLDB_RECORD_METHOD_NO_ARGS(float, InstrumentedFoo, GetC);
+
+  return m_c;
+}
+
 int InstrumentedFoo::D(const char *d) const {
   LLDB_RECORD_METHOD_CONST(int, InstrumentedFoo, D, (const char *), d);
   m_d = std::string(d);
   return 2;
 }
 
+void InstrumentedFoo::GetD(char *buffer, size_t length) {
+  LLDB_RECORD_METHOD(void, InstrumentedFoo, GetD, (char *, size_t), buffer,
+                     length);
+  ::snprintf(buffer, length, "%s", m_d.c_str());
+}
+
 void InstrumentedFoo::E(double e) {
   LLDB_RECORD_STATIC_METHOD(void, InstrumentedFoo, E, (double), e);
   g_e = e;
 }
 
+double InstrumentedFoo::GetE() {
+  LLDB_RECORD_METHOD_NO_ARGS(double, InstrumentedFoo, GetE);
+
+  return g_e;
+}
+
 int InstrumentedFoo::F() {
   LLDB_RECORD_STATIC_METHOD_NO_ARGS(int, InstrumentedFoo, F);
   g_f = true;
   return 3;
 }
 
+bool InstrumentedFoo::GetF() {
+  LLDB_RECORD_METHOD_NO_ARGS(bool, InstrumentedFoo, GetF);
+
+  return g_f;
+}
+
 void InstrumentedFoo::Validate() {
   LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedFoo, Validate);
   EXPECT_EQ(m_a, 100);
@@ -296,6 +362,12 @@
   LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
                        (InstrumentedFoo &));
   LLDB_REGISTER_METHOD(void, InstrumentedBar, Validate, ());
+  LLDB_REGISTER_METHOD(int, InstrumentedFoo, GetA, ());
+  LLDB_REGISTER_METHOD(int &, InstrumentedFoo, GetB, ());
+  LLDB_REGISTER_METHOD(float, InstrumentedFoo, GetC, ());
+  LLDB_REGISTER_METHOD(void, InstrumentedFoo, GetD, (char *, size_t));
+  LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
+  LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
 }
 
 static const Pod p;
@@ -534,7 +606,8 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
 
     int b = 200;
     float c = 300.3f;
@@ -563,7 +636,8 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
 
     int b = 200;
     float c = 300.3f;
@@ -603,7 +677,8 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo foo = bar.GetInstrumentedFoo();
@@ -643,7 +718,8 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
@@ -679,7 +755,8 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
@@ -709,3 +786,259 @@
       deserializer.GetAllObjects(),
       {{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
 }
+
+TEST(PassiveReplayTest, InstrumentedFoo) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    InstrumentedFoo foo(0);
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+  }
+
+  std::string buffer = os.str();
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    int b = 999;
+    float c = 999.9f;
+    double e = 999.9;
+
+    InstrumentedFoo foo(9);
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBar) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo foo = bar.GetInstrumentedFoo();
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo foo = bar.GetInstrumentedFoo();
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBarRef) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBarPtr) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    TestInstrumentationDataRAII data =
+        TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
Index: lldb/source/Utility/ReproducerInstrumentation.cpp
===================================================================
--- lldb/source/Utility/ReproducerInstrumentation.cpp
+++ lldb/source/Utility/ReproducerInstrumentation.cpp
@@ -8,9 +8,9 @@
 
 #include "lldb/Utility/ReproducerInstrumentation.h"
 #include "lldb/Utility/Reproducer.h"
-#include <thread>
 #include <stdio.h>
 #include <stdlib.h>
+#include <thread>
 
 using namespace lldb_private;
 using namespace lldb_private::repro;
@@ -120,7 +120,7 @@
 
   // Add a small artificial delay to ensure that all asynchronous events have
   // completed before we exit.
-  std::this_thread::sleep_for (std::chrono::milliseconds(100));
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
   return true;
 }
@@ -145,6 +145,22 @@
   return m_ids[id].second.ToString();
 }
 
+void Registry::CheckID(unsigned expected, unsigned actual) {
+  if (expected != actual) {
+    llvm::errs() << "Reproducer expected signature " << expected << ": '"
+                 << GetSignature(expected) << "'\n";
+    llvm::errs() << "Reproducer actual signature " << actual << ": '"
+                 << GetSignature(actual) << "'\n";
+    llvm::report_fatal_error(
+        "Detected reproducer replay divergence. Refusing to continue.");
+  }
+
+#ifdef LLDB_REPRO_INSTR_TRACE
+  llvm::errs() << "Replaying " << actual << ": " << GetSignature(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_passive_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->IsPassiveReplay()) {
+      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/SBDebugger.cpp
===================================================================
--- lldb/source/API/SBDebugger.cpp
+++ lldb/source/API/SBDebugger.cpp
@@ -1629,31 +1629,31 @@
 
 template <> void RegisterMethods<SBDebugger>(Registry &R) {
   // Custom implementation.
-  R.Register(&invoke<void (SBDebugger::*)(
-                 FILE *, bool)>::method<&SBDebugger::SetErrorFileHandle>::doit,
+  R.Register(&invoke<void (SBDebugger::*)(FILE *, bool)>::method<
+                 &SBDebugger::SetErrorFileHandle>::record,
              &SetFileHandleRedirect);
-  R.Register(&invoke<void (SBDebugger::*)(
-                 FILE *, bool)>::method<&SBDebugger::SetOutputFileHandle>::doit,
+  R.Register(&invoke<void (SBDebugger::*)(FILE *, bool)>::method<
+                 &SBDebugger::SetOutputFileHandle>::record,
              &SetFileHandleRedirect);
 
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetInputFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetInputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetOutputFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetOutputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetErrorFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetErrorFile>::record,
              &SetFileRedirect);
 
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetInputFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetInputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetOutputFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetOutputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetErrorFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetErrorFile>::record,
              &SetFileRedirect);
 
   LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(bool, SBDebugger,
Index: lldb/include/lldb/Utility/ReproducerInstrumentation.h
===================================================================
--- lldb/include/lldb/Utility/ReproducerInstrumentation.h
+++ lldb/include/lldb/Utility/ReproducerInstrumentation.h
@@ -75,63 +75,61 @@
 // #define LLDB_REPRO_INSTR_TRACE
 
 #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature)                            \
-  R.Register<Class * Signature>(&construct<Class Signature>::doit, "", #Class, \
-                                #Class, #Signature)
+  R.Register<Class * Signature>(&construct<Class Signature>::record, "",       \
+                                #Class, #Class, #Signature)
 
 #define LLDB_REGISTER_METHOD(Result, Class, Method, Signature)                 \
   R.Register(                                                                  \
-      &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::doit,     \
+      &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::record,   \
       #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature)           \
   R.Register(&invoke<Result(Class::*) Signature const>::method_const<(         \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature)          \
   R.Register(                                                                  \
-      &invoke<Result(*) Signature>::method_static<(&Class::Method)>::doit,     \
+      &invoke<Result(*) Signature>::method_static<(&Class::Method)>::record,   \
       #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(Result, Class, Method)          \
   R.Register(&invoke<Result (*)(char *, size_t)>::method_static<(              \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              &char_ptr_redirect<Result (*)(char *, size_t)>::method_static<(   \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT(Result, Class, Method)                 \
   R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<(              \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              &char_ptr_redirect<Result (Class::*)(char *, size_t)>::method<(   \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(Result, Class, Method)           \
-  R.Register(&invoke<Result (Class::*)(char *, size_t)                         \
-                         const>::method_const<(&Class::Method)>::doit,         \
-             &char_ptr_redirect<Result (Class::*)(                             \
-                 char *, size_t) const>::method_const<(&Class::Method)>::doit, \
-             #Result, #Class, #Method, "(char*, size_t");
+  R.Register(                                                                  \
+      &invoke<Result (Class::*)(char *, size_t)                                \
+                  const>::method_const<(&Class::Method)>::record,              \
+      &char_ptr_redirect<Result (Class::*)(char *, size_t)                     \
+                             const>::method_const<(&Class::Method)>::record,   \
+      #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...)                         \
-  lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,                \
-                                          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);                                       \
+  {                                                                            \
+    lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,              \
+                                            stringify_args(__VA_ARGS__));      \
+    lldb_private::repro::construct<Class Signature>::handle(                   \
+        LLDB_GET_INSTRUMENTATION_DATA(), _recorder, LLVM_PRETTY_FUNCTION,      \
+        this, __VA_ARGS__);                                                    \
   }
 
 #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);                                       \
+  {                                                                            \
+    lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION);             \
+    lldb_private::repro::construct<Class()>::handle(                           \
+        LLDB_GET_INSTRUMENTATION_DATA(), _recorder, LLVM_PRETTY_FUNCTION,      \
+        this);                                                                 \
   }
 
 #define LLDB_RECORD_(Method, T1, T2, ...)                                      \
@@ -139,9 +137,19 @@
                                           stringify_args(__VA_ARGS__));        \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::invoke<T1>::Method<T2>::doit,       \
-                     __VA_ARGS__);                                             \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::invoke<T1>::Method<T2>::record,   \
+                       __VA_ARGS__);                                           \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::invoke<T1>::Method<T2>::replay(            \
+            _recorder, *_deserializer, _data.GetRegistry(),                    \
+            LLVM_PRETTY_FUNCTION);                                             \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...)              \
@@ -207,17 +215,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;
   }
 
   /// Get all objects sorted by their index.
@@ -289,20 +299,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.
@@ -414,7 +424,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));
   }
@@ -429,6 +443,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();
@@ -490,15 +508,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 CheckID(unsigned expected, unsigned actual);
+
 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;
@@ -507,50 +529,6 @@
   std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids;
 };
 
-/// To be used as the "Runtime ID" of a constructor. It also invokes the
-/// constructor when called.
-template <typename Signature> struct construct;
-template <typename Class, typename... Args> struct construct<Class(Args...)> {
-  static Class *doit(Args... args) { return new Class(args...); }
-};
-
-/// To be used as the "Runtime ID" of a member function. It also invokes the
-/// member function when called.
-template <typename Signature> struct invoke;
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...)> {
-  template <Result (Class::*m)(Args...)> struct method {
-    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
-  };
-};
-
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...) const> {
-  template <Result (Class::*m)(Args...) const> struct method_const {
-    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
-  };
-};
-
-template <typename Result, typename... Args>
-struct invoke<Result (*)(Args...)> {
-  template <Result (*m)(Args...)> struct method_static {
-    static Result doit(Args... args) { return (*m)(args...); }
-  };
-};
-
-template <typename... Args> struct invoke<void (*)(Args...)> {
-  template <void (*m)(Args...)> struct method_static {
-    static void doit(Args... args) { return (*m)(args...); }
-  };
-};
-
-template <typename Class, typename... Args>
-struct invoke<void (Class::*)(Args...)> {
-  template <void (Class::*m)(Args...)> struct method {
-    static void doit(Class *c, Args... args) { (c->*m)(args...); }
-  };
-};
-
 /// Maps an object to an index for serialization. Indices are unique and
 /// incremented for every new object.
 ///
@@ -663,17 +641,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;
 };
 
@@ -779,14 +767,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 << " ("
@@ -810,11 +806,157 @@
   static bool g_global_boundary;
 };
 
+/// To be used as the "Runtime ID" of a constructor. It also invokes the
+/// constructor when called.
+template <typename Signature> struct construct;
+template <typename Class, typename... Args> struct construct<Class(Args...)> {
+  static Class *handle(lldb_private::repro::InstrumentationData data,
+                       lldb_private::repro::Recorder &recorder,
+                       llvm::StringRef signature, Class *c, Args... args) {
+    if (!data)
+      return nullptr;
+
+    if (Serializer *serializer = data.GetSerializer()) {
+      recorder.Record(*serializer, data.GetRegistry(),
+                      &lldb_private::repro::construct<Class(Args...)>::record,
+                      args...);
+      recorder.RecordResult(c, false);
+    } else if (Deserializer *deserializer = data.GetDeserializer()) {
+      if (recorder.ShouldCapture()) {
+        lldb_private::repro::construct<Class(Args...)>::replay(
+            recorder, *deserializer, data.GetRegistry(), signature);
+      }
+    }
+
+    return nullptr;
+  }
+
+  static Class *record(Args... args) { return new Class(args...); }
+
+  static Class *replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+    unsigned actual_id = registry.GetID(uintptr_t(&record));
+    unsigned id = deserializer.Deserialize<unsigned>();
+    registry.CheckID(id, actual_id);
+    return recorder.ReplayResult(
+        static_cast<DefaultReplayer<Class *(Args...)> *>(
+            registry.GetReplayer(id))
+            ->Replay(deserializer),
+        false);
+  }
+};
+
+/// To be used as the "Runtime ID" of a member function. It also invokes the
+/// member function when called.
+template <typename Signature> struct invoke;
+template <typename Result, typename Class, typename... Args>
+struct invoke<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {
+    static Result record(Class *c, Args... args) { return (c->*m)(args...); }
+
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Class *, Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct invoke<void (Class::*)(Args...)> {
+  template <void (Class::*m)(Args...)> struct method {
+    static void record(Class *c, Args... args) { (c->*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_id);
+      registry.GetReplayer(id)->operator()(deserializer);
+    }
+  };
+};
+
+template <typename Result, typename Class, typename... Args>
+struct invoke<Result (Class::*)(Args...) const> {
+  template <Result (Class::*m)(Args...) const> struct method_const {
+    static Result record(Class *c, Args... args) { return (c->*m)(args...); }
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Class *, Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct invoke<void (Class::*)(Args...) const> {
+  template <void (Class::*m)(Args...) const> struct method_const {
+    static void record(Class *c, Args... args) { return (c->*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_id);
+      registry.GetReplayer(id)->operator()(deserializer);
+    }
+  };
+};
+
+template <typename Signature> struct replay;
+
+template <typename Result, typename Class, typename... Args>
+struct replay<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {};
+};
+
+template <typename Result, typename... Args>
+struct invoke<Result (*)(Args...)> {
+  template <Result (*m)(Args...)> struct method_static {
+    static Result record(Args... args) { return (*m)(args...); }
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_id);
+      return recorder.ReplayResult<Result>(
+          static_cast<DefaultReplayer<Result(Args...)> *>(
+              registry.GetReplayer(id))
+              ->Replay(deserializer),
+          true);
+    }
+  };
+};
+
+template <typename... Args> struct invoke<void (*)(Args...)> {
+  template <void (*m)(Args...)> struct method_static {
+    static void record(Args... args) { return (*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry, llvm::StringRef signature) {
+      unsigned actual_id = registry.GetID(uintptr_t(&record));
+      unsigned id = deserializer.Deserialize<unsigned>();
+      registry.CheckID(id, actual_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> {
   template <Result (Class::*m)(char *, size_t) const> struct method_const {
-    static Result doit(Class *c, char *s, size_t l) {
+    static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
@@ -823,17 +965,16 @@
 template <typename Result, typename Class>
 struct char_ptr_redirect<Result (Class::*)(char *, size_t)> {
   template <Result (Class::*m)(char *, size_t)> struct method {
-    static Result doit(Class *c, char *s, size_t l) {
+    static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
   };
 };
-
 template <typename Result>
 struct char_ptr_redirect<Result (*)(char *, size_t)> {
   template <Result (*m)(char *, size_t)> struct method_static {
-    static Result doit(char *s, size_t l) {
+    static Result record(char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (*m)(buffer, l);
     }
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 SetPassiveReplay(bool b) { m_passive_replay = b; }
+
+  bool IsPassiveReplay() const { return m_passive_replay; }
+
 private:
   bool HasFile(llvm::StringRef file);
 
   FileSpec m_root;
   std::vector<std::string> m_files;
   bool m_loaded;
+  bool m_passive_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