[JITLink] Add convenience methods for creating block readers / writers.
authorLang Hames <lhames@gmail.com>
Tue, 18 Oct 2022 17:53:25 +0000 (10:53 -0700)
committerLang Hames <lhames@gmail.com>
Tue, 18 Oct 2022 23:25:47 +0000 (16:25 -0700)
This saves clients some boilerplate compared to setting up the readers and
writers manually.

To obtain a BinaryStreamWriter / BinaryStreamReader for a given block, B,
clients can now write:

auto Reader = G.getBlockContentReader(B);

and

auto Writer = G.getBlockContentWriter(B);

The latter will trigger a copy to mutable memory allocated on the graph's
allocator if the block is currently marked as backed by read-only memory.

This commit also introduces a new createMutableContentBlock overload that
creates a block with a given size and zero-filled content (by default --
passing false for the ZeroInitialize bypasses initialization entirely).
This overload is intended to be used with getBlockContentWriter above when
creating new content for the graph.

llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp

index 7f8dd73..f6e7706 100644 (file)
@@ -22,6 +22,8 @@
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -1031,6 +1033,20 @@ public:
                        AlignmentOffset);
   }
 
+  /// Create a content block with initially mutable data of the given size.
+  /// Content will be allocated via the LinkGraph's allocateBuffer method.
+  /// By default the memory will be zero-initialized. Passing false for
+  /// ZeroInitialize will prevent this.
+  Block &createMutableContentBlock(Section &Parent, size_t ContentSize,
+                                   orc::ExecutorAddr Address,
+                                   uint64_t Alignment, uint64_t AlignmentOffset,
+                                   bool ZeroInitialize = true) {
+    auto Content = allocateContent(ContentSize);
+    if (ZeroInitialize)
+      memset(Content.data(), 0, Content.size());
+    return createBlock(Parent, Content, Address, Alignment, AlignmentOffset);
+  }
+
   /// Create a zero-fill block.
   Block &createZeroFillBlock(Section &Parent, orc::ExecutorAddrDiff Size,
                              orc::ExecutorAddr Address, uint64_t Alignment,
@@ -1038,6 +1054,22 @@ public:
     return createBlock(Parent, Size, Address, Alignment, AlignmentOffset);
   }
 
+  /// Returns a BinaryStreamReader for the given block.
+  BinaryStreamReader getBlockContentReader(Block &B) {
+    ArrayRef<uint8_t> C(
+        reinterpret_cast<const uint8_t *>(B.getContent().data()), B.getSize());
+    return BinaryStreamReader(C, getEndianness());
+  }
+
+  /// Returns a BinaryStreamWriter for the given block.
+  /// This will call getMutableContent to obtain mutable content for the block.
+  BinaryStreamWriter getBlockContentWriter(Block &B) {
+    MutableArrayRef<uint8_t> C(
+        reinterpret_cast<uint8_t *>(B.getMutableContent(*this).data()),
+        B.getSize());
+    return BinaryStreamWriter(C, getEndianness());
+  }
+
   /// Cache type for the splitBlock function.
   using SplitBlockCache = Optional<SmallVector<Symbol *, 8>>;
 
index bbb93ce..c16757d 100644 (file)
@@ -10,6 +10,8 @@
 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Memory.h"
+
+#include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -196,6 +198,16 @@ TEST(LinkGraphTest, ContentAccessAndUpdate) {
   EXPECT_EQ(MutableContent3.size(), MutableContent.size())
       << "Unexpected mutable content 2 size";
 
+  // Check that we can obtain a writer and reader over the content.
+  // Check that we can get a BinaryStreamReader for B.
+  auto Writer = G.getBlockContentWriter(B);
+  EXPECT_THAT_ERROR(Writer.writeInteger((uint32_t)0xcafef00d), Succeeded());
+
+  auto Reader = G.getBlockContentReader(B);
+  uint32_t Initial32Bits = 0;
+  EXPECT_THAT_ERROR(Reader.readInteger(Initial32Bits), Succeeded());
+  EXPECT_EQ(Initial32Bits, (uint32_t)0xcafef00d);
+
   // Set content back to immutable and check that everything behaves as
   // expected again.
   B.setContent(BlockContent);