[cfe-commits] r58400 - in /cfe/trunk: lib/CodeGen/CGObjCMac.cpp test/CodeGenObjC/protocols-lazy.m

Daniel Dunbar daniel at zuster.org
Wed Oct 29 15:36:39 PDT 2008


Author: ddunbar
Date: Wed Oct 29 17:36:39 2008
New Revision: 58400

URL: http://llvm.org/viewvc/llvm-project?rev=58400&view=rev
Log:
NeXT: Emit protocol objects lazily.
 - That is, the metadata for a protocol is only emitted if that
   protocol is actually used in the translation unit. This is
   important because Objective-C headers frequently contain a large
   number of protocol definitions, only a few of which will be used in
   any given file.

Added:
    cfe/trunk/test/CodeGenObjC/protocols-lazy.m
Modified:
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=58400&r1=58399&r2=58400&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Wed Oct 29 17:36:39 2008
@@ -21,6 +21,7 @@
 #include "clang/Basic/LangOptions.h"
 
 #include "llvm/Module.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/Support/IRBuilder.h"
 #include "llvm/Target/TargetData.h"
 #include <sstream>
@@ -219,6 +220,10 @@
   /// empty structure whose initializer is filled in when/if defined.
   llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
 
+  /// DefinedProtocols - Protocols which have actually been
+  /// defined. We should not need this, see FIXME in GenerateProtocol.
+  llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
+
   /// DefinedClasses - List of defined classes.
   std::vector<llvm::GlobalValue*> DefinedClasses;
 
@@ -316,6 +321,17 @@
                                    ObjCPropertyDecl * const *begin,
                                    ObjCPropertyDecl * const *end);
 
+  /// GetOrEmitProtocol - Get the protocol object for the given
+  /// declaration, emitting it if necessary. The return value has type
+  /// ProtocolPtrTy.
+  llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
+
+  /// GetOrEmitProtocolRef - Get a forward reference to the protocol
+  /// object for the given declaration, emitting it if needed. These
+  /// forward references will be filled in with empty bodies if no
+  /// definition is seen. The return value has type ProtocolPtrTy.
+  llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
+
   /// EmitProtocolExtension - Generate the protocol extension
   /// structure used to store optional instance and class methods, and
   /// protocol properties. The return value has type
@@ -337,8 +353,8 @@
 
   /// GetProtocolRef - Return a reference to the internal protocol
   /// description, creating an empty one if it has not been
-  /// defined. The return value has type pointer-to ProtocolTy.
-  llvm::GlobalVariable *GetProtocolRef(const ObjCProtocolDecl *PD);
+  /// defined. The return value has type ProtocolPtrTy.
+  llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
 
   /// GetClassName - Return a unique constant for the given selector's
   /// name. The return value has type char *.
@@ -506,7 +522,7 @@
   // and ObjCTypes types.
   const llvm::Type *ClassTy = 
     CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
-  Target = CGF.Builder.CreateBitCast(Target, ClassTy);                                     
+  Target = CGF.Builder.CreateBitCast(Target, ClassTy);
   CGF.Builder.CreateStore(Target, 
                           CGF.Builder.CreateStructGEP(ObjCSuper, 1));
     
@@ -572,6 +588,25 @@
                                         ObjCTypes.ExternalProtocolPtrTy);
 }
 
+void CGObjCMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
+  // FIXME: We shouldn't need this, the protocol decl should contain
+  // enough information to tell us whether this was a declaration or a
+  // definition.
+  DefinedProtocols.insert(PD->getIdentifier());
+
+  // If we have generated a forward reference to this protocol, emit
+  // it now. Otherwise do nothing, the protocol objects are lazily
+  // emitted.
+  if (Protocols.count(PD->getIdentifier())) 
+    GetOrEmitProtocol(PD);
+}
+
+llvm::Constant *CGObjCMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
+  if (DefinedProtocols.count(PD->getIdentifier()))
+    return GetOrEmitProtocol(PD);
+  return GetOrEmitProtocolRef(PD);
+}
+
 /*
      // APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions
   struct _objc_protocol {
@@ -584,7 +619,13 @@
 
   See EmitProtocolExtension().
 */
-void CGObjCMac::GenerateProtocol(const ObjCProtocolDecl *PD) { 
+llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
+  llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+
+  // Early exit if a defining object has already been generated.
+  if (Entry && Entry->hasInitializer())
+    return Entry;
+
   // FIXME: I don't understand why gcc generates this, or where it is
   // resolved. Investigate. Its also wasteful to look this up over and
   // over.
@@ -637,9 +678,9 @@
   llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
                                                    Values);
   
