Skip to content

Commit 540c026

Browse files
committed
ClangImporter: Look up availability domains in Clang modules.
In addition to tracking availability domains in SwiftLookupTable, also serialize and deserialize the mapping from domain name to `clang::VarDecl`. Ideally this serialization and lookup infrastructure would be entirely handled by Clang, since it also needs to look up availability domains in serialized modules, but the implementation for that is not ready yet. Part of rdar://138441266.
1 parent a27817e commit 540c026

File tree

9 files changed

+340
-22
lines changed

9 files changed

+340
-22
lines changed

lib/ClangImporter/SwiftLookupTable.cpp

+214-7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace {
6464

6565
class BaseNameToEntitiesTableReaderInfo;
6666
class GlobalsAsMembersTableReaderInfo;
67+
class AvailabilityDomainsTableReaderInfo;
6768

6869
using SerializedBaseNameToEntitiesTable =
6970
llvm::OnDiskIterableChainedHashTable<BaseNameToEntitiesTableReaderInfo>;
@@ -73,6 +74,9 @@ namespace {
7374

7475
using SerializedGlobalsAsMembersIndex =
7576
llvm::OnDiskIterableChainedHashTable<GlobalsAsMembersTableReaderInfo>;
77+
78+
using SerializedAvailabilityDomainsTable =
79+
llvm::OnDiskIterableChainedHashTable<AvailabilityDomainsTableReaderInfo>;
7680
} // end anonymous namespace
7781

7882
namespace swift {
@@ -114,6 +118,8 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader {
114118

115119
std::unique_ptr<SerializedBaseNameToEntitiesTable> SerializedTable;
116120
ArrayRef<clang::serialization::DeclID> Categories;
121+
// FIXME: [availability] Remove this when Clang supports domain lookup.
122+
std::unique_ptr<SerializedAvailabilityDomainsTable> AvailabilityDomainsTable;
117123
std::unique_ptr<SerializedGlobalsAsMembersTable> GlobalsAsMembersTable;
118124
std::unique_ptr<SerializedGlobalsAsMembersIndex> GlobalsAsMembersIndex;
119125

@@ -124,13 +130,16 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader {
124130
std::unique_ptr<SerializedBaseNameToEntitiesTable>
125131
serializedTable,
126132
ArrayRef<clang::serialization::DeclID> categories,
133+
std::unique_ptr<SerializedAvailabilityDomainsTable>
134+
availabilityDomainsTable,
127135
std::unique_ptr<SerializedGlobalsAsMembersTable>
128136
globalsAsMembersTable,
129137
std::unique_ptr<SerializedGlobalsAsMembersIndex>
130138
globalsAsMembersIndex)
131139
: ModuleFileExtensionReader(extension), Reader(reader),
132140
ModuleFile(moduleFile), OnRemove(onRemove),
133141
SerializedTable(std::move(serializedTable)), Categories(categories),
142+
AvailabilityDomainsTable(std::move(availabilityDomainsTable)),
134143
GlobalsAsMembersTable(std::move(globalsAsMembersTable)),
135144
GlobalsAsMembersIndex(std::move(globalsAsMembersIndex)) {}
136145

@@ -185,6 +194,12 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader {
185194
bool lookupGlobalsAsMembers(
186195
SerializedSwiftName baseName,
187196
SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries);
197+
198+
SmallVector<StringRef, 4> getAvailabilityDomainNames();
199+
200+
/// Retreve the decl ID representing the availability domain with the given
201+
/// name.
202+
clang::serialization::DeclID lookupAvailabilityDomain(StringRef domainName);
188203
};
189204
} // namespace swift
190205

@@ -352,7 +367,7 @@ void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) {
352367

353368
void SwiftLookupTable::addAvailabilityDomainDecl(StringRef name,
354369
clang::VarDecl *decl) {
355-
AvailabilityDomains.insert({name, StoredSingleEntry(decl)});
370+
AvailabilityDomains.insert({name, decl});
356371
}
357372

358373
bool SwiftLookupTable::resolveUnresolvedEntries(
@@ -717,15 +732,36 @@ SwiftLookupTable::lookupGlobalsAsMembers(SerializedSwiftName baseName,
717732
return lookupGlobalsAsMembersImpl(baseName, *storedContext);
718733
}
719734

735+
// FIXME: [availability] Remove this once Clang has a lookup table.
720736
clang::VarDecl *SwiftLookupTable::lookupAvailabilityDomainDecl(StringRef name) {
721-
// FIXME: [availability] Remove this once Clang has a lookup table.
722-
auto result = AvailabilityDomains.find(name);
723-
if (result == AvailabilityDomains.end())
737+
// If the name is empty, there is nothing to find.
738+
if (name.empty())
724739
return nullptr;
725740

726-
auto &entry = result->second;
727-
DEBUG_ASSERT(entry.isASTNodeEntry());
728-
return static_cast<clang::VarDecl *>(entry.getASTNode());
741+
// See if we have an existing cached lookup result.
742+
auto known = AvailabilityDomains.find(name);
743+
if (known != AvailabilityDomains.end())
744+
return known->second;
745+
746+
// If there's no reader, we've found all there is to find.
747+
if (!Reader)
748+
return nullptr;
749+
750+
// Look up this domain in the module file.
751+
clang::VarDecl *result = nullptr;
752+
auto declID = Reader->lookupAvailabilityDomain(name);
753+
if (declID) {
754+
auto localID = clang::LocalDeclID::get(Reader->getASTReader(),
755+
Reader->getModuleFile(), declID);
756+
result = cast_or_null<clang::VarDecl>(
757+
Reader->getASTReader().GetLocalDecl(Reader->getModuleFile(), localID));
758+
}
759+
760+
// Add the result to the table (whether we found a decl or not) so that we
761+
// don't look again.
762+
AvailabilityDomains.insert({name, result});
763+
764+
return result;
729765
}
730766

731767
SmallVector<SwiftLookupTable::SingleEntry, 4>
@@ -936,6 +972,10 @@ void SwiftLookupTable::deserializeAll() {
936972
for (auto context : Reader->getGlobalsAsMembersContexts()) {
937973
(void)allGlobalsAsMembersInContext(context);
938974
}
975+
976+
for (auto domainName : Reader->getAvailabilityDomainNames()) {
977+
(void)lookupAvailabilityDomainDecl(domainName);
978+
}
939979
}
940980

941981
/// Print a stored context to the given output stream for debugging purposes.
@@ -1066,6 +1106,22 @@ void SwiftLookupTable::dump(raw_ostream &os) const {
10661106
os << "\n";
10671107
}
10681108
}
1109+
1110+
if (!AvailabilityDomains.empty()) {
1111+
os << "Availability domains:\n";
1112+
SmallVector<StringRef, 4> domainNames;
1113+
for (const auto &entry : AvailabilityDomains) {
1114+
domainNames.push_back(entry.first);
1115+
}
1116+
llvm::array_pod_sort(domainNames.begin(), domainNames.end());
1117+
1118+
for (auto domainName : domainNames) {
1119+
os << " " << domainName << ": ";
1120+
1121+
auto *domainDecl = AvailabilityDomains.find(domainName)->second;
1122+
os << (domainDecl ? domainDecl->getName() : "<nullptr>") << "\n";
1123+
}
1124+
}
10691125
}
10701126

10711127
// ---------------------------------------------------------------------------
@@ -1095,6 +1151,10 @@ namespace {
10951151
/// Record that contains the mapping from contexts to the list of
10961152
/// globals that will be injected as members into those contexts.
10971153
GLOBALS_AS_MEMBERS_INDEX_RECORD_ID,
1154+
1155+
// FIXME: [availability] Remove this when Clang supports domain lookup.
1156+
/// Record that contains the mapping from domain names to domain decls.
1157+
AVAILABILITY_DOMAINS_ID,
10981158
};
10991159

11001160
using BaseNameToEntitiesTableRecordLayout
@@ -1109,6 +1169,9 @@ namespace {
11091169
using GlobalsAsMembersIndexRecordLayout
11101170
= BCRecordLayout<GLOBALS_AS_MEMBERS_INDEX_RECORD_ID, BCVBR<16>, BCBlob>;
11111171

1172+
using AvailabilityDomainsTableRecordLayout =
1173+
BCRecordLayout<AVAILABILITY_DOMAINS_ID, BCVBR<16>, BCBlob>;
1174+
11121175
constexpr size_t SizeOfEmittedStoredSingleEntry
11131176
= sizeof(StoredSingleEntry::SerializationID)
11141177
+ sizeof(StoredSingleEntry::SubmoduleID);
@@ -1303,6 +1366,39 @@ namespace {
13031366
}
13041367
}
13051368
};
1369+
1370+
// FIXME: [availability] Remove this when Clang supports domain lookup.
1371+
/// Trait used to write the on-disk hash table for the identifier ->
1372+
/// availability domain table.
1373+
class AvailabilityDomainsTableWriterInfo {
1374+
public:
1375+
using key_type = StringRef;
1376+
using key_type_ref = key_type;
1377+
using data_type = clang::serialization::DeclID;
1378+
using data_type_ref = const data_type &;
1379+
using hash_value_type = uint32_t;
1380+
using offset_type = unsigned;
1381+
1382+
hash_value_type ComputeHash(key_type_ref key) { return llvm::djbHash(key); }
1383+
1384+
std::pair<unsigned, unsigned>
1385+
EmitKeyDataLength(raw_ostream &os, key_type_ref key, data_type_ref) {
1386+
uint32_t keyLength = key.size();
1387+
uint32_t dataLength = sizeof(data_type);
1388+
1389+
llvm::support::endian::Writer writer(os, llvm::endianness::little);
1390+
writer.write<uint16_t>(keyLength);
1391+
writer.write<uint16_t>(dataLength);
1392+
return {keyLength, dataLength};
1393+
}
1394+
1395+
void EmitKey(raw_ostream &os, key_type_ref key, unsigned) { os << key; }
1396+
1397+
void EmitData(raw_ostream &os, key_type_ref, data_type_ref data, unsigned) {
1398+
llvm::support::endian::Writer writer(os, llvm::endianness::little);
1399+
writer.write<data_type>(data);
1400+
}
1401+
};
13061402
} // end anonymous namespace
13071403

