aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGDebugInfo.cpp
diff options
context:
space:
mode:
authorAdrian Prantl <aprantl@apple.com>2013-03-06 22:03:30 +0000
committerAdrian Prantl <aprantl@apple.com>2013-03-06 22:03:30 +0000
commit4919de6a53a007487c6d6b173921b5e7152a2004 (patch)
tree8b5292fac1a7ea0d07ecfa2f2b2c1fd8aea070e3 /lib/CodeGen/CGDebugInfo.cpp
parent42773d64f98db0dd5cc80181c3b2d561851668f7 (diff)
Ensure that DIType is regenerated after we visit an implementation
that adds ivars to an interface. Fixes rdar://13175234 This is an update to r176116 that performs a smart caching of interfaces. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176584 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGDebugInfo.cpp')
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp63
1 files changed, 57 insertions, 6 deletions
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 970ba50b71..8d6352c404 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1343,7 +1343,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
- // Add this to the completed types cache since we're completing it.
+ // Add this to the completed-type cache while we're completing it recursively.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements.
@@ -1436,7 +1436,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Otherwise, insert it into the CompletedTypeCache so that recursive uses
// will find it and we're emitting the complete type.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ QualType QualTy = QualType(Ty, 0);
+ CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
@@ -1561,6 +1562,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
FwdDeclNode->replaceOperandWith(10, Elements);
+
+ // If the implementation is not yet set, we do not want to mark it
+ // as complete. An implementation may declare additional
+ // private ivars that we would miss otherwise.
+ if (ID->getImplementation() == 0)
+ CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
LexicalBlockStack.pop_back();
return llvm::DIType(FwdDeclNode);
@@ -1790,14 +1797,28 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
// Check for existing entry.
+ llvm::Value *V = 0;
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
CompletedTypeCache.find(Ty.getAsOpaquePtr());
- if (it != CompletedTypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
+ if (it != CompletedTypeCache.end())
+ V = it->second;
+ else {
+ // Is there a cached interface that hasn't changed?
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr());
+
+ if (it1 != ObjCInterfaceCache.end())
+ if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty))
+ if (Checksum(Decl) == it1->second.second) {
+ // Return cached type.
+ V = it1->second.first;
+ }
}
+ // Verify that any cached debug info still exists.
+ if (V != 0)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+
return llvm::DIType();
}
@@ -1824,6 +1845,16 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
static_cast<llvm::Value*>(TC)));
+ // Do not cache the type if it may be incomplete.
+ if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) {
+ // clang::ParseAST handles each TopLevelDecl immediately after it was parsed.
+ // A subsequent implementation may add more ivars to an interface, which is
+ // why we cache it together with a checksum to see if it changed.
+ ObjCInterfaceCache[Ty.getAsOpaquePtr()] =
+ std::make_pair(Res, Checksum(Decl));
+ return Res;
+ }
+
// And update the type cache.
TypeCache[Ty.getAsOpaquePtr()] = Res;
@@ -1833,6 +1864,26 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
return Res;
}
+/// Currently the checksum merely consists of the number of ivars.
+unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl
+ *InterfaceDecl) {
+ unsigned IvarNo = 0;
+ for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin();
+ Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo;
+ return IvarNo;
+}
+
+ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
+ switch (Ty->getTypeClass()) {
+ case Type::ObjCObjectPointer:
+ return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(Ty)->getDecl();
+ default:
+ return 0;
+ }
+}
+
/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.