[ORC][ORC-RT][MachO] Reset __data and __common sections on library close.

If we want to be able to close and then re-open a library then we need to reset
the data section states when the library is closed. This commit updates
MachOPlatform and the ORC runtime to track __data and __common sections, and
reset the state in MachOPlatformRuntimeState::dlcloseDeinitialize.

This is only a first step to full support -- there are other data sections that
we're not capturing, and we'll probably want a more efficient representation
for the sections (rather than passing their string name over IPC), but this is
a reasonable first step.

This commit also contains a fix to MapperJITLinkMemoryManager that prevents it
from calling OnDeallocated twice in the case of an error.

GitOrigin-RevId: 47e9e588083493414d0abfbe33fe3566879c219b
diff --git a/lib/orc/macho_platform.cpp b/lib/orc/macho_platform.cpp
index 7c70999..f17230c 100644
--- a/lib/orc/macho_platform.cpp
+++ b/lib/orc/macho_platform.cpp
@@ -137,6 +137,8 @@
     std::vector<JITDylibState *> Deps;
     AtExitsVector AtExits;
     const objc_image_info *ObjCImageInfo = nullptr;
+    std::unordered_map<void *, std::vector<char>> DataSectionContent;
+    std::unordered_map<void *, size_t> ZeroInitRanges;
     std::vector<span<void (*)()>> ModInitsSections;
     std::vector<span<void (*)()>> ModInitsSectionsNew;
     std::vector<span<uintptr_t>> ObjCClassListSections;
@@ -340,7 +342,17 @@
 
   for (auto &KV : Secs) {
     // FIXME: Validate section ranges?
-    if (KV.first == "__DATA,__thread_data") {
+    if (KV.first == "__DATA,__data") {
+      assert(!JDS->DataSectionContent.count(KV.second.Start.toPtr<char *>()) &&
+             "Address already registered.");
+      auto S = KV.second.toSpan<char>();
+      JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
+          std::vector<char>(S.begin(), S.end());
+    } else if (KV.first == "__DATA,__common") {
+      // fprintf(stderr, "Adding zero-init range %llx -- %llx\n",
+      // KV.second.Start.getValue(), KV.second.size());
+      JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
+    } else if (KV.first == "__DATA,__thread_data") {
       if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
         return Err;
     } else if (KV.first == "__DATA,__objc_selrefs")
@@ -406,9 +418,17 @@
   // FIXME: Implement faster-path by returning immediately if JDS is being
   // torn down entirely?
 
+  // TODO: Make library permanent (i.e. not able to be dlclosed) if it contains
+  // any Swift or ObjC. Once this happens we can clear (and no longer record)
+  // data section content, as the library could never be re-initialized.
+
   for (auto &KV : Secs) {
     // FIXME: Validate section ranges?
-    if (KV.first == "__DATA,__thread_data") {
+    if (KV.first == "__DATA,__data") {
+      JDS->DataSectionContent.erase(KV.second.Start.toPtr<char *>());
+    } else if (KV.first == "__DATA,__common") {
+      JDS->ZeroInitRanges.erase(KV.second.Start.toPtr<char *>());
+    } else if (KV.first == "__DATA,__thread_data") {
       if (auto Err =
               deregisterThreadDataSection(KV.second.toSpan<const char>()))
         return Err;
@@ -874,6 +894,12 @@
   moveAppendSections(JDS.ModInitsSections, JDS.ModInitsSectionsNew);
   JDS.ModInitsSectionsNew = std::move(JDS.ModInitsSections);
 
+  // Reset data section contents.
+  for (auto &KV : JDS.DataSectionContent)
+    memcpy(KV.first, KV.second.data(), KV.second.size());
+  for (auto &KV : JDS.ZeroInitRanges)
+    memset(KV.first, 0, KV.second);
+
   // Deinitialize any dependencies.
   for (auto *DepJDS : JDS.Deps) {
     --DepJDS->LinkedAgainstRefCount;
diff --git a/test/orc/TestCases/Darwin/x86-64/jit-re-dlopen-data-reset.S b/test/orc/TestCases/Darwin/x86-64/jit-re-dlopen-data-reset.S
new file mode 100644
index 0000000..8582c9e
--- /dev/null
+++ b/test/orc/TestCases/Darwin/x86-64/jit-re-dlopen-data-reset.S
@@ -0,0 +1,46 @@
+// Test that __orc_rt_macho_jit_dlopen resets the state of the data sections.
+//
+// RUN: %clang -c -o %t.main.o %p/Inputs/dlopen-dlclose-x2.S
+// RUN: %clang -c -o %t.inits.o %s
+// RUN: %llvm_jitlink \
+// RUN:   -alias _dlopen=___orc_rt_macho_jit_dlopen \
+// RUN:   -alias _dlclose=___orc_rt_macho_jit_dlclose \
+// RUN:   %t.main.o -jd inits %t.inits.o -lmain | FileCheck %s
+
+// CHECK: entering main
+// CHECK-NEXT: X = 1, Y = 2
+// CHECK-NEXT: X = 1, Y = 2
+// CHECK-NEXT: leaving main
+
+	.section	__TEXT,__text,regular,pure_instructions
+	.build_version macos, 13, 0	sdk_version 13, 0
+	.section	__TEXT,__StaticInit,regular,pure_instructions
+	.p2align	4, 0x90
+_initializer:
+	movq	_X(%rip), %rsi
+	addq	$1, %rsi
+	movq	%rsi, _X(%rip)
+	movq	_Y(%rip), %rdx
+	addq	$1, %rdx
+	movq	%rdx, _Y(%rip)
+	leaq	L_.str(%rip), %rdi
+	xorl	%eax, %eax
+	jmp	_printf
+
+	.section	__TEXT,__cstring,cstring_literals
+L_.str:
+	.asciz	"X = %zu, Y = %zu\n"
+
+	.globl	_X                              ## @X
+.zerofill __DATA,__common,_X,8,3
+	.section	__DATA,__data
+	.globl	_Y                              ## @Y
+	.p2align	3
+_Y:
+	.quad	1                               ## 0x1
+
+	.section	__DATA,__mod_init_func,mod_init_funcs
+	.p2align	3
+	.quad	_initializer
+
+.subsections_via_symbols