Reactor: Fix all memory leaks with rr::DebugInfo.

DebugInfo::NotifyObjectEmitted and NotifyFreeingObject
have become statics as the free-object callback happens
after the DebugInfo instance is destroyed. This isn't
an issue as the JITEventListener is a singleton in LLVM.

Bug: b/133399620
Change-Id: I93fa73d0e416ba3c09c6550cc0d3abd56354e862
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31837
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 55865a8..171f9b1 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -643,18 +643,12 @@
 				ObjLayer::NotifyLoadedFtor(),
 				[](llvm::orc::VModuleKey, const llvm::object::ObjectFile &Obj, const llvm::RuntimeDyld::LoadedObjectInfo &L) {
 #ifdef ENABLE_RR_DEBUG_INFO
-					if (debugInfo != nullptr)
-					{
-						debugInfo->NotifyObjectEmitted(Obj, L);
-					}
+					DebugInfo::NotifyObjectEmitted(Obj, L);
 #endif // ENABLE_RR_DEBUG_INFO
 				},
 				[](llvm::orc::VModuleKey, const llvm::object::ObjectFile &Obj) {
 #ifdef ENABLE_RR_DEBUG_INFO
-					if (debugInfo != nullptr)
-					{
-						debugInfo->NotifyFreeingObject(Obj);
-					}
+					DebugInfo::NotifyFreeingObject(Obj);
 #endif // ENABLE_RR_DEBUG_INFO
 				}
 	  		),
@@ -963,6 +957,10 @@
 
 	Nucleus::~Nucleus()
 	{
+#ifdef ENABLE_RR_DEBUG_INFO
+		debugInfo.reset(nullptr);
+#endif // ENABLE_RR_DEBUG_INFO
+
 		::reactorJIT->endSession();
 
 		::codegenMutex.unlock();
diff --git a/src/Reactor/LLVMReactorDebugInfo.cpp b/src/Reactor/LLVMReactorDebugInfo.cpp
index d021a5f..744ae42 100644
--- a/src/Reactor/LLVMReactorDebugInfo.cpp
+++ b/src/Reactor/LLVMReactorDebugInfo.cpp
@@ -29,6 +29,7 @@
 
 #include <cctype>
 #include <fstream>
+#include <mutex>
 #include <regex>
 #include <sstream>
 #include <string>
@@ -45,6 +46,12 @@
 	{
 		return llvm::StringRef(path).rsplit('/');
 	}
+
+	// Note: createGDBRegistrationListener() returns a pointer to a singleton.
+	// Nothing is actually created.
+	auto jitEventListener = llvm::JITEventListener::createGDBRegistrationListener(); // guarded by jitEventListenerMutex
+	std::mutex jitEventListenerMutex;
+
 } // anonymous namespaces
 
 namespace rr
@@ -61,14 +68,13 @@
 		auto location = getCallerLocation();
 
 		auto fileAndDir = splitPath(location.function.file.c_str());
-		diBuilder = new llvm::DIBuilder(*module);
+		diBuilder.reset(new llvm::DIBuilder(*module));
 		diCU = diBuilder->createCompileUnit(
 			llvm::dwarf::DW_LANG_C,
 			diBuilder->createFile(fileAndDir.first, fileAndDir.second),
 			"Reactor",
 			0, "", 0);
 
-		jitEventListener = llvm::JITEventListener::createGDBRegistrationListener();
 		registerBasicTypes();
 
 		SmallVector<Metadata *, 8> EltTys;
@@ -94,11 +100,13 @@
 		builder->SetCurrentDebugLocation(diRootLocation);
 	}
 
+	DebugInfo::~DebugInfo() = default;
+
 	void DebugInfo::Finalize()
 	{
 		while (diScope.size() > 0)
 		{
-			emitPending(diScope.back(), builder, diBuilder);
+			emitPending(diScope.back(), builder);
 			diScope.pop_back();
 		}
 		diBuilder->finalize();
@@ -127,7 +135,7 @@
 
 	void DebugInfo::Flush()
 	{
-		emitPending(diScope.back(), builder, diBuilder);
+		emitPending(diScope.back(), builder);
 	}
 
 	void DebugInfo::syncScope(Backtrace const& backtrace)
@@ -141,7 +149,7 @@
 					int(diScope.size() - 1), scope.di,
 					scope.location.function.file.c_str(),
 					int(scope.location.line));
