Index: lib/CodeGen/CGObjCRuntime.h
===================================================================
--- lib/CodeGen/CGObjCRuntime.h	(revision 48543)
+++ lib/CodeGen/CGObjCRuntime.h	(working copy)
@@ -22,8 +22,10 @@
   class Type;
   class Value;
   class Module;
+  class Function;
 }
 
+
 namespace clang {
 namespace CodeGen {
 
@@ -35,13 +37,19 @@
   // Generate an Objective-C message send operation
   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) = 0;
+  // Generate the function required to register all Objective-C components in
+  // this compilation unit with the runtime library.
+  virtual llvm::Function *ModuleInitFunction() { return 0; }
 };
 
-CGObjCRuntime *CreateObjCRuntime(llvm::Module &M);
+CGObjCRuntime *CreateObjCRuntime(llvm::Module &M,
+                                 const llvm::Type *LLVMIntType,
+                                 const llvm::Type *LLVMLongType);
 }
 }
 #endif
Index: lib/CodeGen/CGObjCGNU.cpp
===================================================================
--- lib/CodeGen/CGObjCGNU.cpp	(revision 48543)
+++ 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,130 @@
 //
 //===----------------------------------------------------------------------===//
 
+#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 *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);
 };
 } // 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);
+}
+
+#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.
+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);
-
-  // 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.
+  llvm::Value *cmd = getSelector(Builder, Selector, 0);
 
-  // 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 +144,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 +156,153 @@
   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;
+}
+/*
+clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
+    llvm::Module &M,
+    const llvm::Type *LLVMIntType,
+    const llvm::Type *LLVMLongType) {
+  return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
+}*/
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp	(revision 48543)
+++ lib/CodeGen/CodeGenModule.cpp	(working copy)
@@ -34,10 +34,16 @@
   : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
     Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) {
   //TODO: Make this selectable at runtime
-  Runtime = CreateObjCRuntime(M);
+  Runtime = CreateObjCRuntime(M,
+      getTypes().ConvertType(getContext().IntTy),
+      getTypes().ConvertType(getContext().LongTy));
 }
 
 CodeGenModule::~CodeGenModule() {
+  llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction();
+  if (ObjCInitFunction) {
+    AddGlobalCtor(ObjCInitFunction);
+  }
   EmitGlobalCtors();
   delete Runtime;
 }
