Skip to content

Commit 7023d08

Browse files
committed
[Serialization] Filter Objective-C methods by mangled name rather than type ID.
Module files store all of the Objective-C method entrypoints in a central table indexed by selector, then filter the results based on the specific class being requested. Rather than storing the class as a TypeID---which requires a bunch of deserialization---store its mangled name. This allows us to deserialize less, and causes circular deserialization in rdar://problem/31615640. (cherry picked from commit f6f5474)
1 parent 121ff7e commit 7023d08

File tree

4 files changed

+33
-22
lines changed

4 files changed

+33
-22
lines changed

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 331; // Last change: type witness substitutions
57+
const uint16_t VERSION_MINOR = 332; // Last change: no type in objc method table
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/Serialization/ModuleFile.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ class ModuleFile::ObjCMethodTableInfo {
532532
public:
533533
using internal_key_type = std::string;
534534
using external_key_type = ObjCSelector;
535-
using data_type = SmallVector<std::tuple<TypeID, bool, DeclID>, 8>;
535+
using data_type = SmallVector<std::tuple<std::string, bool, DeclID>, 8>;
536536
using hash_value_type = uint32_t;
537537
using offset_type = unsigned;
538538

@@ -551,7 +551,7 @@ class ModuleFile::ObjCMethodTableInfo {
551551

552552
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
553553
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
554-
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
554+
unsigned dataLength = endian::readNext<uint32_t, little, unaligned>(data);
555555
return { keyLength, dataLength };
556556
}
557557

@@ -562,14 +562,16 @@ class ModuleFile::ObjCMethodTableInfo {
562562
static data_type ReadData(internal_key_type key, const uint8_t *data,
563563
unsigned length) {
564564
const constexpr auto recordSize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
565-
assert(length % recordSize == 0 && "invalid length");
566565
data_type result;
567566
while (length > 0) {
568-
TypeID typeID = endian::readNext<uint32_t, little, unaligned>(data);
567+
unsigned ownerLen = endian::readNext<uint32_t, little, unaligned>(data);
569568
bool isInstanceMethod = *data++ != 0;
570569
DeclID methodID = endian::readNext<uint32_t, little, unaligned>(data);
571-
result.push_back(std::make_tuple(typeID, isInstanceMethod, methodID));
572-
length -= recordSize;
570+
std::string ownerName((const char *)data, ownerLen);
571+
result.push_back(
572+
std::make_tuple(std::move(ownerName), isInstanceMethod, methodID));
573+
data += ownerLen;
574+
length -= (recordSize + ownerLen);
573575
}
574576

575577
return result;
@@ -1553,15 +1555,15 @@ void ModuleFile::loadObjCMethods(
15531555
return;
15541556
}
15551557

1558+
std::string ownerName = Mangle::ASTMangler().mangleNominalType(classDecl);
15561559
auto results = *known;
15571560
for (const auto &result : results) {
15581561
// If the method is the wrong kind (instance vs. class), skip it.
15591562
if (isInstanceMethod != std::get<1>(result))
15601563
continue;
15611564

15621565
// If the method isn't defined in the requested class, skip it.
1563-
Type type = getType(std::get<0>(result));
1564-
if (type->getClassOrBoundGenericClass() != classDecl)
1566+
if (std::get<0>(result) != ownerName)
15651567
continue;
15661568

15671569
// Deserialize the method and add it to the list.

lib/Serialization/Serialization.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4119,13 +4119,15 @@ namespace {
41194119
auto keyLength = key.getString(scratch).size();
41204120
assert(keyLength <= std::numeric_limits<uint16_t>::max() &&
41214121
"selector too long");
4122-
size_t entrySize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
4123-
uint16_t dataLength = entrySize * data.size();
4124-
assert(dataLength / entrySize == data.size() && "too many methods");
4122+
uint32_t dataLength = 0;
4123+
for (const auto &entry : data) {
4124+
dataLength += sizeof(uint32_t) + 1 + sizeof(uint32_t);
4125+
dataLength += std::get<0>(entry).size();
4126+
}
41254127

41264128
endian::Writer<little> writer(out);
41274129
writer.write<uint16_t>(keyLength);
4128-
writer.write<uint16_t>(dataLength);
4130+
writer.write<uint32_t>(dataLength);
41294131
return { keyLength, dataLength };
41304132
}
41314133

@@ -4141,10 +4143,11 @@ namespace {
41414143
unsigned len) {
41424144
static_assert(declIDFitsIn32Bits(), "DeclID too large");
41434145
endian::Writer<little> writer(out);
4144-
for (auto entry : data) {
4145-
writer.write<uint32_t>(std::get<0>(entry));
4146+
for (const auto &entry : data) {
4147+
writer.write<uint32_t>(std::get<0>(entry).size());
41464148
writer.write<uint8_t>(std::get<1>(entry));
41474149
writer.write<uint32_t>(std::get<2>(entry));
4150+
out.write(std::get<0>(entry).c_str(), std::get<0>(entry).size());
41484151
}
41494152
}
41504153
};
@@ -4234,12 +4237,17 @@ static void collectInterestingNestedDeclarations(
42344237
if (!isLocal) {
42354238
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
42364239
if (func->isObjC()) {
4237-
TypeID owningTypeID
4238-
= S.addTypeRef(func->getDeclContext()->getDeclaredInterfaceType());
4239-
objcMethods[func->getObjCSelector()].push_back(
4240-
std::make_tuple(owningTypeID,
4241-
func->isObjCInstanceMethod(),
4242-
S.addDeclRef(func)));
4240+
if (auto owningClass =
4241+
func->getDeclContext()->getAsClassOrClassExtensionContext()) {
4242+
Mangle::ASTMangler mangler;
4243+
std::string ownerName = mangler.mangleNominalType(owningClass);
4244+
assert(!ownerName.empty() && "Mangled type came back empty!");
4245+
4246+
objcMethods[func->getObjCSelector()].push_back(
4247+
std::make_tuple(ownerName,
4248+
func->isObjCInstanceMethod(),
4249+
S.addDeclRef(func)));
4250+
}
42434251
}
42444252
}
42454253
}

lib/Serialization/Serialization.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ class Serializer {
117117
/// table.
118118
using DeclTable = llvm::MapVector<Identifier, DeclTableData>;
119119

120-
using ObjCMethodTableData = SmallVector<std::tuple<TypeID, bool, DeclID>, 4>;
120+
using ObjCMethodTableData =
121+
SmallVector<std::tuple<std::string, bool, DeclID>, 4>;
121122

122123
// In-memory representation of what will eventually be an on-disk
123124
// hash table of all defined Objective-C methods.

0 commit comments

Comments
 (0)