summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGObjCMac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGObjCMac.cpp')
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp103
1 files changed, 90 insertions, 13 deletions
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 79b00f21411..4d4e54d214d 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -721,6 +721,33 @@ public:
"objc_begin_catch");
}
+ /// Class objc_loadClassref (void *)
+ ///
+ /// Loads from a classref. For Objective-C stub classes, this invokes the
+ /// initialization callback stored inside the stub. For all other classes
+ /// this simply dereferences the pointer.
+ llvm::FunctionCallee getLoadClassrefFn() const {
+ // Add the non-lazy-bind attribute, since objc_loadClassref is likely to
+ // be called a lot.
+ //
+ // Also it is safe to make it readnone, since we never load or store the
+ // classref except by calling this function.
+ llvm::Type *params[] = { Int8PtrPtrTy };
+ llvm::FunctionCallee F = CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(ClassnfABIPtrTy, params, false),
+ "objc_loadClassref",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ {llvm::Attribute::NonLazyBind,
+ llvm::Attribute::ReadNone,
+ llvm::Attribute::NoUnwind}));
+ if (!CGM.getTriple().isOSBinFormatCOFF())
+ cast<llvm::Function>(F.getCallee())->setLinkage(
+ llvm::Function::ExternalWeakLinkage);
+
+ return F;
+ }
+
llvm::StructType *EHTypeTy;
llvm::Type *EHTypePtrTy;
@@ -877,6 +904,9 @@ protected:
/// DefinedCategories - List of defined categories.
SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
+ /// DefinedStubCategories - List of defined categories on class stubs.
+ SmallVector<llvm::GlobalValue*, 16> DefinedStubCategories;
+
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
@@ -1464,6 +1494,12 @@ private:
bool isMetaclass,
ForDefinition_t isForDefinition);
+ llvm::Constant *GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID);
+
+ llvm::Value *EmitLoadOfClassRef(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *ID,
+ llvm::GlobalVariable *Entry);
+
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
llvm::Value *EmitClassRef(CodeGenFunction &CGF,
@@ -1933,7 +1969,7 @@ llvm::Constant *CGObjCNonFragileABIMac::getNSConstantStringClassRef() {
std::string str =
StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
: "OBJC_CLASS_$_" + StringClass;
- auto GV = GetClassGlobal(str, NotForDefinition);
+ llvm::Constant *GV = GetClassGlobal(str, NotForDefinition);
// Make sure the result is of the correct type.
auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo());
@@ -6069,6 +6105,9 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
GetSectionName("__objc_catlist",
"regular,no_dead_strip"));
+ AddModuleClassList(DefinedStubCategories, "OBJC_LABEL_STUB_CATEGORY_$",
+ GetSectionName("__objc_catlist2",
+ "regular,no_dead_strip"));
AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
GetSectionName("__objc_nlcatlist",
"regular,no_dead_strip"));
@@ -6560,7 +6599,10 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::GlobalVariable *GCATV =
finishAndCreateGlobal(values, ExtCatName.str(), CGM);
CGM.addCompilerUsedGlobal(GCATV);
- DefinedCategories.push_back(GCATV);
+ if (Interface->hasAttr<ObjCClassStubAttr>())
+ DefinedStubCategories.push_back(GCATV);
+ else
+ DefinedCategories.push_back(GCATV);
// Determine if this category is also "non-lazy".
if (ImplementationIsNonLazy(OCD))
@@ -7236,33 +7278,68 @@ CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name,
return GV;
}
+llvm::Constant *
+CGObjCNonFragileABIMac::GetClassGlobalForClassRef(const ObjCInterfaceDecl *ID) {
+ llvm::Constant *ClassGV = GetClassGlobal(ID, /*metaclass*/ false,
+ NotForDefinition);
+
+ if (!ID->hasAttr<ObjCClassStubAttr>())
+ return ClassGV;
+
+ ClassGV = llvm::ConstantExpr::getPointerCast(ClassGV, ObjCTypes.Int8PtrTy);
+
+ // Stub classes are pointer-aligned. Classrefs pointing at stub classes
+ // must set the least significant bit set to 1.
+ auto *Idx = llvm::ConstantInt::get(CGM.Int32Ty, 1);
+ return llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, ClassGV, Idx);
+}
+
+llvm::Value *
+CGObjCNonFragileABIMac::EmitLoadOfClassRef(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *ID,
+ llvm::GlobalVariable *Entry) {
+ if (ID && ID->hasAttr<ObjCClassStubAttr>()) {
+ // Classrefs pointing at Objective-C stub classes must be loaded by calling
+ // a special runtime function.
+ return CGF.EmitRuntimeCall(
+ ObjCTypes.getLoadClassrefFn(), Entry, "load_classref_result");
+ }
+
+ CharUnits Align = CGF.getPointerAlign();
+ return CGF.Builder.CreateAlignedLoad(Entry, Align);
+}
+
llvm::Value *
CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II,
const ObjCInterfaceDecl *ID) {
- CharUnits Align = CGF.getPointerAlign();
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
llvm::Constant *ClassGV;
if (ID) {
- ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
+ ClassGV = GetClassGlobalForClassRef(ID);
} else {
ClassGV = GetClassGlobal((getClassSymbolPrefix() + II->getName()).str(),
NotForDefinition);
+ assert(ClassGV->getType() == ObjCTypes.ClassnfABIPtrTy &&
+ "classref was emitted with the wrong type?");
}
std::string SectionName =
GetSectionName("__objc_classrefs", "regular,no_dead_strip");
Entry = new llvm::GlobalVariable(
- CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
+ CGM.getModule(), ClassGV->getType(), false,
getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
"OBJC_CLASSLIST_REFERENCES_$_");
- Entry->setAlignment(Align.getQuantity());
- Entry->setSection(SectionName);
+ Entry->setAlignment(CGF.getPointerAlign().getQuantity());
+ if (!ID || !ID->hasAttr<ObjCClassStubAttr>())
+ Entry->setSection(SectionName);
+
CGM.addCompilerUsedGlobal(Entry);
}
- return CGF.Builder.CreateAlignedLoad(Entry, Align);
+
+ return EmitLoadOfClassRef(CGF, ID, Entry);
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
@@ -7284,22 +7361,22 @@ llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
llvm::Value *
CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- CharUnits Align = CGF.getPointerAlign();
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
if (!Entry) {
- auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition);
+ llvm::Constant *ClassGV = GetClassGlobalForClassRef(ID);
std::string SectionName =
GetSectionName("__objc_superrefs", "regular,no_dead_strip");
Entry = new llvm::GlobalVariable(
- CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
+ CGM.getModule(), ClassGV->getType(), false,
getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
"OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(Align.getQuantity());
+ Entry->setAlignment(CGF.getPointerAlign().getQuantity());
Entry->setSection(SectionName);
CGM.addCompilerUsedGlobal(Entry);
}
- return CGF.Builder.CreateAlignedLoad(Entry, Align);
+
+ return EmitLoadOfClassRef(CGF, ID, Entry);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
OpenPOWER on IntegriCloud