13081404
void SwiftLookupTableWriter::writeExtensionContents(
@@ -1414,6 +1510,35 @@ void SwiftLookupTableWriter::writeExtensionContents(
14141510
GlobalsAsMembersIndexRecordLayout layout(stream);
14151511
layout.emit(ScratchRecord, tableOffset, hashTableBlob);
14161512
}
1513+
1514+
if (!table.AvailabilityDomains.empty()) {
1515+
// Sort the availability domain names.
1516+
SmallVector<StringRef, 4> domainNames;
1517+
for (const auto &entry : table.AvailabilityDomains)
1518+
domainNames.push_back(entry.first);
1519+
llvm::array_pod_sort(domainNames.begin(), domainNames.end());
1520+
1521+
llvm::SmallString<4096> hashTableBlob;
1522+
uint32_t tableOffset;
1523+
{
1524+
llvm::OnDiskChainedHashTableGenerator<AvailabilityDomainsTableWriterInfo>
1525+
generator;
1526+
AvailabilityDomainsTableWriterInfo info;
1527+
1528+
for (auto domainName : domainNames) {
1529+
auto domainDecl = table.AvailabilityDomains[domainName];
1530+
auto declID = Writer.getDeclID(domainDecl).getRawValue();
1531+
generator.insert(domainName, declID, info);
1532+
}
1533+
1534+
llvm::raw_svector_ostream blobStream(hashTableBlob);
1535+
// Make sure that no bucket is at offset 0
1536+
endian::write<uint32_t>(blobStream, 0, llvm::endianness::little);
1537+
tableOffset = generator.Emit(blobStream, info);
1538+
}
1539+
AvailabilityDomainsTableRecordLayout layout(stream);
1540+
layout.emit(ScratchRecord, tableOffset, hashTableBlob);
1541+
}
14171542
}
14181543

