Skip to content

Commit f6f5474

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.
1 parent 54f132c commit f6f5474

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 = 334; // Last change: AnyObject bit in ProtocolCompositionType
57+
const uint16_t VERSION_MINOR = 335; // 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
@@ -543,7 +543,7 @@ class ModuleFile::ObjCMethodTableInfo {
543543
public:
544544
using internal_key_type = std::string;
545545
using external_key_type = ObjCSelector;
546-
using data_type = SmallVector<std::tuple<TypeID, bool, DeclID>, 8>;
546+
using data_type = SmallVector<std::tuple<std::string, bool, DeclID>, 8>;
547547
using hash_value_type = uint32_t;
548548
using offset_type = unsigned;
549549

@@ -562,7 +562,7 @@ class ModuleFile::ObjCMethodTableInfo {
562562

563563
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
564564
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
565-
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
565+
unsigned dataLength = endian::readNext<uint32_t, little, unaligned>(data);
566566
return { keyLength, dataLength };
567567
}
568568

@@ -573,14 +573,16 @@ class ModuleFile::ObjCMethodTableInfo {
573573
static data_type ReadData(internal_key_type key, const uint8_t *data,
574574
unsigned length) {
575575
const constexpr auto recordSize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
576-
assert(length % recordSize == 0 && "invalid length");
577576
data_type result;
578577
while (length > 0) {
579-
TypeID typeID = endian::readNext<uint32_t, little, unaligned>(data);
578+
unsigned ownerLen = endian::readNext<uint32_t, little, unaligned>(data);
580579
bool isInstanceMethod = *data++ != 0;
581580
DeclID methodID = endian::readNext<uint32_t, little, unaligned>(data);
582-
result.push_back(std::make_tuple(typeID, isInstanceMethod, methodID));
583-
length -= recordSize;
581+
std::string ownerName((const char *)data, ownerLen);
582+
result.push_back(
583+
std::make_tuple(std::move(ownerName), isInstanceMethod, methodID));
584+
data += ownerLen;
585+
length -= (recordSize + ownerLen);
584586
}
585587

586588
return result;
@@ -1565,15 +1567,15 @@ void ModuleFile::loadObjCMethods(
15651567
return;
15661568
}
15671569

1570+
std::string ownerName = Mangle::ASTMangler().mangleNominalType(classDecl);
15681571
auto results = *known;
15691572
for (const auto &result : results) {
15701573
// If the method is the wrong kind (instance vs. class), skip it.
15711574
if (isInstanceMethod != std::get<1>(result))
15721575
continue;
15731576

15741577
// If the method isn't defined in the requested class, skip it.
1575-
Type type = getType(std::get<0>(result));
1576-
if (type->getClassOrBoundGenericClass() != classDecl)
1578+
if (std::get<0>(result) != ownerName)
15771579
continue;
15781580

15791581
// 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
@@ -4127,13 +4127,15 @@ namespace {
41274127
auto keyLength = key.getString(scratch).size();
41284128
assert(keyLength <= std::numeric_limits<uint16_t>::max() &&
41294129
"selector too long");
4130-
size_t entrySize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
4131-
uint16_t dataLength = entrySize * data.size();
4132-
assert(dataLength / entrySize == data.size() && "too many methods");
4130+
uint32_t dataLength = 0;
4131+
for (const auto &entry : data) {
4132+
dataLength += sizeof(uint32_t) + 1 + sizeof(uint32_t);
4133+
dataLength += std::get<0>(entry).size();
4134+
}
41334135

41344136
endian::Writer<little> writer(out);
41354137
writer.write<uint16_t>(keyLength);
4136-
writer.write<uint16_t>(dataLength);
4138+
writer.write<uint32_t>(dataLength);
41374139
return { keyLength, dataLength };
41384140
}
41394141

@@ -4149,10 +4151,11 @@ namespace {
41494151
unsigned len) {
41504152
static_assert(declIDFitsIn32Bits(), "DeclID too large");
41514153
endian::Writer<little> writer(out);
4152-
for (auto entry : data) {
4153-
writer.write<uint32_t>(std::get<0>(entry));
4154+
for (const auto &entry : data) {
4155+
writer.write<uint32_t>(std::get<0>(entry).size());
41544156
writer.write<uint8_t>(std::get<1>(entry));
41554157
writer.write<uint32_t>(std::get<2>(entry));
4158+
out.write(std::get<0>(entry).c_str(), std::get<0>(entry).size());
41564159
}
41574160
}
41584161
};
@@ -4242,12 +4245,17 @@ static void collectInterestingNestedDeclarations(
42424245
if (!isLocal) {
42434246
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
42444247
if (func->isObjC()) {
4245-
TypeID owningTypeID
4246-
= S.addTypeRef(func->getDeclContext()->getDeclaredInterfaceType());
4247-
objcMethods[func->getObjCSelector()].push_back(
4248-
std::make_tuple(owningTypeID,
4249-
func->isObjCInstanceMethod(),
4250-
S.addDeclRef(func)));
4248+
if (auto owningClass =
4249+
func->getDeclContext()->getAsClassOrClassExtensionContext()) {
4250+
Mangle::ASTMangler mangler;
4251+
std::string ownerName = mangler.mangleNominalType(owningClass);
4252+
assert(!ownerName.empty() && "Mangled type came back empty!");
4253+
4254+
objcMethods[func->getObjCSelector()].push_back(
4255+
std::make_tuple(ownerName,
4256+
func->isObjCInstanceMethod(),
4257+
S.addDeclRef(func)));
4258+
}
42514259
}
42524260
}
42534261
}

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)