@@ -71,47 +77,50 @@
 }
 
 void CodeGenModule::EmitGlobalCtors() {
-  // Get the type of @llvm.global_ctors
-  std::vector<const llvm::Type*> CtorFields;
-  CtorFields.push_back(llvm::IntegerType::get(32));
-  // Constructor function type
-  std::vector<const llvm::Type*> VoidArgs;
-  llvm::FunctionType* CtorFuncTy = llvm::FunctionType::get(
-    llvm::Type::VoidTy,
-    VoidArgs,
-    false);
-  // i32, function type pair
-  const llvm::Type *FPType = llvm::PointerType::getUnqual(CtorFuncTy);
-  llvm::StructType* CtorStructTy = 
-  llvm::StructType::get(llvm::Type::Int32Ty, FPType, NULL);
-  // Array of fields
-  llvm::ArrayType* GlobalCtorsTy = 
-    llvm::ArrayType::get(CtorStructTy, GlobalCtors.size());
-  
-  // Define the global variable
-  llvm::GlobalVariable *GlobalCtorsVal =
-    new llvm::GlobalVariable(GlobalCtorsTy, false,
-                             llvm::GlobalValue::AppendingLinkage,
-                             (llvm::Constant*)0, "llvm.global_ctors",
-                             &TheModule);
+  if (!GlobalCtors.empty()) {
+    // Get the type of @llvm.global_ctors
+    std::vector<const llvm::Type*> CtorFields;
+    CtorFields.push_back(llvm::IntegerType::get(32));
+    // Constructor function type
+    std::vector<const llvm::Type*> VoidArgs;
+    llvm::FunctionType* CtorFuncTy = llvm::FunctionType::get(
+      llvm::Type::VoidTy,
+      VoidArgs,
+      false);
+    // i32, function type pair
+    CtorFields.push_back(llvm::PointerType::getUnqual(CtorFuncTy));
+    llvm::StructType* CtorStructTy = llvm::StructType::get(CtorFields, false);
+    // Array of fields
+    llvm::ArrayType* GlobalCtorsTy = llvm::ArrayType::get(CtorStructTy,
+        GlobalCtors.size());
+    
+    const std::string GlobalCtorsVar = std::string("llvm.global_ctors");
+    // Define the global variable
+    llvm::GlobalVariable *GlobalCtorsVal = new llvm::GlobalVariable(
+      GlobalCtorsTy,
+      false,
+      llvm::GlobalValue::AppendingLinkage,
+      (llvm::Constant*)0, 
+      GlobalCtorsVar,
+      &TheModule);
 
-  // Populate the array
-  std::vector<llvm::Constant*> CtorValues;
-  llvm::Constant *MagicNumber = 
-    llvm::ConstantInt::get(llvm::Type::Int32Ty, 65535, false);
-  std::vector<llvm::Constant*> StructValues;
-  for (std::vector<llvm::Constant*>::iterator I = GlobalCtors.begin(), 
-       E = GlobalCtors.end(); I != E; ++I) {
-    StructValues.clear();
-    StructValues.push_back(MagicNumber);
-    StructValues.push_back(*I);
+    // Populate the array
+    std::vector<llvm::Constant*> CtorValues;
+    llvm::Constant *MagicNumber = llvm::ConstantInt::get(llvm::IntegerType::Int32Ty,
+        65535,
+        false);
+    for (std::vector<llvm::Constant*>::iterator I = GlobalCtors.begin(), 
+        E = GlobalCtors.end(); I != E; ++I) {
+      std::vector<llvm::Constant*> StructValues;
+      StructValues.push_back(MagicNumber);
+      StructValues.push_back(*I);
 
-    CtorValues.push_back(llvm::ConstantStruct::get(CtorStructTy, StructValues));
+      llvm::Constant* CtorEntry = llvm::ConstantStruct::get(CtorStructTy, StructValues);
+      CtorValues.push_back(CtorEntry);
+    }
+    llvm::Constant* CtorArray = llvm::ConstantArray::get(GlobalCtorsTy, CtorValues);
+    GlobalCtorsVal->setInitializer(CtorArray);
   }
-  
-  GlobalCtorsVal->setInitializer(llvm::ConstantArray::get(GlobalCtorsTy,
-                                                          CtorValues));
-
 }
 
 /// ReplaceMapValuesWith - This is a really slow and bad function that
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp	(revision 48543)
+++ lib/CodeGen/CGExprScalar.cpp	(working copy)
@@ -481,11 +481,16 @@
   // Get the selector string
   std::string SelStr = E->getSelector().getName();
   llvm::Constant *Selector = CGF.CGM.GetAddrOfConstantString(SelStr);
-  ConvertType(E->getType());
+
+  llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+  llvm::Constant *Ops[] = {Idx0, Idx0};
+  llvm::Value *SelPtr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2);
+
   return Runtime->generateMessageSend(Builder,
       ConvertType(E->getType()),
+      0, // FIXME: Should be self in this context
       Receiver,
-      Selector,
+      SelPtr,
       &Args[0],
       Args.size());
 }