14191544
namespace {
@@ -1564,6 +1689,47 @@ namespace {
15641689
return result;
15651690
}
15661691
};
1692+
1693+
// FIXME: [availability] Remove this when Clang supports domain lookup.
1694+
/// Used to deserialize the on-disk identifier -> availability domain table.
1695+
class AvailabilityDomainsTableReaderInfo {
1696+
public:
1697+
using internal_key_type = llvm::StringRef;
1698+
using external_key_type = internal_key_type;
1699+
using data_type = clang::serialization::DeclID;
1700+
using hash_value_type = uint32_t;
1701+
using offset_type = unsigned;
1702+
1703+
internal_key_type GetInternalKey(external_key_type key) { return key; }
1704+
external_key_type GetExternalKey(internal_key_type key) { return key; }
1705+
1706+
hash_value_type ComputeHash(internal_key_type key) {
1707+
return llvm::djbHash(key);
1708+
}
1709+
1710+
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
1711+
return lhs == rhs;
1712+
}
1713+
1714+
static std::pair<unsigned, unsigned>
1715+
ReadKeyDataLength(const uint8_t *&data) {
1716+
unsigned keyLength =
1717+
endian::readNext<uint16_t, llvm::endianness::little>(data);
1718+
unsigned dataLength =
1719+
endian::readNext<uint16_t, llvm::endianness::little>(data);
1720+
return {keyLength, dataLength};
1721+
}
1722+
1723+
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
1724+
return llvm::StringRef(reinterpret_cast<const char *>(data), length);
1725+
}
1726+
1727+
static data_type ReadData(internal_key_type key, const uint8_t *data,
1728+
unsigned length) {
1729+
return endian::readNext<data_type, llvm::endianness::little>(data);
1730+
}
1731+
};
1732+
15671733
} // end anonymous namespace
15681734

