diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp | 252 |
1 files changed, 152 insertions, 100 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 54d0ff2..7c679b9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -16,7 +16,8 @@ #include "CGRecordLayout.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" -#include "CGException.h" +#include "CGBlocks.h" +#include "CGCleanup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -77,6 +78,7 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, ++Index; } assert(Index != Ivars.size() && "Ivar is not inside container!"); + assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); return RL->getFieldOffset(Index); } @@ -129,7 +131,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // a synthesized ivar can never be a bit-field, so this is safe. const ASTRecordLayout &RL = CGF.CGM.getContext().getASTObjCInterfaceLayout(OID); - uint64_t TypeSizeInBits = RL.getSize(); + uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize()); uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); uint64_t BitOffset = FieldBitOffset % 8; uint64_t ContainingTypeAlign = 8; @@ -462,7 +464,7 @@ public: // void objc_exception_rethrow(void) std::vector<const llvm::Type*> Args; llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, true); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow"); } @@ -999,8 +1001,8 @@ public: /// forward references will be filled in with empty bodies if no /// definition is seen. The return value has type ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; - virtual llvm::Constant *GCBlockLayout(CodeGen::CodeGenFunction &CGF, - const llvm::SmallVectorImpl<const BlockDeclRefExpr *> &); + virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, + const CGBlockInfo &blockInfo); }; @@ -1156,7 +1158,8 @@ public: virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); - virtual llvm::Constant *GetCopyStructFunction(); + virtual llvm::Constant *GetGetStructFunction(); + virtual llvm::Constant *GetSetStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF, @@ -1401,7 +1404,10 @@ public: return ObjCTypes.getSetPropertyFn(); } - virtual llvm::Constant *GetCopyStructFunction() { + virtual llvm::Constant *GetSetStructFunction() { + return ObjCTypes.getCopyStructFn(); + } + virtual llvm::Constant *GetGetStructFunction() { return ObjCTypes.getCopyStructFn(); } @@ -1520,7 +1526,7 @@ llvm::Constant *CGObjCCommonMac::GenerateConstantString( const StringLiteral *SL) { return (CGM.getLangOptions().NoConstantCFStrings == 0 ? CGM.GetAddrOfConstantCFString(SL) : - CGM.GetAddrOfConstantNSString(SL)); + CGM.GetAddrOfConstantString(SL)); } /// Generates a message send where the super is the receiver. This is @@ -1662,57 +1668,76 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { return Qualifiers::GCNone; } -llvm::Constant *CGObjCCommonMac::GCBlockLayout(CodeGen::CodeGenFunction &CGF, - const llvm::SmallVectorImpl<const BlockDeclRefExpr *> &DeclRefs) { - llvm::Constant *NullPtr = +llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + llvm::Constant *nullPtr = llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); - if ((CGM.getLangOptions().getGCMode() == LangOptions::NonGC) || - DeclRefs.empty()) - return NullPtr; + + if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + return nullPtr; + bool hasUnion = false; SkipIvars.clear(); IvarsInfo.clear(); unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0); unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth(); - for (size_t i = 0; i < DeclRefs.size(); ++i) { - const BlockDeclRefExpr *BDRE = DeclRefs[i]; - const ValueDecl *VD = BDRE->getDecl(); - CharUnits Offset = CGF.BlockDecls[VD]; - uint64_t FieldOffset = Offset.getQuantity(); - QualType Ty = VD->getType(); - assert(!Ty->isArrayType() && - "Array block variable should have been caught"); - if ((Ty->isRecordType() || Ty->isUnionType()) && !BDRE->isByRef()) { - BuildAggrIvarRecordLayout(Ty->getAs<RecordType>(), - FieldOffset, - true, - hasUnion); + // __isa is the first field in block descriptor and must assume by runtime's + // convention that it is GC'able. + IvarsInfo.push_back(GC_IVAR(0, 1)); + + const BlockDecl *blockDecl = blockInfo.getBlockDecl(); + + // Calculate the basic layout of the block structure. + const llvm::StructLayout *layout = + CGM.getTargetData().getStructLayout(blockInfo.StructureType); + + // Ignore the optional 'this' capture: C++ objects are not assumed + // to be GC'ed. + + // Walk the captured variables. + for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), + ce = blockDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType type = variable->getType(); + + const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); + + // Ignore constant captures. + if (capture.isConstant()) continue; + + uint64_t fieldOffset = layout->getElementOffset(capture.getIndex()); + + // __block variables are passed by their descriptor address. + if (ci->isByRef()) { + IvarsInfo.push_back(GC_IVAR(fieldOffset, /*size in words*/ 1)); + continue; + } + + assert(!type->isArrayType() && "array variable should not be caught"); + if (const RecordType *record = type->getAs<RecordType>()) { + BuildAggrIvarRecordLayout(record, fieldOffset, true, hasUnion); continue; } - Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), Ty); - unsigned FieldSize = CGM.getContext().getTypeSize(Ty); - // __block variables are passed by their descriptior address. So, size - // must reflect this. - if (BDRE->isByRef()) - FieldSize = WordSizeInBits; - if (GCAttr == Qualifiers::Strong || BDRE->isByRef()) - IvarsInfo.push_back(GC_IVAR(FieldOffset, - FieldSize / WordSizeInBits)); + Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type); + unsigned fieldSize = CGM.getContext().getTypeSize(type); + + if (GCAttr == Qualifiers::Strong) + IvarsInfo.push_back(GC_IVAR(fieldOffset, + fieldSize / WordSizeInBits)); else if (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak) - SkipIvars.push_back(GC_IVAR(FieldOffset, - FieldSize / ByteSizeInBits)); + SkipIvars.push_back(GC_IVAR(fieldOffset, + fieldSize / ByteSizeInBits)); } if (IvarsInfo.empty()) - return NullPtr; - // Sort on byte position in case we encounterred a union nested in - // block variable type's aggregate type. - if (hasUnion && !IvarsInfo.empty()) - std::sort(IvarsInfo.begin(), IvarsInfo.end()); - if (hasUnion && !SkipIvars.empty()) - std::sort(SkipIvars.begin(), SkipIvars.end()); + return nullPtr; + + // Sort on byte position; captures might not be allocated in order, + // and unions can do funny things. + llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end()); + llvm::array_pod_sort(SkipIvars.begin(), SkipIvars.end()); std::string BitMap; llvm::Constant *C = BuildIvarLayoutBitmap(BitMap); @@ -2189,10 +2214,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { if (ID->getNumIvarInitializers()) Flags |= eClassFlags_HasCXXStructors; unsigned Size = - CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8; + CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity(); // FIXME: Set CXX-structors flag. - if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden) + if (ID->getClassInterface()->getVisibility() == HiddenVisibility) Flags |= eClassFlags_Hidden; std::vector<llvm::Constant*> InstanceMethods, ClassMethods; @@ -2277,7 +2302,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, unsigned Flags = eClassFlags_Meta; unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy); - if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden) + if (ID->getClassInterface()->getVisibility() == HiddenVisibility) Flags |= eClassFlags_Hidden; std::vector<llvm::Constant*> Values(12); @@ -2578,7 +2603,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } -llvm::Constant *CGObjCMac::GetCopyStructFunction() { +llvm::Constant *CGObjCMac::GetGetStructFunction() { + return ObjCTypes.getCopyStructFn(); +} +llvm::Constant *CGObjCMac::GetSetStructFunction() { return ObjCTypes.getCopyStructFn(); } @@ -2968,6 +2996,10 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "_call_try_exit"); + // A slot containing the exception to rethrow. Only needed when we + // have both a @catch and a @finally. + llvm::Value *PropagatingExnVar = 0; + // Push a normal cleanup to leave the try scope. CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S, SyncArgSlot, @@ -3039,6 +3071,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *CatchBlock = 0; llvm::BasicBlock *CatchHandler = 0; if (HasFinally) { + // Save the currently-propagating exception before + // objc_exception_try_enter clears the exception slot. + PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(), + "propagating_exception"); + CGF.Builder.CreateStore(Caught, PropagatingExnVar); + // Enter a new exception try block (in case a @catch block // throws an exception). CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData) @@ -3090,7 +3128,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF); if (CatchParam) { - CGF.EmitLocalBlockVarDecl(*CatchParam); + CGF.EmitAutoVarDecl(*CatchParam); assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?"); // These types work out because ConvertType(id) == i8*. @@ -3134,7 +3172,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // the end of the catch body. CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF); - CGF.EmitLocalBlockVarDecl(*CatchParam); + CGF.EmitAutoVarDecl(*CatchParam); assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?"); // Initialize the catch variable. @@ -3173,6 +3211,15 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // the try's write hazard and here. //Hazards.emitWriteHazard(); + // Extract the new exception and save it to the + // propagating-exception slot. + assert(PropagatingExnVar); + llvm::CallInst *NewCaught = + CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), + ExceptionData, "caught"); + NewCaught->setDoesNotThrow(); + CGF.Builder.CreateStore(NewCaught, PropagatingExnVar); + // Don't pop the catch handler; the throw already did. CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar); CGF.EmitBranchThroughCleanup(FinallyRethrow); @@ -3193,13 +3240,21 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); CGF.EmitBlock(FinallyRethrow.getBlock(), true); if (CGF.HaveInsertPoint()) { - // Just look in the buffer for the exception to throw. - llvm::CallInst *Caught = - CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData); - Caught->setDoesNotThrow(); + // If we have a propagating-exception variable, check it. + llvm::Value *PropagatingExn; + if (PropagatingExnVar) { + PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar); + + // Otherwise, just look in the buffer for the exception to throw. + } else { + llvm::CallInst *Caught = + CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), + ExceptionData); + Caught->setDoesNotThrow(); + PropagatingExn = Caught; + } - CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), Caught) + CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn) ->setDoesNotThrow(); CGF.Builder.CreateUnreachable(); } @@ -3586,10 +3641,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, uint64_t MaxSkippedUnionIvarSize = 0; FieldDecl *MaxField = 0; FieldDecl *MaxSkippedField = 0; - FieldDecl *LastFieldBitfield = 0; + FieldDecl *LastFieldBitfieldOrUnnamed = 0; uint64_t MaxFieldOffset = 0; uint64_t MaxSkippedFieldOffset = 0; - uint64_t LastBitfieldOffset = 0; + uint64_t LastBitfieldOrUnnamedOffset = 0; if (RecFields.empty()) return; @@ -3609,12 +3664,12 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, // Skip over unnamed or bitfields if (!Field->getIdentifier() || Field->isBitField()) { - LastFieldBitfield = Field; - LastBitfieldOffset = FieldOffset; + LastFieldBitfieldOrUnnamed = Field; + LastBitfieldOrUnnamedOffset = FieldOffset; continue; } - LastFieldBitfield = 0; + LastFieldBitfieldOrUnnamed = 0; QualType FQT = Field->getType(); if (FQT->isRecordType() || FQT->isUnionType()) { if (FQT->isUnionType()) @@ -3641,7 +3696,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, assert(!FQT->isUnionType() && "layout for array of unions not supported"); - if (FQT->isRecordType()) { + if (FQT->isRecordType() && ElCount) { int OldIndex = IvarsInfo.size() - 1; int OldSkIndex = SkipIvars.size() -1; @@ -3703,16 +3758,25 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, } } - if (LastFieldBitfield) { - // Last field was a bitfield. Must update skip info. - Expr *BitWidth = LastFieldBitfield->getBitWidth(); - uint64_t BitFieldSize = - BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - GC_IVAR skivar; - skivar.ivar_bytepos = BytePos + LastBitfieldOffset; - skivar.ivar_size = (BitFieldSize / ByteSizeInBits) - + ((BitFieldSize % ByteSizeInBits) != 0); - SkipIvars.push_back(skivar); + if (LastFieldBitfieldOrUnnamed) { + if (LastFieldBitfieldOrUnnamed->isBitField()) { + // Last field was a bitfield. Must update skip info. + Expr *BitWidth = LastFieldBitfieldOrUnnamed->getBitWidth(); + uint64_t BitFieldSize = + BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); + GC_IVAR skivar; + skivar.ivar_bytepos = BytePos + LastBitfieldOrUnnamedOffset; + skivar.ivar_size = (BitFieldSize / ByteSizeInBits) + + ((BitFieldSize % ByteSizeInBits) != 0); + SkipIvars.push_back(skivar); + } else { + assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed"); + // Last field was unnamed. Must update skip info. + unsigned FieldSize + = CGM.getContext().getTypeSize(LastFieldBitfieldOrUnnamed->getType()); + SkipIvars.push_back(GC_IVAR(BytePos + LastBitfieldOrUnnamedOffset, + FieldSize / ByteSizeInBits)); + } } if (MaxField) @@ -4886,7 +4950,7 @@ void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID, CGM.getContext().getASTObjCImplementationLayout(OID); // InstanceSize is really instance end. - InstanceSize = llvm::RoundUpToAlignment(RL.getDataSize(), 8) / 8; + InstanceSize = RL.getDataSize().getQuantity(); // If there are no fields, the start is the same as the end. if (!RL.getFieldCount()) @@ -4927,7 +4991,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { llvm::GlobalVariable *SuperClassGV, *IsAGV; bool classIsHidden = - CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden; + ID->getClassInterface()->getVisibility() == HiddenVisibility; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; if (ID->getNumIvarInitializers()) @@ -5222,7 +5286,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, // well (i.e., in ObjCIvarOffsetVariable). if (Ivar->getAccessControl() == ObjCIvarDecl::Private || Ivar->getAccessControl() == ObjCIvarDecl::Package || - CGM.getDeclVisibilityMode(ID) == LangOptions::Hidden) + ID->getVisibility() == HiddenVisibility) IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility); else IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -6096,7 +6160,7 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); - CGF.EmitLocalBlockVarDecl(*CatchParam); + CGF.EmitAutoVarDecl(*CatchParam); CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam)); } @@ -6124,32 +6188,20 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, /// EmitThrowStmt - Generate code for a throw statement. void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { - llvm::Value *Exception; - llvm::Constant *FunctionThrowOrRethrow; if (const Expr *ThrowExpr = S.getThrowExpr()) { - Exception = CGF.EmitScalarExpr(ThrowExpr); - FunctionThrowOrRethrow = ObjCTypes.getExceptionThrowFn(); - } else { - assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && - "Unexpected rethrow outside @catch block."); - Exception = CGF.ObjCEHValueStack.back(); - FunctionThrowOrRethrow = ObjCTypes.getExceptionRethrowFn(); - } - - llvm::Value *ExceptionAsObject = - CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp"); - llvm::BasicBlock *InvokeDest = CGF.getInvokeDest(); - if (InvokeDest) { - CGF.Builder.CreateInvoke(FunctionThrowOrRethrow, - CGF.getUnreachableBlock(), InvokeDest, - &ExceptionAsObject, &ExceptionAsObject + 1); + llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); + Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, + "tmp"); + llvm::Value *Args[] = { Exception }; + CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), + Args, Args+1) + .setDoesNotReturn(); } else { - CGF.Builder.CreateCall(FunctionThrowOrRethrow, ExceptionAsObject) - ->setDoesNotReturn(); - CGF.Builder.CreateUnreachable(); + CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn(), 0, 0) + .setDoesNotReturn(); } - // Clear the insertion point to indicate we are in unreachable code. + CGF.Builder.CreateUnreachable(); CGF.Builder.ClearInsertionPoint(); } @@ -6208,7 +6260,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, ID->getIdentifier()->getName())); } - if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden) + if (CGM.getLangOptions().getVisibilityMode() == HiddenVisibility) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); Entry->setAlignment(CGM.getTargetData().getABITypeAlignment( ObjCTypes.EHTypeTy)); |