r208015 - Build debug info for ObjC interface types at the end of the translation unit to ensure all ivars are included.
Jordan Rose
jordan_rose at apple.com
Mon May 5 16:38:41 PDT 2014
@interface is a definition of an ObjC class, but it doesn't contain all the ivars. @implementation can also contain ivars, but it's not in the redeclaration chain for the @interface/@class. Is this going to mess things up at all?
Jordan
On May 5, 2014, at 16:23, David Blaikie <dblaikie at gmail.com> wrote:
> Author: dblaikie
> Date: Mon May 5 18:23:53 2014
> New Revision: 208015
>
> URL: http://llvm.org/viewvc/llvm-project?rev=208015&view=rev
> Log:
> Build debug info for ObjC interface types at the end of the translation unit to ensure all ivars are included.
>
> This takes a different approach than the
> completedType/requiresCompleteType work which relies on AST callbacks to
> upgrade the type declaration to a definition. Instead, just defer
> constructing the definition to the end of the translation unit.
>
> This works because the definition is never needed by other debug info
> (so far as I know), whereas the definition of a struct may be needed by
> other debug info before the end of the translation unit (such as
> emitting the definition of a member function which must refer to that
> member function's declaration).
>
> If we had a callback for whenever an IVar was added to an ObjC interface
> we could use that, and remove the need for the ObjCInterfaceCache, which
> might be nice. (also would need a callback for when it was more than
> just a declaration so we could get properties, etc).
>
> A side benefit is that we also don't need the CompletedTypeCache
> anymore. Just rely on the declaration-ness of a type to decide whether
> its definition is yet to be emitted.
>
> There's still the PR19562 memory leak, but this should hopefully make
> that a bit easier to approach.
>
> Modified:
> cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
> cfe/trunk/lib/CodeGen/CGDebugInfo.h
> cfe/trunk/test/CodeGenObjC/debug-info-ivars-indirect.m
>
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=208015&r1=208014&r2=208015&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon May 5 18:23:53 2014
> @@ -1453,11 +1453,13 @@ void CGDebugInfo::completeClassData(cons
> return;
> QualType Ty = CGM.getContext().getRecordType(RD);
> void* TyPtr = Ty.getAsOpaquePtr();
> - if (CompletedTypeCache.count(TyPtr))
> + auto I = TypeCache.find(TyPtr);
> + if (I != TypeCache.end() &&
> + !llvm::DIType(cast<llvm::MDNode>(static_cast<llvm::Value *>(I->second)))
> + .isForwardDecl())
> return;
> llvm::DIType Res = CreateTypeDefinition(Ty->castAs<RecordType>());
> assert(!Res.isForwardDecl());
> - CompletedTypeCache[TyPtr] = Res;
> TypeCache[TyPtr] = Res;
> }
>
> @@ -1545,9 +1547,6 @@ llvm::DIType CGDebugInfo::CreateTypeDefi
> LexicalBlockStack.push_back(&*FwdDecl);
> RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
>
> - // Add this to the completed-type cache while we're completing it recursively.
> - CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
> -
> // Convert all the elements.
> SmallVector<llvm::Value *, 16> EltTys;
> // what about nested types?
> @@ -1624,15 +1623,24 @@ llvm::DIType CGDebugInfo::CreateType(con
> // If this is just a forward declaration return a special forward-declaration
> // debug type since we won't be able to lay out the entire type.
> ObjCInterfaceDecl *Def = ID->getDefinition();
> - if (!Def) {
> + if (!Def || !Def->getImplementation()) {
> llvm::DIType FwdDecl =
> DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
> ID->getName(), TheCU, DefUnit, Line,
> RuntimeLang);
> + ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit));
> return FwdDecl;
> }
>
> - ID = Def;
> +
> + return CreateTypeDefinition(Ty, Unit);
> +}
> +
> +llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile Unit) {
> + ObjCInterfaceDecl *ID = Ty->getDecl();
> + llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
> + unsigned Line = getLineNumber(ID->getLocation());
> + unsigned RuntimeLang = TheCU.getLanguage();
>
> // Bit size, align and offset of the type.
> uint64_t Size = CGM.getContext().getTypeSize(Ty);
> @@ -1647,10 +1655,8 @@ llvm::DIType CGDebugInfo::CreateType(con
> Line, Size, Align, Flags,
> llvm::DIType(), llvm::DIArray(), RuntimeLang);
>
> - // Otherwise, insert it into the CompletedTypeCache so that recursive uses
> - // will find it and we're emitting the complete type.
> - QualType QualTy = QualType(Ty, 0);
> - CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
> + QualType QTy(Ty, 0);
> + TypeCache[QTy.getAsOpaquePtr()] = RealDecl;
>
> // Push the struct on region stack.
> LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
> @@ -1774,12 +1780,6 @@ llvm::DIType CGDebugInfo::CreateType(con
> llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
> RealDecl.setTypeArray(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 RealDecl;
> }
> @@ -2002,14 +2002,6 @@ llvm::DIType CGDebugInfo::getTypeOrNull(
> // Unwrap the type as needed for debug information.
> Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
>
> - // Check for existing entry.
> - if (Ty->getTypeClass() == Type::ObjCInterface) {
> - llvm::Value *V = getCachedInterfaceTypeOrNull(Ty);
> - if (V)
> - return llvm::DIType(cast<llvm::MDNode>(V));
> - else return llvm::DIType();
> - }
> -
> llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
> TypeCache.find(Ty.getAsOpaquePtr());
> if (it != TypeCache.end()) {
> @@ -2021,27 +2013,6 @@ llvm::DIType CGDebugInfo::getTypeOrNull(
> return llvm::DIType();
> }
>
> -/// getCompletedTypeOrNull - Get the type from the cache or return null if it
> -/// doesn't exist.
> -llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
> -
> - // Unwrap the type as needed for debug information.
> - 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())
> - V = it->second;
> - else {
> - V = getCachedInterfaceTypeOrNull(Ty);
> - }
> -
> - // Verify that any cached debug info still exists.
> - return llvm::DIType(cast_or_null<llvm::MDNode>(V));
> -}
> -
> void CGDebugInfo::completeTemplateDefinition(
> const ClassTemplateSpecializationDecl &SD) {
> if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
> @@ -2053,22 +2024,6 @@ void CGDebugInfo::completeTemplateDefini
> RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
> }
>
> -/// getCachedInterfaceTypeOrNull - Get the type from the interface
> -/// cache, unless it needs to regenerated. Otherwise return null.
> -llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) {
> - // 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 forward declaration.
> - return it1->second.first;
> -
> - return 0;
> -}
> -
> /// getOrCreateType - Get the type from the cache or create a new
> /// one if necessary.
> llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
> @@ -2078,7 +2033,7 @@ llvm::DIType CGDebugInfo::getOrCreateTyp
> // Unwrap the type as needed for debug information.
> Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
>
> - if (llvm::DIType T = getCompletedTypeOrNull(Ty))
> + if (llvm::DIType T = getTypeOrNull(Ty))
> return T;
>
> // Otherwise create the type.
> @@ -2088,37 +2043,6 @@ llvm::DIType CGDebugInfo::getOrCreateTyp
> // And update the type cache.
> TypeCache[TyPtr] = Res;
>
> - // FIXME: this getTypeOrNull call seems silly when we just inserted the type
> - // into the cache - but getTypeOrNull has a special case for cached interface
> - // types. We should probably just pull that out as a special case for the
> - // "else" block below & skip the otherwise needless lookup.
> - llvm::DIType TC = getTypeOrNull(Ty);
> - if (ObjCInterfaceDecl *Decl = getObjCInterfaceDecl(Ty)) {
> - // Interface types may have elements added to them by a
> - // subsequent implementation or extension, so we keep them in
> - // the ObjCInterfaceCache together with a checksum. Instead of
> - // the (possibly) incomplete interface type, we return a forward
> - // declaration that gets RAUW'd in CGDebugInfo::finalize().
> - std::pair<llvm::WeakVH, unsigned> &V = ObjCInterfaceCache[TyPtr];
> - if (V.first)
> - return llvm::DIType(cast<llvm::MDNode>(V.first));
> - TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
> - Decl->getName(), TheCU, Unit,
> - getLineNumber(Decl->getLocation()),
> - TheCU.getLanguage());
> - // Store the forward declaration in the cache.
> - V.first = TC;
> - V.second = Checksum(Decl);
> -
> - // Register the type for replacement in finalize().
> - ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
> -
> - return TC;
> - }
> -
> - if (!Res.isForwardDecl())
> - CompletedTypeCache[TyPtr] = Res;
> -
> return Res;
> }
>
> @@ -2282,13 +2206,6 @@ llvm::DICompositeType CGDebugInfo::Creat
>
> // If we ended up creating the type during the context chain construction,
> // just return that.
> - // FIXME: this could be dealt with better if the type was recorded as
> - // completed before we started this (see the CompletedTypeCache usage in
> - // CGDebugInfo::CreateTypeDefinition(const RecordType*) - that would need to
> - // be pushed to before context creation, but after it was known to be
> - // destined for completion (might still have an issue if this caller only
> - // required a declaration but the context construction ended up creating a
> - // definition)
> llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));
> if (T && (!T.isForwardDecl() || !RD->getDefinition()))
> return T;
> @@ -3393,6 +3310,11 @@ void CGDebugInfo::finalize() {
> Ty.replaceAllUsesWith(RepTy);
> }
>
> + for (auto E : ObjCInterfaceCache)
> + E.Decl.replaceAllUsesWith(E.Type->getDecl()->getDefinition()
> + ? CreateTypeDefinition(E.Type, E.Unit)
> + : E.Decl);
> +
> // We keep our own list of retained types, because we need to look
> // up the final type in the type cache.
> for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
>
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=208015&r1=208014&r2=208015&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Mon May 5 18:23:53 2014
> @@ -67,16 +67,22 @@ class CGDebugInfo {
> /// TypeCache - Cache of previously constructed Types.
> llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
>
> + struct ObjCInterfaceCacheEntry {
> + const ObjCInterfaceType *Type;
> + llvm::DIType Decl;
> + llvm::DIFile Unit;
> + ObjCInterfaceCacheEntry(const ObjCInterfaceType *Type, llvm::DIType Decl,
> + llvm::DIFile Unit)
> + : Type(Type), Decl(Decl), Unit(Unit) {}
> + };
> +
> /// ObjCInterfaceCache - Cache of previously constructed interfaces
> - /// which may change. Storing a pair of DIType and checksum.
> - llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned> > ObjCInterfaceCache;
> + /// which may change.
> + llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
>
> /// RetainedTypes - list of interfaces we want to keep even if orphaned.
> std::vector<void *> RetainedTypes;
>
> - /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
> - llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
> -
> /// ReplaceMap - Cache of forward declared types to RAUW at the end of
> /// compilation.
> std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
> @@ -120,6 +126,7 @@ class CGDebugInfo {
> llvm::DICompositeType CreateLimitedType(const RecordType *Ty);
> void CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType CT);
> llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
> + llvm::DIType CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile F);
> llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
> llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
> llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F);
> @@ -130,7 +137,6 @@ class CGDebugInfo {
> llvm::DIType CreateEnumType(const EnumType *Ty);
> llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
> llvm::DIType getTypeOrNull(const QualType);
> - llvm::DIType getCompletedTypeOrNull(const QualType);
> llvm::DICompositeType getOrCreateMethodType(const CXXMethodDecl *Method,
> llvm::DIFile F);
> llvm::DICompositeType getOrCreateInstanceMethodType(
>
> Modified: cfe/trunk/test/CodeGenObjC/debug-info-ivars-indirect.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/debug-info-ivars-indirect.m?rev=208015&r1=208014&r2=208015&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/debug-info-ivars-indirect.m (original)
> +++ cfe/trunk/test/CodeGenObjC/debug-info-ivars-indirect.m Mon May 5 18:23:53 2014
> @@ -3,6 +3,14 @@
> // Make sure we generate debug symbols for an indirectly referenced
> // extension to an interface.
>
> +// This happens to be the order the members are emitted in... I'm assuming it's
> +// not meaningful/important, so if something causes the order to change, feel
> +// free to update the test to reflect the new order.
> +// CHECK: ; [ DW_TAG_member ] [a]
> +// CHECK: ; [ DW_TAG_member ] [d]
> +// CHECK: ; [ DW_TAG_member ] [c]
> +// CHECK: ; [ DW_TAG_member ] [b]
> +
> @interface I
> {
> @public int a;
> @@ -29,7 +37,6 @@ void gorf (struct S* s) {
> int _b = s->i->b;
> }
>
> -// CHECK: ; [ DW_TAG_member ] [b]
>
> I *source();
>
> @@ -39,8 +46,14 @@ I *source();
> }
> @end
>
> -// CHECK: ; [ DW_TAG_member ] [c]
> -
> void use() {
> int _c = source()->c;
> }
> +
> + at interface I()
> +{
> + @public int d;
> +}
> + at end
> +
> +I *x();
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list