15691735
clang::NamedDecl *SwiftLookupTable::mapStoredDecl(StoredSingleEntry &entry) {
@@ -1673,6 +1839,8 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension,
16731839
std::unique_ptr<SerializedGlobalsAsMembersIndex> globalsAsMembersIndex;
16741840
std::unique_ptr<SerializedGlobalsAsMembersTable> globalsAsMembersTable;
16751841
ArrayRef<clang::serialization::DeclID> categories;
1842+
std::unique_ptr<SerializedAvailabilityDomainsTable> availabilityDomainsTable;
1843+
16761844
while (next.Kind != llvm::BitstreamEntry::EndBlock) {
16771845
if (next.Kind == llvm::BitstreamEntry::Error)
16781846
return nullptr;
@@ -1764,6 +1932,20 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension,
17641932
break;
17651933
}
17661934

1935+
case AVAILABILITY_DOMAINS_ID: {
1936+
// Already saw the availability domains table.
1937+
if (availabilityDomainsTable)
1938+
return nullptr;
1939+
1940+
uint32_t tableOffset;
1941+
AvailabilityDomainsTableRecordLayout::readRecord(scratch, tableOffset);
1942+
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
1943+
1944+
availabilityDomainsTable.reset(SerializedAvailabilityDomainsTable::Create(
1945+
base + tableOffset, base + sizeof(uint32_t), base));
1946+
break;
1947+
}
1948+
17671949
default:
17681950
// Unknown record, possibly for use by a future version of the
17691951
// module format.
@@ -1787,6 +1969,7 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension,
17871969
return std::unique_ptr<SwiftLookupTableReader>(
17881970
new SwiftLookupTableReader(extension, reader, moduleFile, onRemove,
17891971
std::move(serializedTable), categories,
1972+
std::move(availabilityDomainsTable),
17901973
std::move(globalsAsMembersTable),
17911974
std::move(globalsAsMembersIndex)));
17921975

@@ -1862,6 +2045,30 @@ bool SwiftLookupTableReader::lookupGlobalsAsMembers(
18622045
return true;
18632046
}
18642047

2048+
SmallVector<StringRef, 4> SwiftLookupTableReader::getAvailabilityDomainNames() {
2049+
SmallVector<StringRef, 4> results;
2050+
if (!AvailabilityDomainsTable)
2051+
return {};
2052+
2053+
for (auto name : AvailabilityDomainsTable->keys()) {
2054+
results.push_back(name);
2055+
}
2056+
return results;
2057+
}
2058+
2059+
clang::serialization::DeclID
2060+
SwiftLookupTableReader::lookupAvailabilityDomain(StringRef domainName) {
2061+
if (!AvailabilityDomainsTable)
2062+
return {};
2063+
2064+
// Look for an entry with this context name.
2065+
auto known = AvailabilityDomainsTable->find(domainName);
2066+
if (known == AvailabilityDomainsTable->end())
2067+
return {};
2068+
2069+
return *known;
2070+
}
2071+
18652072
clang::ModuleFileExtensionMetadata
18662073
SwiftNameLookupExtension::getExtensionMetadata() const {
18672074
clang::ModuleFileExtensionMetadata metadata;

lib/ClangImporter/SwiftLookupTable.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ class SwiftLookupTable {
488488

489489
/// A mapping from availability domain name strings to their corresponding
490490
/// declarations.
491-
llvm::SmallDenseMap<StringRef, StoredSingleEntry> AvailabilityDomains;
491+
llvm::SmallDenseMap<StringRef, clang::VarDecl *> AvailabilityDomains;
492492

493493
/// A mapping from stored contexts to the set of global declarations that
494494
/// are mapped to members within that context.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Seas
2+
3+
@available(Arctic) // expected-warning {{unrecognized platform name 'Arctic'}}
4+
func availableInArctic() { }
5+
6+
@available(Mediterranean)
7+
func availableInMediterranean() { }
8+
9+
func testOtherClangDecls() {
10+
available_in_baltic()
11+
}

0 commit comments

Comments
 (0)