Files
swift-mirror/unittests/runtime/PrebuiltStringMap.cpp
Mike Ash 4b3a197dc2 [Runtime] Support type descriptor map in LibPrespecialized.
The descriptor map is keyed by a simplified mangling that canonicalizes the differences that we accept in _contextDescriptorMatchesMangling, such as the ability to specify any kind of type with an OtherNominalType node.

This simplified mangling is not necessarily unique, but we use _contextDescriptorMatchesMangling for the final equality checking when looking up entries in the map, so occasional collisions are acceptable and get resolved when probing the table.

The table is meant to be comprehensive, so it includes all descriptors that can be looked up by name, and a negative result means the descriptor does not exist in the shared cache. We add a flag to the options that can mark it as non-definitive in case we ever need to degrade this, and fall back to a full search after a negative result.

The map encompasses the entire shared cache but we need to reject lookups for types in images that aren't loaded. The map includes an image index which allows us to cheaply query whether a given descriptor is in a loaded image or not, so we can ignore ones which are not.

TypeMetadataPrivateState now has a separate sections array for sections within the shared cache. _searchTypeMetadataRecords consults the map first. If no result is found in the map and the map is marked as comprehensive, then only the sections outside the shared cache need to be scanned.

Replace the SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED environment variable with one specifically for metadata and one for descriptor lookup so they can be controlled independently. Also add SWIFT_DEBUG_VALIDATE_LIB_PRESPECIALIZED_DESCRIPTOR_LOOKUP which consults the map and does the full scan, and ensures they produce the same result, for debugging purposes.

Enhance the environment variable code to track whether a variable was set at all. This allows SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED to override the default in either direction.

Remove the disablePrespecializedMetadata global and instead modify the mapConfiguration to disable prespecialized metadata when an image is loaded that overrides one in the shared cache.

rdar://113059233
2024-08-01 18:43:15 -04:00

144 lines
4.6 KiB
C++

//===--- PrebuiltStringMap.cpp - Unit tests for PrebuiltStringMap ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/PrebuiltStringMap.h"
#include "gtest/gtest.h"
static bool stringIsNull(const char *str) { return str == nullptr; }
TEST(PrebuiltStringMapTest, PrebuiltStringMap) {
auto testOnce = [&](unsigned testEntryCount) {
std::vector<std::pair<std::string, unsigned>> testVector;
testVector.reserve(testEntryCount);
for (unsigned i = 0; i < testEntryCount; i++) {
std::string key;
for (unsigned j = 0; j < i; j++)
key += std::to_string(j);
testVector.push_back({key, i});
}
using Map = swift::PrebuiltStringMap<const char *, unsigned, stringIsNull>;
unsigned mapSize = testEntryCount * 4 / 3;
void *mapAllocation = calloc(1, Map::byteSize(mapSize));
Map *map = new (mapAllocation) Map(mapSize);
// Populate the map.
for (auto &[key, value] : testVector) {
const char *keyCStr = key.c_str();
auto *element = map->insert(keyCStr);
EXPECT_NE(element, nullptr);
element->key = keyCStr;
element->value = value;
}
// Verify that we can find all the test values.
for (auto &[key, value] : testVector) {
const char *keyCStr = key.c_str();
auto *element = map->find(keyCStr);
EXPECT_NE(element, nullptr);
EXPECT_EQ(element->key, key);
EXPECT_EQ(element->value, value);
}
// Test the interface that takes a string and length without NUL
// termination.
for (auto &[key, value] : testVector) {
auto keyCopy = key;
keyCopy += "xyz";
const char *keyCStr = keyCopy.c_str();
auto *element = map->find(keyCStr, key.size());
EXPECT_NE(element, nullptr);
EXPECT_EQ(element->key, key);
EXPECT_EQ(element->value, value);
}
// Verify that nonexistent keys are not found.
const char *nonexistentKey = "ceci n'est pas une clef";
auto *element = map->find(nonexistentKey);
EXPECT_EQ(element, nullptr);
free(mapAllocation);
};
testOnce(10);
testOnce(100);
testOnce(1000);
}
TEST(PrebuiltStringMapTest, PrebuiltAuxDataImplicitStringMap) {
auto testOnce = [&](unsigned testEntryCount) {
// Test a map containing positive integers, where the key is a string
// derived from the integer. The aux data is the negative of the integer.
using Map = swift::PrebuiltAuxDataImplicitStringMap<uint64_t, int32_t>;
auto getKey = [](unsigned n) {
std::string key;
for (unsigned i = 0; i < n; i++) {
key += 'A' + (i % 26);
}
return key;
};
unsigned mapSize = testEntryCount * 4 / 3;
void *mapAllocation = calloc(1, Map::byteSize(mapSize));
Map *map = new (mapAllocation) Map(mapSize);
// Populate the map.
for (unsigned n = 0; n < testEntryCount; n++) {
auto key = getKey(n);
auto isNull = [](auto pointers) { return *pointers.first == 0; };
auto pointers = map->insert(key.c_str(), isNull);
EXPECT_NE(pointers.first, nullptr);
EXPECT_NE(pointers.second, nullptr);
*pointers.first = n;
*pointers.second = -(int64_t)n;
}
// Verify that we can find all the test values.
for (unsigned n = 0; n < testEntryCount; n++) {
auto key = getKey(n);
auto keyLength = key.size();
// Add some trash to the end to make sure the lookup doesn't look beyond
// the specified length.
key += "xyz";
auto isMatch = [n](auto pointers) { return *pointers.first == n; };
auto isNull = [](auto pointers) { return *pointers.first == 0; };
auto pointers = map->find(key.c_str(), keyLength, isMatch, isNull);
EXPECT_NE(pointers.first, nullptr);
EXPECT_NE(pointers.second, nullptr);
EXPECT_EQ(*pointers.first, n);
EXPECT_EQ(*pointers.second, -(int64_t)n);
}
// Verfy a nonexistent value is not found.
const char *nonexistentKey = "ceci n'est pas une clef";
auto isMatch = [](auto pointers) { return false; };
auto isNull = [](auto pointers) { return *pointers.first == 0; };
auto pointers =
map->find(nonexistentKey, strlen(nonexistentKey), isMatch, isNull);
EXPECT_EQ(*pointers.first, 0);
EXPECT_EQ(*pointers.second, 0);
};
testOnce(10);
testOnce(100);
testOnce(1000);
}