Index: lib/CodeGen/CGObjCEtoile.cpp
===================================================================
--- lib/CodeGen/CGObjCEtoile.cpp	(revision 0)
+++ lib/CodeGen/CGObjCEtoile.cpp	(revision 0)
@@ -0,0 +1,207 @@
+//===------- CGObjCEtoile.cpp - Emit LLVM Code from ASTs for a Module --------===// 
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides Objective-C code generation targetting the Etoile runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+
+
+clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {}
+
+namespace {
+class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime {
+private:
+  llvm::Module &TheModule;
+  const llvm::Type *SelectorTy;
+  const llvm::PointerType *PtrToInt8Ty;
+  const llvm::Type *IMPTy;
+  const llvm::Type *IntTy;
+  const llvm::Type *PtrTy;
+  const llvm::Type *LongTy;
+  const llvm::Type *PtrToIntTy;
+  const llvm::Type *IdTy;
+  const llvm::Type *CallTy;
+  const llvm::Type *SlotTy;
+  const llvm::Type *LookupFunctionTy;
+public:
+  CGObjCEtoile(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::Value *Selector,
+                                           llvm::Value** ArgV,
+                                           unsigned ArgC);
+  llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
+      llvm::Value *SelName,
+      llvm::Value *SelTypes);
+};
+} // end anonymous namespace
+
+CGObjCEtoile::CGObjCEtoile(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.
+  SelectorTy = llvm::Type::Int32Ty;
+  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);
+
+  // Call structure type.
+  llvm::OpaqueType *OpaqueSlotTy = llvm::OpaqueType::get();
+  CallTy = llvm::StructType::get(llvm::PointerType::getUnqual(OpaqueSlotTy),
+      SelectorTy,
+      IdTy,
+      0);
+  //CallTy = llvm::PointerType::getUnqual(CallTy);
+
+  // IMP type
+  std::vector<const llvm::Type*> IMPArgs;
+  IMPArgs.push_back(IdTy);
+  IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
+  IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+
+  // Slot type
+  SlotTy = llvm::StructType::get(IntTy,
+      IMPTy,
+      PtrToInt8Ty,
+      PtrToInt8Ty,
+      llvm::Type::Int32Ty,
+      0);
+  OpaqueSlotTy->refineAbstractTypeTo(SlotTy);
+  SlotTy = llvm::PointerType::getUnqual(SlotTy);
+
+  // Lookup function type
+  std::vector<const llvm::Type*> LookupFunctionArgs;
+  LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy));
+  LookupFunctionArgs.push_back(IdTy);
+  LookupFunctionArgs.push_back(SelectorTy);
+  LookupFunctionArgs.push_back(IdTy);
+  LookupFunctionTy = llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
+  LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
+
+}
+
+// Looks up the selector for the specified name / type pair.
+llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder,
+    llvm::Value *SelName,
+    llvm::Value *SelTypes)
+{
+  // Look up the selector.
+  if(SelTypes == 0) {
+    SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+  }
+  llvm::Constant *SelFunction = 
+    TheModule.getOrInsertFunction("lookup_typed_selector",
+        SelectorTy,
+        PtrToInt8Ty,
+        PtrToInt8Ty,
+        0);
+  llvm::SmallVector<llvm::Value*, 2> Args;
+  Args.push_back(SelName);
+  Args.push_back(SelTypes);
+  return Builder.CreateCall(SelFunction, Args.begin(), Args.end());
+}
+
+#define SET(structure, index, value) do {\
+    llvm::Value *element_ptr = Builder.CreateStructGEP(structure, index);\
+    Builder.CreateStore(value, element_ptr);} while(0)
+// Generate code for a message send expression on the Etoile runtime.
+// BIG FAT WARNING: Much of this code will need factoring out later.
+llvm::Value *CGObjCEtoile::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
+                                            const llvm::Type *ReturnTy,
+                                            llvm::Value *Sender,
+                                            llvm::Value *Receiver,
+                                            llvm::Value *Selector,
+                                            llvm::Value** ArgV,
+                                            unsigned ArgC) {
+  // FIXME: Selectors should be statically cached, not looked up on every call.
+  llvm::Value *cmd = getSelector(Builder, Selector, 0);
+  // TODO: [Polymorphic] inline caching
+
+  // Get the lookup function for this object:
+  llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
+  llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
+      false,
+      llvm::GlobalValue::ExternalLinkage,
+      0,
+      "lookup_offset",
+      &TheModule);
+  FunctionOffset = Builder.CreateLoad(FunctionOffset);
+  llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
+  llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
+
+  // TODO: Remove this when the caller is providing sensible sender info
+  if(Sender == 0) {
+    Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
+  }
+  Receiver = Builder.CreateBitCast(Receiver, IdTy);
+  llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
+  Builder.CreateStore(Receiver, ReceiverAddr);
+  // Look up the method implementation.
+  llvm::SmallVector<llvm::Value*, 4> LookupArgs;
+  LookupArgs.push_back(ReceiverAddr);
+  LookupArgs.push_back(Receiver);
+  LookupArgs.push_back(cmd);
+  LookupArgs.push_back(Sender);
+  llvm::Value *Slot = Builder.CreateCall(Lookup,
+      LookupArgs.begin(),
+      LookupArgs.end());
+  
+  // Create the call structure
+  llvm::Value *Call = Builder.CreateAlloca(CallTy);
+  SET(Call, 0, Slot);
+  SET(Call, 1, cmd);
+  SET(Call, 2, Sender);
+
+  // Get the IMP from the slot and call it
+  // TODO: Property load / store optimisations
+  llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1);
+  // If the return type of the IMP is wrong, cast it so it isn't.
+  if(ReturnTy != IdTy) {
+    std::vector<const llvm::Type*> IMPArgs;
+    IMPArgs.push_back(IdTy);
+    IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
+    llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true);
+    IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy));
+  }
+  llvm::SmallVector<llvm::Value*, 16> Args;
+  Args.push_back(Receiver);
+  Args.push_back(Call);
+  Args.insert(Args.end(), ArgV, ArgV+ArgC);
+  return Builder.CreateCall(IMP, Args.begin(), Args.end());
+}
+
+clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
+    llvm::Module &M,
+    const llvm::Type *LLVMIntType,
+    const llvm::Type *LLVMLongType) {
+  return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
+}
