Skip to content

Cherrypick ObjC method mangling commits for Swift #2026

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

Closed
wants to merge 2 commits into from
Closed
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
7 changes: 7 additions & 0 deletions clang/include/clang/AST/DeclObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,13 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
}

/// If this method is declared or implemented in a category, return
/// that category.
ObjCCategoryDecl *getCategory();
const ObjCCategoryDecl *getCategory() const {
return const_cast<ObjCMethodDecl*>(this)->getCategory();
}

Selector getSelector() const { return getDeclName().getObjCSelector(); }

QualType getReturnType() const { return MethodDeclType; }
Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,11 @@ class MangleContext {
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
raw_ostream &Out);

void mangleObjCMethodNameWithoutSize(const ObjCMethodDecl *MD, raw_ostream &);
void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &);
void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &OS,
bool includePrefixByte = true,
bool includeCategoryNamespace = true);
void mangleObjCMethodNameAsSourceName(const ObjCMethodDecl *MD,
raw_ostream &);

virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0;

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/DeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,14 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
llvm_unreachable("unknown method context");
}

ObjCCategoryDecl *ObjCMethodDecl::getCategory() {
if (auto *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext()))
return CD;
if (auto *IMD = dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
return IMD->getCategoryDecl();
return nullptr;
}

SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
const auto *TSI = getReturnTypeSourceInfo();
if (TSI)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2492,7 +2492,7 @@ void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
}

void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
Context.mangleObjCMethodNameAsSourceName(MD, Out);
}

static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty,
Expand Down
72 changes: 57 additions & 15 deletions clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const TargetInfo &TI = Context.getTargetInfo();
if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
mangleObjCMethodName(OMD, Out);
mangleObjCMethodNameAsSourceName(OMD, Out);
else
mangleCXXName(GD, Out);
return;
Expand All @@ -192,7 +192,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (!MCXX)
Out << D->getIdentifier()->getName();
else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
mangleObjCMethodName(OMD, Out);
mangleObjCMethodNameAsSourceName(OMD, Out);
else
mangleCXXName(GD, Out);

Expand Down Expand Up @@ -275,7 +275,7 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
SmallString<64> Buffer;
llvm::raw_svector_ostream Stream(Buffer);
if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method, Stream);
mangleObjCMethodNameAsSourceName(Method, Stream);
} else {
assert((isa<NamedDecl>(DC) || isa<BlockDecl>(DC)) &&
"expected a NamedDecl or BlockDecl");
Expand Down Expand Up @@ -304,29 +304,70 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
mangleFunctionBlock(*this, Buffer, BD, Out);
}

void MangleContext::mangleObjCMethodNameWithoutSize(const ObjCMethodDecl *MD,
raw_ostream &OS) {
const ObjCContainerDecl *CD =
dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
assert (CD && "Missing container decl in GetNameForMethod");
void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
raw_ostream &OS,
bool includePrefixByte,
bool includeCategoryNamespace) {
if (getASTContext().getLangOpts().ObjCRuntime.isGNUFamily()) {
// This is the mangling we've always used on the GNU runtimes, but it
// has obvious collisions in the face of underscores within class
// names, category names, and selectors; maybe we should improve it.

OS << (MD->isClassMethod() ? "_c_" : "_i_")
<< MD->getClassInterface()->getName() << '_';

if (includeCategoryNamespace) {
if (auto category = MD->getCategory())
OS << category->getName();
}
OS << '_';

auto selector = MD->getSelector();
for (unsigned slotIndex = 0,
numArgs = selector.getNumArgs(),
slotEnd = std::max(numArgs, 1U);
slotIndex != slotEnd; ++slotIndex) {
if (auto name = selector.getIdentifierInfoForSlot(slotIndex))
OS << name->getName();

// Replace all the positions that would've been ':' with '_'.
// That's after each slot except that a unary selector doesn't
// end in ':'.
if (numArgs)
OS << '_';
}

return;
}

// \01+[ContainerName(CategoryName) SelectorName]
if (includePrefixByte) {
OS << '\01';
}
OS << (MD->isInstanceMethod() ? '-' : '+') << '[';
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) {
if (const auto *CID = MD->getCategory()) {
OS << CID->getClassInterface()->getName();
OS << '(' << *CID << ')';
} else {
if (includeCategoryNamespace) {
OS << '(' << *CID << ')';
}
} else if (const auto *CD =
dyn_cast<ObjCContainerDecl>(MD->getDeclContext())) {
OS << CD->getName();
} else {
llvm_unreachable("Unexpected ObjC method decl context");
}
OS << ' ';
MD->getSelector().print(OS);
OS << ']';
}

void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
raw_ostream &Out) {
void MangleContext::mangleObjCMethodNameAsSourceName(const ObjCMethodDecl *MD,
raw_ostream &Out) {
SmallString<64> Name;
llvm::raw_svector_ostream OS(Name);

mangleObjCMethodNameWithoutSize(MD, OS);
mangleObjCMethodName(MD, OS, /*includePrefixByte=*/false,
/*includeCategoryNamespace=*/true);
Out << OS.str().size() << OS.str();
}

Expand All @@ -352,7 +393,8 @@ class ASTNameGenerator::Implementation {
if (writeFuncOrVarName(VD, FrontendBufOS))
return true;
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
MC->mangleObjCMethodNameWithoutSize(MD, OS);
MC->mangleObjCMethodName(MD, OS, /*includePrefixByte=*/false,
/*includeCategoryNamespace=*/true);
return false;
} else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
writeObjCClassName(ID, FrontendBufOS);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,7 @@ void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
}

