Index: CGObjCGNU.cpp
===================================================================
--- CGObjCGNU.cpp	(revision 48418)
+++ CGObjCGNU.cpp	(working copy)
@@ -1,4 +1,4 @@
-//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
+//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// 
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -17,60 +17,104 @@
 #include "llvm/Support/LLVMBuilder.h"
 #include "llvm/ADT/SmallVector.h"
 
-using namespace clang::CodeGen;
-using namespace clang;
 
-CGObjCRuntime::~CGObjCRuntime() {}
+clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {}
 
 namespace {
-class CGObjCGNU : public CGObjCRuntime {
+class CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
 private:
   llvm::Module &TheModule;
+  const llvm::Type *SelectorTy;
+  const llvm::Type *PtrToInt8Ty;
+  const llvm::Type *IMPTy;
+  const llvm::Type *IntTy;
+  const llvm::Type *PtrToIntTy;
 public:
-  CGObjCGNU(llvm::Module &M) : TheModule(M) {};
+  CGObjCGNU(llvm::Module &M);
   virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
                                            const llvm::Type *ReturnTy,
                                            llvm::Value *Receiver,
                                            llvm::Constant *Selector,
                                            llvm::Value** ArgV,
                                            unsigned ArgC);
+  llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
+      llvm::Value *SelName,
+      llvm::Value *SelTypes);
+  llvm::Value *GenerateIvarList(llvm::LLVMFoldingBuilder &Builder,
+      std::vector<llvm::Constant*> MethodNames,
+      std::vector<llvm::Constant*> MethodTypes,
+      std::vector<llvm::Constant*> MethodIMPs);
+  llvm::Value *GenerateMethodList(llvm::LLVMFoldingBuilder &Builder,
+      std::vector<llvm::Constant*> MethodNames,
+      std::vector<llvm::Constant*> MethodTypes,
+      std::vector<llvm::Constant*> MethodIMPs);
 };
 } // end anonymous namespace
 
+CGObjCGNU::CGObjCGNU(llvm::Module &M) : TheModule(M) 
+{
+  // C string type.  Used in lots of places.
+  PtrToInt8Ty = 
+    llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+  // Get the selector Type.
+  std::vector<const llvm::Type*> Str2(2, PtrToInt8Ty);
+  const llvm::Type *SelStructTy = llvm::StructType::get(Str2);
+  SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
+  // FIXME: Should be host native word size
+  IntTy = llvm::Type::Int32Ty;
+  PtrToInt8Ty = llvm::PointerType::getUnqual(IntTy);
+}
+
+#define GEP(value, index) \
+  (Builder.CreateGEP(value, \
+      llvm::ConstantInt::get(llvm::Type::Int32Ty, index)))
+
+// Looks up the selector for the specified name / type pair.
+llvm::Value *CGObjCGNU::getSelector(llvm::LLVMFoldingBuilder &Builder,
+    llvm::Value *SelName,
+    llvm::Value *SelTypes)
+{
+  llvm::Value *cmd;
+  // Look up the selector.
+  if(SelTypes == 0) {
+    llvm::Constant *SelFunction = 
+      TheModule.getOrInsertFunction("sel_get_uid", SelectorTy, PtrToInt8Ty, NULL);
+    cmd = Builder.CreateCall(SelFunction, &SelName, &SelName+1);
+  }
+  else {
+    llvm::Constant *SelFunction = 
+      TheModule.getOrInsertFunction("sel_get_typed_uid",
+          SelectorTy,
+          PtrToInt8Ty,
+          PtrToInt8Ty,
+          NULL);
+    cmd = Builder.CreateCall(SelFunction, &SelName, &SelName+1);
+  }
+  return cmd;
+}
+
+
 // Generate code for a message send expression on the GNU runtime.
 // BIG FAT WARNING: Much of this code will need factoring out later.
-// FIXME: This currently only handles id returns.  Other return types 
-// need some explicit casting.
+// TODO: This should take a sender argument (pointer to self in the calling
+// context)
 llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
                                             const llvm::Type *ReturnTy,
                                             llvm::Value *Receiver,
                                             llvm::Constant *Selector,
                                             llvm::Value** ArgV,
                                             unsigned ArgC) {
-  // Get the selector Type.
-  const llvm::Type *PtrToInt8Ty = 
-    llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
-  std::vector<const llvm::Type*> Str2(2, PtrToInt8Ty);
-  const llvm::Type *SelStructTy = llvm::StructType::get(Str2);
-  const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy);
-
-  // Look up the selector.
-  // If we haven't got the selector lookup function, look it up now.
-  // TODO: Factor this out and use it to implement @selector() too.
-  llvm::Constant *SelFunction = 
-    TheModule.getOrInsertFunction("sel_get_uid", SelTy, PtrToInt8Ty, NULL);
   // FIXME: Selectors should be statically cached, not looked up on every call.
-
   // TODO: Pull this out into the caller.
   llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
   llvm::Constant *Ops[] = {Idx0, Idx0};
   llvm::Value *SelStr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2);
-  llvm::Value *cmd = Builder.CreateCall(SelFunction, &SelStr, &SelStr+1);
+  llvm::Value *cmd = getSelector(Builder, SelStr, 0);
 
   // Look up the method implementation.
   std::vector<const llvm::Type*> impArgTypes;
   impArgTypes.push_back(Receiver->getType());
-  impArgTypes.push_back(SelTy);
+  impArgTypes.push_back(SelectorTy);
   
   // Avoid an explicit cast on the IMP by getting a version that has the right
   // return type.
