Index: lib/CodeGen/CGObjCGNU.cpp
===================================================================
--- lib/CodeGen/CGObjCGNU.cpp	(revision 48734)
+++ lib/CodeGen/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
 //
@@ -11,66 +11,149 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <stdarg.h>
 #include "CGObjCRuntime.h"
 #include "llvm/Module.h"
 #include "llvm/Support/Compiler.h"
 #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 *IdTy;
+  const llvm::Type *IntTy;
+  const llvm::Type *PtrTy;
+  const llvm::Type *LongTy;
+  const llvm::Type *PtrToIntTy;
 public:
-  CGObjCGNU(llvm::Module &M) : TheModule(M) {};
+  CGObjCGNU(llvm::Module &Mp,
+    const llvm::Type *LLVMIntType,
+    const llvm::Type *LLVMLongType);
   virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
                                            const llvm::Type *ReturnTy,
+                                           llvm::Value *Sender,
                                            llvm::Value *Receiver,
-                                           llvm::Constant *Selector,
+                                           llvm::Value *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);
+  llvm::Value *GenerateClassStructure(
+      llvm::LLVMFoldingBuilder &Builder,
+      llvm::Value *MetaClass,
+      llvm::Value *SuperClass,
+      llvm::Value *Name,
+      llvm::Value *Version,
+      llvm::Value *InstanceSize,
+      llvm::Value *IVars,
+      llvm::Value *Methods);
+  virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
+                                 const llvm::Type *SelfTy,
+                                 const llvm::Type **ArgTy,
+                                 unsigned ArgC,
+                                 bool isVarArg);
 };
 } // end anonymous namespace
 
+CGObjCGNU::CGObjCGNU(llvm::Module &M,
+    const llvm::Type *LLVMIntType,
+    const llvm::Type *LLVMLongType) : 
+  TheModule(M),
+  IntTy(LLVMIntType),
+  LongTy(LLVMLongType)
+{
+  // 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);
+  PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
+  PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ 
+  // Object type
+  llvm::OpaqueType *OpaqueObjTy = llvm::OpaqueType::get();
+  llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
+  IdTy = llvm::PointerType::getUnqual(llvm::StructType::get(OpaqueIdTy, 0));
+  OpaqueObjTy->refineAbstractTypeTo(IdTy);
+ 
+  // IMP type
+  std::vector<const llvm::Type*> IMPArgs;
+  IMPArgs.push_back(IdTy);
+  IMPArgs.push_back(SelectorTy);
+  IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+
+}
+
+#define SET(structure, index, value) do {\
+    llvm::Value *element_ptr = Builder.CreateStructGEP(structure, index);\
+    Builder.CreateStore(value, element_ptr);} while(0)
+
+
+// Looks up the selector for the specified name / type pair.
+// FIXME: Selectors should be statically cached, not looked up on every call.
+llvm::Value *CGObjCGNU::getSelector(llvm::LLVMFoldingBuilder &Builder,
+    llvm::Value *SelName,
+    llvm::Value *SelTypes)
+{
+  // Look up the selector.
+  llvm::Value *cmd;
+  if(SelTypes == 0) {
+    llvm::Constant *SelFunction = 
+      TheModule.getOrInsertFunction("sel_get_uid", SelectorTy, PtrToInt8Ty, NULL);
+    cmd = Builder.CreateCall(SelFunction, SelName);
+  }
+  else {
+    llvm::Constant *SelFunction = 
+      TheModule.getOrInsertFunction("sel_get_typed_uid",
+          SelectorTy,
+          PtrToInt8Ty,
+          PtrToInt8Ty,
+          NULL);
+    llvm::SmallVector<llvm::Value*, 2> Args;
+    Args.push_back(SelName);
+    Args.push_back(SelTypes);
+    cmd = Builder.CreateCall(SelFunction, Args.begin(), Args.end());
+  }
+  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 *Sender,
                                             llvm::Value *Receiver,
-                                            llvm::Constant *Selector,
+                                            llvm::Value *Selector,
                                             llvm::Value** ArgV,
                                             unsigned ArgC) {
-  // Get the selector Type.
-  const llvm::Type *PtrToInt8Ty = 
-    llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
-  const llvm::Type *SelStructTy = 
-    llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL);
-  const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy);
+  llvm::Value *cmd = getSelector(Builder, Selector, 0);
 
-  // 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);
-
   // 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 +163,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 +175,178 @@
   return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
 }
 
-CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) {
-  return new CGObjCGNU(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.  
+  llvm::Type *ObjCMethodTy = llvm::StructType::get(
+    SelectorTy,
+    PtrToInt8Ty,
+    IMPTy,
+    0);
+
+  // 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);
+
+  llvm::Type *ObjCMethodListTy = llvm::StructType::get(NextPtrTy, 
+      IntTy, 
+      ObjCMethodArrayTy,
+      0);
+
+  // 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 = Builder.CreateStructGEP(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 = Builder.CreateStructGEP(MethodArray, i);
+    // Store the selector
+    llvm::Value *MethodNamePtr = Builder.CreateStructGEP(MethodStruct, 0);
+    llvm::Value *Selector = getSelector(Builder, MethodNames[i], MethodTypes[i]);
+    Builder.CreateStore(Selector, MethodNamePtr);
+
+    // Store the types
+    llvm::Value *MethodTypesPtr = Builder.CreateStructGEP(MethodStruct, 1);
+    Builder.CreateStore(MethodTypes[i], MethodTypesPtr);
+
+    // Store the IMP
+    llvm::Value *MethodIMPPtr = Builder.CreateStructGEP(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.  
+  llvm::Type *ObjCIvarTy = llvm::StructType::get(
+    PtrToInt8Ty,
+    PtrToInt8Ty,
+    IntTy,
+    0);
+
+  // Array of method structures
+  llvm::Type *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
+      IvarNames.size());
+
+  // Structure containing array and array count
+  llvm::Type *ObjCIvarListTy = llvm::StructType::get(IntTy,
+    ObjCIvarArrayTy,
+    0);
+
+  // Create an instance of the structure
+  llvm::Value *IvarList = Builder.CreateMalloc(ObjCIvarListTy);
+  llvm::Value *IvarArray = Builder.CreateStructGEP(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 = Builder.CreateStructGEP(IvarArray, i);
+    // Store the name
+    llvm::Value *IvarNamePtr = Builder.CreateStructGEP(IvarStruct, 0);
+    Builder.CreateStore(IvarNames[i], IvarNamePtr);
+
+    // Store the types
+    llvm::Value *IvarTypesPtr = Builder.CreateStructGEP(IvarStruct, 1);
+    Builder.CreateStore(IvarTypes[i], IvarTypesPtr);
+
+    // Store the fffset
+    llvm::Value *IvarOffsetPtr = Builder.CreateStructGEP(IvarStruct, 2);
+    Builder.CreateStore(IvarOffsets[i], IvarOffsetPtr);
+  }
+  return IvarList;
+}
+
+// Generate a class structure
+llvm::Value *CGObjCGNU::GenerateClassStructure(
+    llvm::LLVMFoldingBuilder &Builder,
+    llvm::Value *MetaClass,
+    llvm::Value *SuperClass,
+    llvm::Value *Name,
+    llvm::Value *Version,
+    llvm::Value *InstanceSize,
+    llvm::Value *IVars,
+    llvm::Value *Methods) {
+  // Set up the class structure
+  llvm::OpaqueType *OpaqueClassTy = llvm::OpaqueType::get();
+  llvm::Type *PtrToOpaqueClassTy = llvm::PointerType::getUnqual(OpaqueClassTy);
+  llvm::Type *ClassTy = llvm::StructType::get(
+      // TODO: Should these be class names at this point?
+      PtrToOpaqueClassTy, // 0 - class_pointer
+      PtrToOpaqueClassTy, // 1 - super_class
+      PtrToInt8Ty,        // 2 - name
+      LongTy,             // 3 - version
+      LongTy,             // 4 - info
+      LongTy,             // 5 - instance_size
+      IVars->getType(),   // 6 - ivars
+      Methods->getType(), // 7 - methods
+      // These are all filled in by the runtime, so we pretend 
+      PtrTy,              // 8 - dtable
+      PtrTy,              // 9 - subclass_list
+      PtrTy,              // 10 - sibling_class
+      // FIXME: We should be filling this one in
+      PtrTy,              // 11 - protocols
+      PtrTy,              // 12 - gc_object_type
+      0);
+  OpaqueClassTy->refineAbstractTypeTo(ClassTy);
+  // Fill in the structure
+  llvm::Value *NewClass = Builder.CreateMalloc(ClassTy);
+  SET(NewClass, 0, MetaClass);
+  SET(NewClass, 1, SuperClass);
+  SET(NewClass, 2, Name);
+  SET(NewClass, 3, Version);
+  // TODO: info (flags)
+  SET(NewClass, 5, InstanceSize);
+  SET(NewClass, 6, IVars);
+  SET(NewClass, 7, MetaClass);
+  return NewClass;
+}
+
+llvm::Function *CGObjCGNU::MethodPreamble(
+                                         const llvm::Type *ReturnTy,
+                                         const llvm::Type *SelfTy,
+                                         const llvm::Type **ArgTy,
+                                         unsigned ArgC,
+                                         bool isVarArg) {
+  std::vector<const llvm::Type*> Args;
+  Args.push_back(SelfTy);
+  Args.push_back(SelectorTy);
+  for (unsigned i=0; i<ArgC ; i++) {
+    Args.push_back(ArgTy[i]);
+  }
+  llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy, Args, isVarArg);
+  llvm::Function *Method = new llvm::Function(MethodTy,
+      llvm::GlobalValue::InternalLinkage,
+      ".objc.method",
+      &TheModule);
+  // Set the names of the hidden arguments
+  llvm::Function::arg_iterator AI = Method->arg_begin();
+  AI->setName("self");
+  ++AI;
+  AI->setName("_cmd");
+  return Method;
+}
+
+clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
+    llvm::Module &M,
+    const llvm::Type *LLVMIntType,
+    const llvm::Type *LLVMLongType) {
+  return new CGObjCGNU(M, LLVMIntType, LLVMLongType);
+}