-  llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];  
   if (Entry) {
-    // Already created, just update the initializer
+    // Already created, fix the linkage and update the initializer.
+    Entry->setLinkage(llvm::GlobalValue::InternalLinkage);
     Entry->setInitializer(Init);
   } else {
     Entry = 
@@ -653,25 +694,21 @@
     // FIXME: Is this necessary? Why only for protocol?
     Entry->setAlignment(4);
   }
+
+  return Entry;
 }
 
-llvm::GlobalVariable *CGObjCMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
+llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
   llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
 
   if (!Entry) {
-    std::vector<llvm::Constant*> Values(5);
-    Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
-    Values[1] = GetClassName(PD->getIdentifier());
-    Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
-    Values[3] = Values[4] =
-      llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
-    llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
-                                                     Values);
-
+    // We use the initializer as a marker of whether this is a forward
+    // reference or not. At module finalization we add the empty
+    // contents for protocols which were referenced but never defined.
     Entry = 
       new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false,
-                               llvm::GlobalValue::InternalLinkage,
-                               Init,
+                               llvm::GlobalValue::ExternalLinkage,
+                               0,
                                std::string("\01L_OBJC_PROTOCOL_")+PD->getName(),
                                &CGM.getModule());
     Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
@@ -1510,7 +1547,8 @@
   // Allocate memory for the exception data and rethrow pointer.
   llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
                                                     "exceptiondata.ptr");
-  llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, "_rethrow");
+  llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, 
+                                                 "_rethrow");
   
   // Enter a new try block and call setjmp.
   CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData);
@@ -1988,8 +2026,25 @@
 void CGObjCMac::FinishModule() {
   EmitModuleInfo();
 
-  std::vector<llvm::Constant*> Used;
+  // Emit the dummy bodies for any protocols which were referenced but
+  // never defined.
+  for (llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*>::iterator 
+         i = Protocols.begin(), e = Protocols.end(); i != e; ++i) {
+    if (i->second->hasInitializer())
+      continue;
 
+    std::vector<llvm::Constant*> Values(5);
+    Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
+    Values[1] = GetClassName(i->first);
+    Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
+    Values[3] = Values[4] =
+      llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
+    i->second->setLinkage(llvm::GlobalValue::InternalLinkage);
+    i->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
+                                                        Values));
+  }
+
+  std::vector<llvm::Constant*> Used;
   for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(), 
          e = UsedGlobals.end(); i != e; ++i) {
     Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
@@ -2086,7 +2141,7 @@
                               ProtocolExtensionTy);
   ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
 
-  // Handle recursive construction of Protocl and ProtocolList types
+  // Handle recursive construction of Protocol and ProtocolList types
 
   llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get();
   llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get();

Added: cfe/trunk/test/CodeGenObjC/protocols-lazy.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/protocols-lazy.m?rev=58400&view=auto

==============================================================================
--- cfe/trunk/test/CodeGenObjC/protocols-lazy.m (added)
+++ cfe/trunk/test/CodeGenObjC/protocols-lazy.m Wed Oct 29 17:36:39 2008
@@ -0,0 +1,48 @@
+// RUN: clang -emit-llvm -o %t %s &&
+// RUNX: llvm-gcc -S -emit-llvm -o %t %s &&
+
+// No object generated
+// RUN: grep OBJC_PROTOCOL_P0 %t | count 0 &&
+ at protocol P0;
+
+// No object generated
+// RUN: grep OBJC_PROTOCOL_P1 %t | count 0 &&
+ at protocol P1 -im1; @end
+
+// Definition triggered by protocol reference.
+// RUN: grep OBJC_PROTOCOL_P2 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P2 %t | count 3 &&
+ at protocol P2 -im1; @end
+void f0() { id x = @protocol(P2); }
+
+// Forward definition triggered by protocol reference.
+// RUN: grep OBJC_PROTOCOL_P3 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P3 %t | count 0 &&
+ at protocol P3;
+void f1() { id x = @protocol(P3); }
+
+// Definition triggered by class reference.
+// RUN: grep OBJC_PROTOCOL_P4 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P4 %t | count 3 &&
+ at protocol P4 -im1; @end
+ at interface I0<P4> @end
+ at implementation I0 -im1 {}; @end
+
+// Definition following forward reference.
+// RUN: grep OBJC_PROTOCOL_P5 %t | count 3  &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P5 %t | count 3 &&
+ at protocol P5;
+void f2() { id x = @protocol(P5); } // This generates a forward
+                                    // reference, which has to be
+                                    // updated on the next line.
+ at protocol P5 -im1; @end               
+
+// Protocol reference following definition.
+// RUN: grep OBJC_PROTOCOL_P6 %t | count 4  &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P6 %t | count 3 &&
+ at protocol P6 -im1; @end
+ at interface I1<P6> @end
+ at implementation I1 -im1 {}; @end
+void f3() { id x = @protocol(P6); }
+
+// RUN: true





More information about the cfe-commits mailing list