-				emitPending(scope, builder, diBuilder);
+				emitPending(scope, builder);
 				diScope.pop_back();
 			}
 		};
@@ -172,7 +180,7 @@
 				auto di = diBuilder->createLexicalBlock(scope.di, file, newLocation.line, 0);
 				LOG("  STACK(%d): Jumped backwards %d -> %d. di: %p -> %p", int(i),
 					oldLocation.line, newLocation.line, scope.di, di);
-				emitPending(scope, builder, diBuilder);
+				emitPending(scope, builder);
 				scope = {newLocation, di};
 				shrink(i+1);
 				break;
@@ -263,7 +271,7 @@
 			auto &scope = diScope[i];
 			if (scope.pending.location != location)
 			{
-				emitPending(scope, builder, diBuilder);
+				emitPending(scope, builder);
 			}
 
 			auto value = V(variable);
@@ -297,7 +305,7 @@
 		}
 	}
 
-	void DebugInfo::emitPending(Scope &scope, IRBuilder *builder, llvm::DIBuilder *diBuilder)
+	void DebugInfo::emitPending(Scope &scope, IRBuilder *builder)
 	{
 		auto const &pending = scope.pending;
 		if (pending.value == nullptr)
@@ -373,11 +381,13 @@
 
 	void DebugInfo::NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L)
 	{
+		std::unique_lock<std::mutex> lock(jitEventListenerMutex);
 		jitEventListener->NotifyObjectEmitted(Obj, static_cast<const llvm::RuntimeDyld::LoadedObjectInfo&>(L));
 	}
 
 	void DebugInfo::NotifyFreeingObject(const llvm::object::ObjectFile &Obj)
 	{
+		std::unique_lock<std::mutex> lock(jitEventListenerMutex);
 		jitEventListener->NotifyFreeingObject(Obj);
 	}
 
diff --git a/src/Reactor/LLVMReactorDebugInfo.hpp b/src/Reactor/LLVMReactorDebugInfo.hpp
index d8c83de..db743d7 100644
--- a/src/Reactor/LLVMReactorDebugInfo.hpp
+++ b/src/Reactor/LLVMReactorDebugInfo.hpp
@@ -71,6 +71,8 @@
 				llvm::Module *module,
 				llvm::Function *function);
 
+		~DebugInfo();
+
 		// Finalize debug info generation. Must be called before the LLVM module
 		// is built.
 		void Finalize();
@@ -88,11 +90,11 @@
 
 		// NotifyObjectEmitted informs any attached debuggers of the JIT'd
 		// object.
-		void NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L);
+		static void NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L);
 
 		// NotifyFreeingObject informs any attached debuggers that the JIT'd
 		// object is now invalid.
-		void NotifyFreeingObject(const llvm::object::ObjectFile &Obj);
+		static void NotifyFreeingObject(const llvm::object::ObjectFile &Obj);
 
 	private:
 		struct Token
@@ -168,7 +170,7 @@
 
 		void registerBasicTypes();
 
-		void emitPending(Scope &scope, IRBuilder *builder, llvm::DIBuilder *diBuilder);
+		void emitPending(Scope &scope, IRBuilder *builder);
 
 		// Returns the source location of the non-Reactor calling function.
 		Location getCallerLocation() const;
@@ -192,7 +194,7 @@
 		llvm::Module *module;
 		llvm::Function *function;
 
-		llvm::DIBuilder *diBuilder;
+		std::unique_ptr<llvm::DIBuilder> diBuilder;
 		llvm::DICompileUnit *diCU;
 		llvm::DISubprogram *diSubprogram;
 		llvm::DILocation *diRootLocation;
@@ -200,7 +202,6 @@
 		std::unordered_map<std::string, llvm::DIFile*> diFiles;
 		std::unordered_map<llvm::Type*, llvm::DIType*> diTypes;
 		std::unordered_map<std::string, std::unique_ptr<LineTokens>> fileTokens;
-		llvm::JITEventListener *jitEventListener;
 		std::vector<void const*> pushed;
 	};