xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp (revision 56c72c7f339cd6ff780a0d6aa1a0ac8bfc1487aa)
1 //===----- SymbolStringPoolTest.cpp - Unit tests for SymbolStringPool -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
10 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
11 #include "gtest/gtest.h"
12 
13 using namespace llvm;
14 using namespace llvm::orc;
15 
16 namespace llvm::orc {
17 
18 class SymbolStringPoolTest : public testing::Test {
19 public:
getRefCount(const SymbolStringPtrBase & S) const20   size_t getRefCount(const SymbolStringPtrBase &S) const {
21     return SP.getRefCount(S);
22   }
23 
24 protected:
25   SymbolStringPool SP;
26 };
27 } // namespace llvm::orc
28 
29 namespace {
30 
TEST_F(SymbolStringPoolTest,UniquingAndComparisons)31 TEST_F(SymbolStringPoolTest, UniquingAndComparisons) {
32   auto P1 = SP.intern("hello");
33 
34   std::string S("hel");
35   S += "lo";
36   auto P2 = SP.intern(S);
37 
38   auto P3 = SP.intern("goodbye");
39 
40   EXPECT_EQ(P1, P2) << "Failed to unique entries";
41   EXPECT_NE(P1, P3) << "Unequal pooled symbol strings comparing equal";
42 
43   // We want to test that less-than comparison of SymbolStringPtrs compiles,
44   // however we can't test the actual result as this is a pointer comparison and
45   // SymbolStringPtr doesn't expose the underlying address of the string.
46   (void)(P1 < P3);
47 }
48 
TEST_F(SymbolStringPoolTest,Dereference)49 TEST_F(SymbolStringPoolTest, Dereference) {
50   auto Foo = SP.intern("foo");
51   EXPECT_EQ(*Foo, "foo") << "Equality on dereferenced string failed";
52 }
53 
TEST_F(SymbolStringPoolTest,ClearDeadEntries)54 TEST_F(SymbolStringPoolTest, ClearDeadEntries) {
55   {
56     auto P1 = SP.intern("s1");
57     SP.clearDeadEntries();
58     EXPECT_FALSE(SP.empty()) << "\"s1\" entry in pool should still be retained";
59   }
60   SP.clearDeadEntries();
61   EXPECT_TRUE(SP.empty()) << "pool should be empty";
62 }
63 
TEST_F(SymbolStringPoolTest,DebugDump)64 TEST_F(SymbolStringPoolTest, DebugDump) {
65   auto A1 = SP.intern("a");
66   auto A2 = A1;
67   auto B = SP.intern("b");
68 
69   std::string DumpString;
70   raw_string_ostream(DumpString) << SP;
71 
72   EXPECT_EQ(DumpString, "a: 2\nb: 1\n");
73 }
74 
TEST_F(SymbolStringPoolTest,NonOwningPointerBasics)75 TEST_F(SymbolStringPoolTest, NonOwningPointerBasics) {
76   auto A = SP.intern("a");
77   auto B = SP.intern("b");
78 
79   NonOwningSymbolStringPtr ANP1(A);    // Constuct from SymbolStringPtr.
80   NonOwningSymbolStringPtr ANP2(ANP1); // Copy-construct.
81   NonOwningSymbolStringPtr BNP(B);
82 
83   // Equality comparisons.
84   EXPECT_EQ(A, ANP1);
85   EXPECT_EQ(ANP1, ANP2);
86   EXPECT_NE(ANP1, BNP);
87 
88   EXPECT_EQ(*ANP1, "a"); // Dereference.
89 
90   // Assignment.
91   ANP2 = ANP1;
92   ANP2 = A;
93 
94   SymbolStringPtr S(ANP1); // Construct SymbolStringPtr from non-owning.
95   EXPECT_EQ(S, A);
96 
97   DenseMap<SymbolStringPtr, int> M;
98   M[A] = 42;
99   EXPECT_EQ(M.find_as(ANP1)->second, 42);
100   EXPECT_EQ(M.find_as(BNP), M.end());
101 }
102 
TEST_F(SymbolStringPoolTest,NonOwningPointerRefCounts)103 TEST_F(SymbolStringPoolTest, NonOwningPointerRefCounts) {
104   // Check that creating and destroying non-owning pointers doesn't affect
105   // ref-counts.
106   auto A = SP.intern("a");
107   EXPECT_EQ(getRefCount(A), 1U);
108 
109   NonOwningSymbolStringPtr ANP(A);
110   EXPECT_EQ(getRefCount(ANP), 1U)
111       << "Construction of NonOwningSymbolStringPtr from SymbolStringPtr "
112          "changed ref-count";
113 
114   {
115     NonOwningSymbolStringPtr ANP2(ANP);
116     EXPECT_EQ(getRefCount(ANP2), 1U)
117         << "Copy-construction of NonOwningSymbolStringPtr changed ref-count";
118   }
119 
120   EXPECT_EQ(getRefCount(ANP), 1U)
121       << "Destruction of NonOwningSymbolStringPtr changed ref-count";
122 
123   {
124     NonOwningSymbolStringPtr ANP2;
125     ANP2 = ANP;
126     EXPECT_EQ(getRefCount(ANP2), 1U)
127         << "Copy-assignment of NonOwningSymbolStringPtr changed ref-count";
128   }
129 
130   {
131     NonOwningSymbolStringPtr ANP2(ANP);
132     NonOwningSymbolStringPtr ANP3(std::move(ANP2));
133     EXPECT_EQ(getRefCount(ANP3), 1U)
134         << "Move-construction of NonOwningSymbolStringPtr changed ref-count";
135   }
136 
137   {
138     NonOwningSymbolStringPtr ANP2(ANP);
139     NonOwningSymbolStringPtr ANP3;
140     ANP3 = std::move(ANP2);
141     EXPECT_EQ(getRefCount(ANP3), 1U)
142         << "Copy-assignment of NonOwningSymbolStringPtr changed ref-count";
143   }
144 }
145 
TEST_F(SymbolStringPoolTest,SymbolStringPoolEntryUnsafe)146 TEST_F(SymbolStringPoolTest, SymbolStringPoolEntryUnsafe) {
147 
148   auto A = SP.intern("a");
149   EXPECT_EQ(getRefCount(A), 1U);
150 
151   {
152     // Try creating an unsafe pool entry ref from the given SymbolStringPtr.
153     // This should not affect the ref-count.
154     auto AUnsafe = SymbolStringPoolEntryUnsafe::from(A);
155     EXPECT_EQ(getRefCount(A), 1U);
156 
157     // Create a new SymbolStringPtr from the unsafe ref. This should increment
158     // the ref-count.
159     auto ACopy = AUnsafe.copyToSymbolStringPtr();
160     EXPECT_EQ(getRefCount(A), 2U);
161   }
162 
163   {
164     // Create a copy of the original string. Move it into an unsafe ref, and
165     // then move it back. None of these operations should affect the ref-count.
166     auto ACopy = A;
167     EXPECT_EQ(getRefCount(A), 2U);
168     auto AUnsafe = SymbolStringPoolEntryUnsafe::take(std::move(ACopy));
169     EXPECT_EQ(getRefCount(A), 2U);
170     ACopy = AUnsafe.moveToSymbolStringPtr();
171     EXPECT_EQ(getRefCount(A), 2U);
172   }
173 
174   // Test manual retain / release.
175   auto AUnsafe = SymbolStringPoolEntryUnsafe::from(A);
176   EXPECT_EQ(getRefCount(A), 1U);
177   AUnsafe.retain();
178   EXPECT_EQ(getRefCount(A), 2U);
179   AUnsafe.release();
180   EXPECT_EQ(getRefCount(A), 1U);
181 }
182 
183 } // namespace
184