summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2009-05-20 18:41:51 +0000
committerFariborz Jahanian <fjahanian@apple.com>2009-05-20 18:41:51 +0000
commitd20a03f30827fdb3ae4fb48522bb6b92fd31c846 (patch)
tree990650454dc9417782f41e1194854256d0648316
parente5370f409bc5f308f26e79ee5dd1595f83667c2e (diff)
downloadbcm5719-llvm-d20a03f30827fdb3ae4fb48522bb6b92fd31c846.tar.gz
bcm5719-llvm-d20a03f30827fdb3ae4fb48522bb6b92fd31c846.zip
This patch provides preliminary support for non-fragile instance variables on the GNU runtime.
It currently requires a patches to GNU libobjc (and so is not enabled by default) which are currently being tested and reviewed by GNUstep before being pushed upstream. This patch does not allow support for synthesized ivars, but does provide the infrastructure needed for supporting them. Patch by David Chisnall llvm-svn: 72175
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp77
1 files changed, 74 insertions, 3 deletions
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index c351fa25926..2cae9a0ea87 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -41,6 +41,7 @@ using llvm::dyn_cast;
// The version of the runtime that this class targets. Must match the version
// in the runtime.
static const int RuntimeVersion = 8;
+static const int NonFragileRuntimeVersion = 9;
static const int ProtocolVersion = 2;
namespace {
@@ -101,6 +102,8 @@ private:
std::vector<llvm::Constant*> &V, const std::string &Name="");
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
std::vector<llvm::Constant*> &V, const std::string &Name="");
+ llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar);
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *);
@@ -822,6 +825,14 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
llvm::SmallVector<llvm::Constant*, 16> IvarNames;
llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
+
+ int superInstanceSize = !SuperClassDecl ? 0 :
+ Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize() / 8;
+ // For non-fragile ivars, set the instance size to 0 - {the size of just this
+ // class}. The runtime will then set this to the correct value on load.
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ instanceSize = 0 - (instanceSize - superInstanceSize);
+ }
for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
// Store the name
@@ -832,7 +843,14 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
IvarTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
// Get the offset
- uint64_t Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ uint64_t Offset;
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter) -
+ superInstanceSize;
+ ObjCIvarOffsetVariable(ClassDecl, *iter);
+ } else {
+ Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ }
IvarOffsets.push_back(
llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset));
}
@@ -1078,7 +1096,12 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
Elements.clear();
// Runtime version used for compatibility checking.
- Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ Elements.push_back(llvm::ConstantInt::get(LongTy,
+ NonFragileRuntimeVersion));
+ } else {
+ Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
+ }
// sizeof(ModuleTy)
llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
Elements.push_back(llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy)/8));
@@ -1104,6 +1127,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Type::VoidTy, Params, true), "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
+
return LoadFunction;
}
@@ -1468,6 +1492,25 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
return;
}
+llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
+ + '.' + Ivar->getNameAsString();
+ // Emit the variable and initialize it with what we think the correct value
+ // is. This allows code compiled with non-fragile ivars to work correctly
+ // when linked against code which isn't (most of the time).
+ llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name);
+ if (!IvarOffsetGV) {
+ uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+ llvm::ConstantInt *OffsetGuess =
+ llvm::ConstantInt::get(LongTy, Offset, "ivar");
+ IvarOffsetGV = new llvm::GlobalVariable(LongTy, false,
+ llvm::GlobalValue::CommonLinkage, OffsetGuess, Name, &TheModule);
+ }
+ return IvarOffsetGV;
+}
+
LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
@@ -1477,12 +1520,40 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
+static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *OIVD) {
+ for (ObjCInterfaceDecl::ivar_iterator IVI = OID->ivar_begin(),
+ IVE = OID->ivar_end(); IVI != IVE; ++IVI)
+ if (OIVD == *IVI)
+ return OID;
+
+ // Also look in synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ Context.CollectSynthesizedIvars(OID, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
+ if (OIVD == Ivars[k])
+ return OID;
+ }
+
+ // Otherwise check in the super class.
+ if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
+ return FindIvarInterface(Context, Super, OIVD);
+
+ return 0;
+}
llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
+ if (CGF.getContext().getLangOptions().ObjCNonFragileABI)
+ {
+ Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
+ return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
+ false, "ivar");
+ }
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
- return llvm::ConstantInt::get(LongTy, Offset);
+ return llvm::ConstantInt::get(LongTy, Offset, "ivar");
}
CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){
OpenPOWER on IntegriCloud