You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
@ -1,15 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
DebugInfoCodeView
|
||||
)
|
||||
|
||||
set(DebugInfoCodeViewSources
|
||||
RandomAccessVisitorTest.cpp
|
||||
TypeHashingTest.cpp
|
||||
TypeIndexDiscoveryTest.cpp
|
||||
)
|
||||
|
||||
add_llvm_unittest(DebugInfoCodeViewTests
|
||||
${DebugInfoCodeViewSources}
|
||||
)
|
||||
|
||||
target_link_libraries(DebugInfoCodeViewTests PRIVATE LLVMTestingSupport)
|
@ -1,402 +0,0 @@
|
||||
//===- llvm/unittest/DebugInfo/CodeView/RandomAccessVisitorTest.cpp -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryItemStream.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
inline bool operator==(const ArrayRecord &R1, const ArrayRecord &R2) {
|
||||
if (R1.ElementType != R2.ElementType)
|
||||
return false;
|
||||
if (R1.IndexType != R2.IndexType)
|
||||
return false;
|
||||
if (R1.Name != R2.Name)
|
||||
return false;
|
||||
if (R1.Size != R2.Size)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool operator!=(const ArrayRecord &R1, const ArrayRecord &R2) {
|
||||
return !(R1 == R2);
|
||||
}
|
||||
|
||||
inline bool operator==(const CVType &R1, const CVType &R2) {
|
||||
if (R1.Type != R2.Type)
|
||||
return false;
|
||||
if (R1.RecordData != R2.RecordData)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool operator!=(const CVType &R1, const CVType &R2) {
|
||||
return !(R1 == R2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template <> struct BinaryItemTraits<CVType> {
|
||||
static size_t length(const CVType &Item) { return Item.length(); }
|
||||
static ArrayRef<uint8_t> bytes(const CVType &Item) { return Item.data(); }
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class MockCallbacks : public TypeVisitorCallbacks {
|
||||
public:
|
||||
virtual Error visitTypeBegin(CVType &CVR, TypeIndex Index) {
|
||||
Indices.push_back(Index);
|
||||
return Error::success();
|
||||
}
|
||||
virtual Error visitKnownRecord(CVType &CVR, ArrayRecord &AR) {
|
||||
VisitedRecords.push_back(AR);
|
||||
RawRecords.push_back(CVR);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t count() const {
|
||||
assert(Indices.size() == RawRecords.size());
|
||||
assert(Indices.size() == VisitedRecords.size());
|
||||
return Indices.size();
|
||||
}
|
||||
std::vector<TypeIndex> Indices;
|
||||
std::vector<CVType> RawRecords;
|
||||
std::vector<ArrayRecord> VisitedRecords;
|
||||
};
|
||||
|
||||
class RandomAccessVisitorTest : public testing::Test {
|
||||
public:
|
||||
RandomAccessVisitorTest() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
GlobalState = llvm::make_unique<GlobalTestState>();
|
||||
|
||||
AppendingTypeTableBuilder Builder(GlobalState->Allocator);
|
||||
|
||||
uint32_t Offset = 0;
|
||||
for (int I = 0; I < 11; ++I) {
|
||||
ArrayRecord AR(TypeRecordKind::Array);
|
||||
AR.ElementType = TypeIndex::Int32();
|
||||
AR.IndexType = TypeIndex::UInt32();
|
||||
AR.Size = I;
|
||||
std::string Name;
|
||||
raw_string_ostream Stream(Name);
|
||||
Stream << "Array [" << I << "]";
|
||||
AR.Name = GlobalState->Strings.save(Stream.str());
|
||||
GlobalState->Records.push_back(AR);
|
||||
GlobalState->Indices.push_back(Builder.writeLeafType(AR));
|
||||
|
||||
CVType Type(TypeLeafKind::LF_ARRAY, Builder.records().back());
|
||||
GlobalState->TypeVector.push_back(Type);
|
||||
|
||||
GlobalState->AllOffsets.push_back(
|
||||
{GlobalState->Indices.back(), ulittle32_t(Offset)});
|
||||
Offset += Type.length();
|
||||
}
|
||||
|
||||
GlobalState->ItemStream.setItems(GlobalState->TypeVector);
|
||||
GlobalState->TypeArray = VarStreamArray<CVType>(GlobalState->ItemStream);
|
||||
}
|
||||
|
||||
static void TearDownTestCase() { GlobalState.reset(); }
|
||||
|
||||
void SetUp() override {
|
||||
TestState = llvm::make_unique<PerTestState>();
|
||||
}
|
||||
|
||||
void TearDown() override { TestState.reset(); }
|
||||
|
||||
protected:
|
||||
bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(Index);
|
||||
if (!Types.contains(TI))
|
||||
return false;
|
||||
if (GlobalState->TypeVector[Index] != Types.getType(TI))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateVisitedRecord(uint32_t VisitationOrder,
|
||||
uint32_t GlobalArrayIndex) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(GlobalArrayIndex);
|
||||
if (TI != TestState->Callbacks.Indices[VisitationOrder])
|
||||
return false;
|
||||
|
||||
if (GlobalState->TypeVector[TI.toArrayIndex()] !=
|
||||
TestState->Callbacks.RawRecords[VisitationOrder])
|
||||
return false;
|
||||
|
||||
if (GlobalState->Records[TI.toArrayIndex()] !=
|
||||
TestState->Callbacks.VisitedRecords[VisitationOrder])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct GlobalTestState {
|
||||
GlobalTestState() : Strings(Allocator), ItemStream(llvm::support::little) {}
|
||||
|
||||
BumpPtrAllocator Allocator;
|
||||
StringSaver Strings;
|
||||
|
||||
std::vector<ArrayRecord> Records;
|
||||
std::vector<TypeIndex> Indices;
|
||||
std::vector<TypeIndexOffset> AllOffsets;
|
||||
std::vector<CVType> TypeVector;
|
||||
BinaryItemStream<CVType> ItemStream;
|
||||
VarStreamArray<CVType> TypeArray;
|
||||
|
||||
MutableBinaryByteStream Stream;
|
||||
};
|
||||
|
||||
struct PerTestState {
|
||||
FixedStreamArray<TypeIndexOffset> Offsets;
|
||||
|
||||
MockCallbacks Callbacks;
|
||||
};
|
||||
|
||||
FixedStreamArray<TypeIndexOffset>
|
||||
createPartialOffsets(MutableBinaryByteStream &Storage,
|
||||
std::initializer_list<uint32_t> Indices) {
|
||||
|
||||
uint32_t Count = Indices.size();
|
||||
uint32_t Size = Count * sizeof(TypeIndexOffset);
|
||||
uint8_t *Buffer = GlobalState->Allocator.Allocate<uint8_t>(Size);
|
||||
MutableArrayRef<uint8_t> Bytes(Buffer, Size);
|
||||
Storage = MutableBinaryByteStream(Bytes, support::little);
|
||||
BinaryStreamWriter Writer(Storage);
|
||||
for (const auto I : Indices)
|
||||
consumeError(Writer.writeObject(GlobalState->AllOffsets[I]));
|
||||
|
||||
BinaryStreamReader Reader(Storage);
|
||||
FixedStreamArray<TypeIndexOffset> Result;
|
||||
consumeError(Reader.readArray(Result, Count));
|
||||
return Result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<GlobalTestState> GlobalState;
|
||||
std::unique_ptr<PerTestState> TestState;
|
||||
};
|
||||
|
||||
std::unique_ptr<RandomAccessVisitorTest::GlobalTestState>
|
||||
RandomAccessVisitorTest::GlobalState;
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, MultipleVisits) {
|
||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
||||
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||
GlobalState->TypeVector.size(),
|
||||
TestState->Offsets);
|
||||
|
||||
std::vector<uint32_t> IndicesToVisit = {5, 5, 5};
|
||||
|
||||
for (uint32_t I : IndicesToVisit) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
||||
CVType T = Types.getType(TI);
|
||||
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
|
||||
Succeeded());
|
||||
}
|
||||
|
||||
// [0,8) should be present
|
||||
EXPECT_EQ(8u, Types.size());
|
||||
for (uint32_t I = 0; I < 8; ++I)
|
||||
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||
|
||||
// 5, 5, 5
|
||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||
for (auto I : enumerate(IndicesToVisit))
|
||||
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, DescendingWithinChunk) {
|
||||
// Visit multiple items from the same "chunk" in reverse order. In this
|
||||
// example, it's 7 then 4 then 2. At the end, all records from 0 to 7 should
|
||||
// be known by the database, but only 2, 4, and 7 should have been visited.
|
||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
||||
|
||||
std::vector<uint32_t> IndicesToVisit = {7, 4, 2};
|
||||
|
||||
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||
GlobalState->TypeVector.size(),
|
||||
TestState->Offsets);
|
||||
for (uint32_t I : IndicesToVisit) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
||||
CVType T = Types.getType(TI);
|
||||
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
|
||||
Succeeded());
|
||||
}
|
||||
|
||||
// [0, 7]
|
||||
EXPECT_EQ(8u, Types.size());
|
||||
for (uint32_t I = 0; I < 8; ++I)
|
||||
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||
|
||||
// 2, 4, 7
|
||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||
for (auto I : enumerate(IndicesToVisit))
|
||||
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, AscendingWithinChunk) {
|
||||
// * Visit multiple items from the same chunk in ascending order, ensuring
|
||||
// that intermediate items are not visited. In the below example, it's
|
||||
// 5 -> 6 -> 7 which come from the [4,8) chunk.
|
||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
||||
|
||||
std::vector<uint32_t> IndicesToVisit = {2, 4, 7};
|
||||
|
||||
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||
GlobalState->TypeVector.size(),
|
||||
TestState->Offsets);
|
||||
for (uint32_t I : IndicesToVisit) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
||||
CVType T = Types.getType(TI);
|
||||
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
|
||||
Succeeded());
|
||||
}
|
||||
|
||||
// [0, 7]
|
||||
EXPECT_EQ(8u, Types.size());
|
||||
for (uint32_t I = 0; I < 8; ++I)
|
||||
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||
|
||||
// 2, 4, 7
|
||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||
for (auto &I : enumerate(IndicesToVisit))
|
||||
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, StopPrematurelyInChunk) {
|
||||
// * Don't visit the last item in one chunk, ensuring that visitation stops
|
||||
// at the record you specify, and the chunk is only partially visited.
|
||||
// In the below example, this is tested by visiting 0 and 1 but not 2,
|
||||
// all from the [0,3) chunk.
|
||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
||||
|
||||
std::vector<uint32_t> IndicesToVisit = {0, 1, 2};
|
||||
|
||||
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||
GlobalState->TypeVector.size(),
|
||||
TestState->Offsets);
|
||||
|
||||
for (uint32_t I : IndicesToVisit) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
||||
CVType T = Types.getType(TI);
|
||||
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
|
||||
Succeeded());
|
||||
}
|
||||
|
||||
// [0, 8) should be visited.
|
||||
EXPECT_EQ(8u, Types.size());
|
||||
for (uint32_t I = 0; I < 8; ++I)
|
||||
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||
|
||||
// [0, 2]
|
||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||
for (auto I : enumerate(IndicesToVisit))
|
||||
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, InnerChunk) {
|
||||
// Test that when a request comes from a chunk in the middle of the partial
|
||||
// offsets array, that items from surrounding chunks are not visited or
|
||||
// added to the database.
|
||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 4, 9});
|
||||
|
||||
std::vector<uint32_t> IndicesToVisit = {5, 7};
|
||||
|
||||
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||
GlobalState->TypeVector.size(),
|
||||
TestState->Offsets);
|
||||
|
||||
for (uint32_t I : IndicesToVisit) {
|
||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
||||
CVType T = Types.getType(TI);
|
||||
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
|
||||
Succeeded());
|
||||
}
|
||||
|
||||
// [4, 9)
|
||||
EXPECT_EQ(5u, Types.size());
|
||||
for (uint32_t I = 4; I < 9; ++I)
|
||||
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||
|
||||
// 5, 7
|
||||
EXPECT_EQ(2u, TestState->Callbacks.count());
|
||||
for (auto &I : enumerate(IndicesToVisit))
|
||||
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
|
||||
}
|
||||
|
||||
TEST_F(RandomAccessVisitorTest, CrossChunkName) {
|
||||
AppendingTypeTableBuilder Builder(GlobalState->Allocator);
|
||||
|
||||
// TypeIndex 0
|
||||
ClassRecord Class(TypeRecordKind::Class);
|
||||
Class.Name = "FooClass";
|
||||
Class.Options = ClassOptions::None;
|
||||
Class.MemberCount = 0;
|
||||
Class.Size = 4U;
|
||||
Class.DerivationList = TypeIndex::fromArrayIndex(0);
|
||||
Class.FieldList = TypeIndex::fromArrayIndex(0);
|
||||
Class.VTableShape = TypeIndex::fromArrayIndex(0);
|
||||
TypeIndex IndexZero = Builder.writeLeafType(Class);
|
||||
|
||||
// TypeIndex 1 refers to type index 0.
|
||||
ModifierRecord Modifier(TypeRecordKind::Modifier);
|
||||
Modifier.ModifiedType = TypeIndex::fromArrayIndex(0);
|
||||
Modifier.Modifiers = ModifierOptions::Const;
|
||||
TypeIndex IndexOne = Builder.writeLeafType(Modifier);
|
||||
|
||||
// set up a type stream that refers to the above two serialized records.
|
||||
std::vector<CVType> TypeArray;
|
||||
TypeArray.push_back(
|
||||
CVType(static_cast<TypeLeafKind>(Class.Kind), Builder.records()[0]));
|
||||
TypeArray.push_back(
|
||||
CVType(static_cast<TypeLeafKind>(Modifier.Kind), Builder.records()[1]));
|
||||
BinaryItemStream<CVType> ItemStream(llvm::support::little);
|
||||
ItemStream.setItems(TypeArray);
|
||||
VarStreamArray<CVType> TypeStream(ItemStream);
|
||||
|
||||
// Figure out the byte offset of the second item.
|
||||
auto ItemOneIter = TypeStream.begin();
|
||||
++ItemOneIter;
|
||||
|
||||
// Set up a partial offsets buffer that contains the first and second items
|
||||
// in separate chunks.
|
||||
std::vector<TypeIndexOffset> TIO;
|
||||
TIO.push_back({IndexZero, ulittle32_t(0u)});
|
||||
TIO.push_back({IndexOne, ulittle32_t(ItemOneIter.offset())});
|
||||
ArrayRef<uint8_t> Buffer(reinterpret_cast<const uint8_t *>(TIO.data()),
|
||||
TIO.size() * sizeof(TypeIndexOffset));
|
||||
|
||||
BinaryStreamReader Reader(Buffer, llvm::support::little);
|
||||
FixedStreamArray<TypeIndexOffset> PartialOffsets;
|
||||
ASSERT_THAT_ERROR(Reader.readArray(PartialOffsets, 2), Succeeded());
|
||||
|
||||
LazyRandomTypeCollection Types(TypeStream, 2, PartialOffsets);
|
||||
|
||||
StringRef Name = Types.getTypeName(IndexOne);
|
||||
EXPECT_EQ("const FooClass", Name);
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
//===- llvm/unittest/DebugInfo/CodeView/TypeHashingTest.cpp ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/TypeHashing.h"
|
||||
#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
static TypeIndex createPointerRecord(AppendingTypeTableBuilder &Builder,
|
||||
TypeIndex TI) {
|
||||
PointerRecord PR(TypeRecordKind::Pointer);
|
||||
PR.setAttrs(PointerKind::Near32, PointerMode::Pointer, PointerOptions::None,
|
||||
4);
|
||||
PR.ReferentType = TI;
|
||||
return Builder.writeLeafType(PR);
|
||||
}
|
||||
|
||||
static TypeIndex createArgListRecord(AppendingTypeTableBuilder &Builder,
|
||||
TypeIndex Q, TypeIndex R) {
|
||||
ArgListRecord AR(TypeRecordKind::ArgList);
|
||||
AR.ArgIndices.push_back(Q);
|
||||
AR.ArgIndices.push_back(R);
|
||||
return Builder.writeLeafType(AR);
|
||||
}
|
||||
|
||||
static TypeIndex createProcedureRecord(AppendingTypeTableBuilder &Builder,
|
||||
uint32_t ParamCount, TypeIndex Return,
|
||||
TypeIndex ArgList) {
|
||||
ProcedureRecord PR(TypeRecordKind::Procedure);
|
||||
PR.ArgumentList = ArgList;
|
||||
PR.CallConv = CallingConvention::NearC;
|
||||
PR.Options = FunctionOptions::None;
|
||||
PR.ParameterCount = ParamCount;
|
||||
PR.ReturnType = Return;
|
||||
return Builder.writeLeafType(PR);
|
||||
}
|
||||
|
||||
static ArrayRef<uint8_t> hash_of(ArrayRef<GloballyHashedType> Hashes,
|
||||
TypeIndex TI) {
|
||||
return Hashes[TI.toArrayIndex()].Hash;
|
||||
}
|
||||
|
||||
static void verifyHashUniqueness(ArrayRef<GloballyHashedType> Hashes) {
|
||||
assert(!Hashes.empty());
|
||||
|
||||
for (size_t I = 0; I < Hashes.size() - 1; ++I) {
|
||||
for (size_t J = I + 1; J < Hashes.size(); ++J) {
|
||||
EXPECT_NE(Hashes[I].Hash, Hashes[J].Hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TypeHashingTest, ContentHash) {
|
||||
SimpleTypeSerializer Serializer;
|
||||
|
||||
TypeIndex CharStar(SimpleTypeKind::SignedCharacter,
|
||||
SimpleTypeMode::NearPointer32);
|
||||
|
||||
BumpPtrAllocator Alloc;
|
||||
AppendingTypeTableBuilder Ordering1(Alloc);
|
||||
AppendingTypeTableBuilder Ordering2(Alloc);
|
||||
|
||||
TypeIndex CharP(SimpleTypeKind::SignedCharacter, SimpleTypeMode::NearPointer);
|
||||
TypeIndex IntP(SimpleTypeKind::Int32, SimpleTypeMode::NearPointer);
|
||||
TypeIndex DoubleP(SimpleTypeKind::Float64, SimpleTypeMode::NearPointer);
|
||||
|
||||
// We're going to the same type sequence with two different orderings, and
|
||||
// then confirm all records are hashed the same.
|
||||
|
||||
TypeIndex CharPP[2];
|
||||
TypeIndex IntPP[2];
|
||||
TypeIndex IntPPP[2];
|
||||
TypeIndex DoublePP[2];
|
||||
TypeIndex Args[2];
|
||||
TypeIndex Proc[2];
|
||||
|
||||
// Ordering 1
|
||||
// ----------------------------------------
|
||||
// LF_POINTER 0x1000 {char**}
|
||||
// Referent = char*
|
||||
// LF_POINTER 0x1001 {int**}
|
||||
// Referent = int*
|
||||
// LF_POINTER 0x1002 {int***}
|
||||
// Referent = 0x1001
|
||||
// LF_ARGLIST 0x1003 {(char**, int***)}
|
||||
// Arg[0] = 0x1000
|
||||
// Arg[1] = 0x1002
|
||||
// LF_PROCEDURE 0x1004 {int** func(char**, int***)}
|
||||
// ArgList = 0x1003
|
||||
// ReturnType = 0x1001
|
||||
std::vector<GloballyHashedType> Ordering1Hashes;
|
||||
CharPP[0] = createPointerRecord(Ordering1, CharP);
|
||||
IntPP[0] = createPointerRecord(Ordering1, IntP);
|
||||
IntPPP[0] = createPointerRecord(Ordering1, IntPP[0]);
|
||||
Args[0] = createArgListRecord(Ordering1, CharPP[0], IntPPP[0]);
|
||||
Proc[0] = createProcedureRecord(Ordering1, 2, IntPP[0], Args[0]);
|
||||
|
||||
ASSERT_EQ(0x1000U, CharPP[0].getIndex());
|
||||
ASSERT_EQ(0x1001U, IntPP[0].getIndex());
|
||||
ASSERT_EQ(0x1002U, IntPPP[0].getIndex());
|
||||
ASSERT_EQ(0x1003U, Args[0].getIndex());
|
||||
ASSERT_EQ(0x1004U, Proc[0].getIndex());
|
||||
|
||||
auto Hashes1 = GloballyHashedType::hashTypes(Ordering1.records());
|
||||
|
||||
// Ordering 2
|
||||
// ----------------------------------------
|
||||
// LF_POINTER 0x1000 {int**}
|
||||
// Referent = int*
|
||||
// LF_POINTER 0x1001 {int***}
|
||||
// Referent = 0x1000
|
||||
// LF_POINTER 0x1002 {char**}
|
||||
// Referent = char*
|
||||
// LF_POINTER 0x1003 {double**}
|
||||
// Referent = double*
|
||||
// LF_ARGLIST 0x1004 {(char**, int***)}
|
||||
// Arg[0] = 0x1002
|
||||
// Arg[1] = 0x1001
|
||||
// LF_PROCEDURE 0x1005 {int** func(char**, int***)}
|
||||
// ArgList = 0x1004
|
||||
// ReturnType = 0x1000
|
||||
IntPP[1] = createPointerRecord(Ordering2, IntP);
|
||||
IntPPP[1] = createPointerRecord(Ordering2, IntPP[1]);
|
||||
CharPP[1] = createPointerRecord(Ordering2, CharP);
|
||||
DoublePP[1] = createPointerRecord(Ordering2, DoubleP);
|
||||
Args[1] = createArgListRecord(Ordering2, CharPP[1], IntPPP[1]);
|
||||
Proc[1] = createProcedureRecord(Ordering2, 2, IntPP[1], Args[1]);
|
||||
auto Hashes2 = GloballyHashedType::hashTypes(Ordering2.records());
|
||||
|
||||
ASSERT_EQ(0x1000U, IntPP[1].getIndex());
|
||||
ASSERT_EQ(0x1001U, IntPPP[1].getIndex());
|
||||
ASSERT_EQ(0x1002U, CharPP[1].getIndex());
|
||||
ASSERT_EQ(0x1003U, DoublePP[1].getIndex());
|
||||
ASSERT_EQ(0x1004U, Args[1].getIndex());
|
||||
ASSERT_EQ(0x1005U, Proc[1].getIndex());
|
||||
|
||||
// Sanity check to make sure all same-ordering hashes are different
|
||||
// from each other.
|
||||
verifyHashUniqueness(Hashes1);
|
||||
verifyHashUniqueness(Hashes2);
|
||||
|
||||
EXPECT_EQ(hash_of(Hashes1, IntPP[0]), hash_of(Hashes2, IntPP[1]));
|
||||
EXPECT_EQ(hash_of(Hashes1, IntPPP[0]), hash_of(Hashes2, IntPPP[1]));
|
||||
EXPECT_EQ(hash_of(Hashes1, CharPP[0]), hash_of(Hashes2, CharPP[1]));
|
||||
EXPECT_EQ(hash_of(Hashes1, Args[0]), hash_of(Hashes2, Args[1]));
|
||||
EXPECT_EQ(hash_of(Hashes1, Proc[0]), hash_of(Hashes2, Proc[1]));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user