Skip to content

[Serialization] Filter Objective-C methods by mangled name rather than type ID. #8838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 334; // Last change: AnyObject bit in ProtocolCompositionType
const uint16_t VERSION_MINOR = 335; // Last change: no type in objc method table

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down
18 changes: 10 additions & 8 deletions lib/Serialization/ModuleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -562,7 +562,7 @@ class ModuleFile::ObjCMethodTableInfo {

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 };
}

Expand All @@ -573,14 +573,16 @@ class ModuleFile::ObjCMethodTableInfo {
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;
Expand Down Expand Up @@ -1565,15 +1567,15 @@ 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.
if (isInstanceMethod != std::get<1>(result))
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.
Expand Down
32 changes: 20 additions & 12 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4127,13 +4127,15 @@ namespace {
auto keyLength = key.getString(scratch).size();
assert(keyLength <= std::numeric_limits<uint16_t>::max() &&
"selector too long");
size_t entrySize = sizeof(uint32_t) + 1 + sizeof(uint32_t);
uint16_t dataLength = entrySize * data.size();
assert(dataLength / entrySize == data.size() && "too many methods");
uint32_t dataLength = 0;
for (const auto &entry : data) {
dataLength += sizeof(uint32_t) + 1 + sizeof(uint32_t);
dataLength += std::get<0>(entry).size();
}

endian::Writer<little> writer(out);
writer.write<uint16_t>(keyLength);
writer.write<uint16_t>(dataLength);
writer.write<uint32_t>(dataLength);
return { keyLength, dataLength };
}

Expand All @@ -4149,10 +4151,11 @@ namespace {
unsigned len) {
static_assert(declIDFitsIn32Bits(), "DeclID too large");
endian::Writer<little> writer(out);
for (auto entry : data) {
writer.write<uint32_t>(std::get<0>(entry));
for (const auto &entry : data) {
writer.write<uint32_t>(std::get<0>(entry).size());
writer.write<uint8_t>(std::get<1>(entry));
writer.write<uint32_t>(std::get<2>(entry));
out.write(std::get<0>(entry).c_str(), std::get<0>(entry).size());
}
}
};
Expand Down Expand Up @@ -4242,12 +4245,17 @@ static void collectInterestingNestedDeclarations(
if (!isLocal) {
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
if (func->isObjC()) {
TypeID owningTypeID
= S.addTypeRef(func->getDeclContext()->getDeclaredInterfaceType());
objcMethods[func->getObjCSelector()].push_back(
std::make_tuple(owningTypeID,
func->isObjCInstanceMethod(),
S.addDeclRef(func)));
if (auto owningClass =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about protocols?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only do this for classes (always have).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then should this be an assertion?

func->getDeclContext()->getAsClassOrClassExtensionContext()) {
Mangle::ASTMangler mangler;
std::string ownerName = mangler.mangleNominalType(owningClass);
assert(!ownerName.empty() && "Mangled type came back empty!");

objcMethods[func->getObjCSelector()].push_back(
std::make_tuple(ownerName,
func->isObjCInstanceMethod(),
S.addDeclRef(func)));
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/Serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ class Serializer {
/// table.
using DeclTable = llvm::MapVector<Identifier, DeclTableData>;

using ObjCMethodTableData = SmallVector<std::tuple<TypeID, bool, DeclID>, 4>;
using ObjCMethodTableData =
SmallVector<std::tuple<std::string, bool, DeclID>, 4>;

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