void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
Context.mangleObjCMethodNameAsSourceName(MD, Out);
}

void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
Expand Down
24 changes: 2 additions & 22 deletions clang/lib/CodeGen/CGObjCGNU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ using namespace CodeGen;

namespace {

std::string SymbolNameForMethod( StringRef ClassName,
StringRef CategoryName, const Selector MethodName,
bool isClassMethod) {
std::string MethodNameColonStripped = MethodName.getAsString();
std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
':', '_');
return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
CategoryName + "_" + MethodNameColonStripped).str();
}

/// Class that lazily initialises the runtime function. Avoids inserting the
/// types and the function declaration into a module if they're not used, and
/// avoids constructing the type more than once if it's used more than once.
Expand Down Expand Up @@ -2825,9 +2815,7 @@ GenerateMethodList(StringRef ClassName,
ASTContext &Context = CGM.getContext();
for (const auto *OMD : Methods) {
llvm::Constant *FnPtr =
TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
OMD->getSelector(),
isClassMethodList));
TheModule.getFunction(getSymbolNameForMethod(OMD));
assert(FnPtr && "Can't generate metadata for method that doesn't exist");
auto Method = MethodArray.beginStruct(ObjCMethodTy);
if (isV2ABI) {
Expand Down Expand Up @@ -3875,18 +3863,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {

llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
StringRef CategoryName = OCD ? OCD->getName() : "";
StringRef ClassName = CD->getName();
Selector MethodName = OMD->getSelector();
bool isClassMethod = !OMD->isInstanceMethod();

CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
MethodName, isClassMethod);
std::string FunctionName = getSymbolNameForMethod(OMD);

llvm::Function *Method
= llvm::Function::Create(MethodTy,
Expand Down
37 changes: 7 additions & 30 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/CodeGenOptions.h"
Expand Down Expand Up @@ -924,13 +925,6 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {

llvm::StringMap<llvm::GlobalVariable *> NSConstantStringMap;

/// GetNameForMethod - Return a name for the given method.
/// \param[out] NameOut - The return value.
void GetNameForMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD,
SmallVectorImpl<char> &NameOut,
bool ignoreCategoryNamespace = false);

/// GetMethodVarName - Return a unique constant for the given
/// selector's name. The return value has type char *.
llvm::Constant *GetMethodVarName(Selector Sel);
Expand Down Expand Up @@ -1085,8 +1079,8 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
void EmitImageInfo();

public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
CGObjCCommonMac(CodeGen::CodeGenModule &cgm)
: CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) {}

bool isNonFragileABI() const {
return ObjCABI == 2;
Expand Down Expand Up @@ -4007,15 +4001,14 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
if (OMD->isDirectMethod()) {
Method = GenerateDirectMethod(OMD, CD);
} else {
SmallString<256> Name;
GetNameForMethod(OMD, CD, Name);
auto Name = getSymbolNameForMethod(OMD);

CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
Method =
llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
Name.str(), &CGM.getModule());
Name, &CGM.getModule());
}

MethodDefinitions.insert(std::make_pair(OMD, Method));
Expand Down Expand Up @@ -4060,11 +4053,10 @@ CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
// Replace the cached function in the map.
I->second = Fn;
} else {
SmallString<256> Name;
GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/ true);
auto Name = getSymbolNameForMethod(OMD, /*include category*/ false);

Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
Name.str(), &CGM.getModule());
Name, &CGM.getModule());
DirectMethodDefinitions.insert(std::make_pair(COMD, Fn));
}

Expand Down Expand Up @@ -5714,21 +5706,6 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
}

void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
const ObjCContainerDecl *CD,
SmallVectorImpl<char> &Name,
bool ignoreCategoryNamespace) {
llvm::raw_svector_ostream OS(Name);
assert (CD && "Missing container decl in GetNameForMethod");
OS << '\01' << (D->isInstanceMethod() ? '-' : '+')
<< '[' << CD->getName();
if (!ignoreCategoryNamespace)
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
OS << '(' << *CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}

void CGObjCMac::FinishModule() {
EmitModuleInfo();

Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CodeGen/CGObjCRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,13 @@ clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM,
const ObjCProtocolDecl *protocol) {
return CGM.getObjCRuntime().GetOrEmitProtocol(protocol);
}

std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD,
bool includeCategoryName) {
std::string buffer;
llvm::raw_string_ostream out(buffer);
CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out,
/*includePrefixByte=*/true,
includeCategoryName);
return buffer;
}
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGObjCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ class CGObjCRuntime {
public:
virtual ~CGObjCRuntime();

std::string getSymbolNameForMethod(const ObjCMethodDecl *method,
bool includeCategoryName = true);

/// Generate the function required to register all Objective-C components in
/// this compilation unit with the runtime library.
virtual llvm::Function *ModuleInitFunction() = 0;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-decl-json.m
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ void f() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "bar",
// CHECK-NEXT: "mangledName": "-[TestObjCCategoryDecl bar]",
// CHECK-NEXT: "mangledName": "-[TestObjCClass(TestObjCCategoryDecl) bar]",
// CHECK-NEXT: "returnType": {
// CHECK-NEXT: "qualType": "void"
// CHECK-NEXT: },
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/dsymutil/SymbolMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ StringRef SymbolMapTranslator::operator()(StringRef Input) {
return Translation;

// Objective-C symbols for the MachO symbol table start with a \1. Please see
// `CGObjCCommonMac::GetNameForMethod` in clang.
// `MangleContext::mangleObjCMethodName` in clang.
if (Translation[0] == 1)
return StringRef(Translation).drop_front();

Expand Down