@@ -80,7 +124,7 @@
   llvm::Constant *lookupFunction = 
      TheModule.getOrInsertFunction("objc_msg_lookup",
                                    llvm::PointerType::get(impType, 0),
-                                   Receiver->getType(), SelTy, NULL);
+                                   Receiver->getType(), SelectorTy, NULL);
   llvm::SmallVector<llvm::Value*, 16> lookupArgs;
   lookupArgs.push_back(Receiver);
   lookupArgs.push_back(cmd);
@@ -92,6 +136,107 @@
   return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
 }
 
-CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) {
+// Generates a MethodList.  Used in construction of a objc_class and 
+// objc_category structures.
+llvm::Value *CGObjCGNU::GenerateMethodList(llvm::LLVMFoldingBuilder &Builder,
+    std::vector<llvm::Constant*> MethodNames,
+    std::vector<llvm::Constant*> MethodTypes,
+    std::vector<llvm::Constant*> MethodIMPs) {
+  // Get the method structure type.  
+  std::vector<const llvm::Type*> ObjCMethodFields;
+  ObjCMethodFields.push_back(SelectorTy);
+  ObjCMethodFields.push_back(PtrToInt8Ty);
+  ObjCMethodFields.push_back(IMPTy);
+  llvm::Type *ObjCMethodTy = llvm::StructType::get(ObjCMethodFields);
+
+  // Array of method structures
+  llvm::Type *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy,
+      MethodNames.size());
+
+  // Structure containing list pointer, array and array count
+  std::vector<const llvm::Type*> ObjCMethodListFields;
+  llvm::OpaqueType *OpaqueNextTy = llvm::OpaqueType::get();
+  llvm::Type *NextPtrTy = llvm::PointerType::get(OpaqueNextTy, 0);
+  ObjCMethodListFields.push_back(NextPtrTy);
+
+  ObjCMethodListFields.push_back(IntTy);
+  ObjCMethodListFields.push_back(ObjCMethodArrayTy);
+  llvm::Type *ObjCMethodListTy = llvm::StructType::get(ObjCMethodListFields);
+
+  // Refine next pointer type to concrete type
+  OpaqueNextTy->refineAbstractTypeTo(
+      ObjCMethodListTy);
+
+  // Create an instance of the structure
+  llvm::Value *MethodList = Builder.CreateMalloc(ObjCMethodListTy);
+  llvm::Value *MethodArray = GEP(MethodList, 3);
+  
+  // FIXME: This should use an iterator.  And possibly a more sensible
+  // data structure than just three vectors.
+  for(unsigned int i=0 ; i<1 ; i++) {
+    llvm::Value *MethodStruct = GEP(MethodArray, i);
+    // Store the selector
+    llvm::Value *MethodNamePtr = GEP(MethodStruct, 0);
+    llvm::Value *Selector = getSelector(Builder, MethodNames[i], MethodTypes[i]);
+    Builder.CreateStore(Selector, MethodNamePtr);
+
+    // Store the types
+    llvm::Value *MethodTypesPtr = GEP(MethodStruct, 1);
+    Builder.CreateStore(MethodTypes[i], MethodTypesPtr);
+
+    // Store the IMP
+    llvm::Value *MethodIMPPtr = GEP(MethodStruct, 2);
+    Builder.CreateStore(MethodIMPs[i], MethodIMPPtr);
+  }
+  return MethodList;
+}
+
+// Generates an IvarList.  Used in construction of a objc_class
+llvm::Value *CGObjCGNU::GenerateIvarList(llvm::LLVMFoldingBuilder &Builder,
+    std::vector<llvm::Constant*> IvarNames,
+    std::vector<llvm::Constant*> IvarTypes,
+    std::vector<llvm::Constant*> IvarOffsets) {
+  // Get the method structure type.  
+  std::vector<const llvm::Type*> ObjCIvarFields;
+  ObjCIvarFields.push_back(PtrToInt8Ty);
+  ObjCIvarFields.push_back(PtrToInt8Ty);
+  ObjCIvarFields.push_back(IntTy);
+  llvm::Type *ObjCIvarTy = llvm::StructType::get(ObjCIvarFields);
+
+  // Array of method structures
+  llvm::Type *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
+      IvarNames.size());
+
+  // Structure containing array and array count
+  std::vector<const llvm::Type*> ObjCIvarListFields;
+  ObjCIvarListFields.push_back(IntTy);
+  ObjCIvarListFields.push_back(ObjCIvarArrayTy);
+  llvm::Type *ObjCIvarListTy = llvm::StructType::get(ObjCIvarListFields);
+
+  // Create an instance of the structure
+  llvm::Value *IvarList = Builder.CreateMalloc(ObjCIvarListTy);
+  llvm::Value *IvarArray = GEP(IvarList, 3);
+  
+  // FIXME: This should use an iterator.  And possibly a more sensible
+  // data structure than just three vectors.
+  for(unsigned int i=0 ; i<1 ; i++) {
+    llvm::Value *IvarStruct = GEP(IvarArray, i);
+    // Store the name
+    llvm::Value *IvarNamePtr = GEP(IvarStruct, 0);
+    Builder.CreateStore(IvarNames[i], IvarNamePtr);
+
+    // Store the types
+    llvm::Value *IvarTypesPtr = GEP(IvarStruct, 1);
+    Builder.CreateStore(IvarTypes[i], IvarTypesPtr);
+
+    // Store the fffset
+    llvm::Value *IvarOffsetPtr = GEP(IvarStruct, 2);
+    Builder.CreateStore(IvarOffsets[i], IvarOffsetPtr);
+  }
+  return IvarList;
+}
+
+clang::CodeGen::CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(
+    llvm::Module &M) {
   return new CGObjCGNU(M);
 }
