194 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"10#include "llvm/ExecutionEngine/Orc/DebugUtils.h"11#include "gtest/gtest.h"12 13using namespace llvm;14using namespace llvm::orc;15 16namespace llvm::orc {17 18class SymbolStringPoolTest : public testing::Test {19public:20 size_t getRefCount(const SymbolStringPtrBase &S) const {21 return SP.getRefCount(S);22 }23 24protected:25 SymbolStringPool SP;26};27} // namespace llvm::orc28 29namespace {30 31TEST_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 and45 // SymbolStringPtr doesn't expose the underlying address of the string.46 (void)(P1 < P3);47}48 49TEST_F(SymbolStringPoolTest, Dereference) {50 auto Foo = SP.intern("foo");51 EXPECT_EQ(*Foo, "foo") << "Equality on dereferenced string failed";52}53 54TEST_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 64TEST_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 75TEST_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 103TEST_F(SymbolStringPoolTest, NonOwningPointerRefCounts) {104 // Check that creating and destroying non-owning pointers doesn't affect105 // 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 146TEST_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 increment158 // 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, and165 // 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 183TEST_F(SymbolStringPoolTest, Hashing) {184 auto A = SP.intern("a");185 auto B = NonOwningSymbolStringPtr(A);186 187 hash_code AHash = hash_value(A);188 hash_code BHash = hash_value(B);189 190 EXPECT_EQ(AHash, BHash);191}192 193} // namespace194