[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.
This commit is contained in:
Doug Gregor
2017-04-18 11:38:39 -07:00
parent 54f132c487
commit f6f547469d
4 changed files with 33 additions and 22 deletions

View File

@@ -543,7 +543,7 @@ class ModuleFile::ObjCMethodTableInfo {
public:
using internal_key_type = std::string;
using external_key_type = ObjCSelector;
using data_type = SmallVector<std::tuple<TypeID, bool, DeclID>, 8>;
using data_type = SmallVector<std::tuple<std::string, bool, DeclID>, 8>;
using hash_value_type = uint32_t;
using offset_type = unsigned;
@@ -562,7 +562,7 @@ public:
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
unsigned dataLength = endian::readNext<uint32_t, little, unaligned>(data);
return { keyLength, dataLength };
}
@@ -573,14 +573,16 @@ public:
static data_type ReadData(internal_key_type key, const uint8_t *data,
unsigned length) {
const constexpr auto recordSize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
assert(length % recordSize == 0 && "invalid length");
data_type result;
while (length > 0) {
TypeID typeID = endian::readNext<uint32_t, little, unaligned>(data);
unsigned ownerLen = endian::readNext<uint32_t, little, unaligned>(data);
bool isInstanceMethod = *data++ != 0;
DeclID methodID = endian::readNext<uint32_t, little, unaligned>(data);
result.push_back(std::make_tuple(typeID, isInstanceMethod, methodID));
length -= recordSize;
std::string ownerName((const char *)data, ownerLen);
result.push_back(
std::make_tuple(std::move(ownerName), isInstanceMethod, methodID));
data += ownerLen;
length -= (recordSize + ownerLen);
}
return result;
@@ -1565,6 +1567,7 @@ void ModuleFile::loadObjCMethods(
return;
}
std::string ownerName = Mangle::ASTMangler().mangleNominalType(classDecl);
auto results = *known;
for (const auto &result : results) {
// If the method is the wrong kind (instance vs. class), skip it.
@@ -1572,8 +1575,7 @@ void ModuleFile::loadObjCMethods(
continue;
// If the method isn't defined in the requested class, skip it.
Type type = getType(std::get<0>(result));
if (type->getClassOrBoundGenericClass() != classDecl)
if (std::get<0>(result) != ownerName)
continue;
// Deserialize the method and add it to the list.