summaryrefslogtreecommitdiff
path: root/Clang
diff options
context:
space:
mode:
Diffstat (limited to 'Clang')
-rw-r--r--Clang/CGObjC.cpp193
-rw-r--r--Clang/CGObjCGNU.cpp869
-rw-r--r--Clang/CGObjCRuntime.h126
3 files changed, 1188 insertions, 0 deletions
diff --git a/Clang/CGObjC.cpp b/Clang/CGObjC.cpp
new file mode 100644
index 0000000..9bf53d9
--- /dev/null
+++ b/Clang/CGObjC.cpp
@@ -0,0 +1,193 @@
+//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Objective-C code as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/Constant.h"
+#include "llvm/Function.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+/// Emits an instance of NSConstantString representing the object.
+llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){
+ return CGM.getObjCRuntime()->GenerateConstantString(
+ E->getString()->getStrData(), E->getString()->getByteLength());
+}
+
+/// Emit a selector.
+llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
+ // Untyped selector.
+ // Note that this implementation allows for non-constant strings to be passed
+ // as arguments to @selector(). Currently, the only thing preventing this
+ // behaviour is the type checking in the front end.
+ return CGM.getObjCRuntime()->GetSelector(Builder, E->getSelector());
+}
+
+
+
+llvm::Value *CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
+ // Only the lookup mechanism and first two arguments of the method
+ // implementation vary between runtimes. We can get the receiver and
+ // arguments in generic code.
+
+ CGObjCRuntime *Runtime = CGM.getObjCRuntime();
+ const Expr *ReceiverExpr = E->getReceiver();
+ bool isSuperMessage = false;
+ // Find the receiver
+ llvm::Value *Receiver;
+ if (!ReceiverExpr) {
+ const char * classname = E->getClassName()->getName();
+ if (!strcmp(classname, "super")) {
+ classname = E->getMethodDecl()->getClassInterface()->getName();
+ }
+ llvm::Value *ClassName = CGM.GetAddrOfConstantString(classname);
+ ClassName = Builder.CreateStructGEP(ClassName, 0);
+ Receiver = Runtime->LookupClass(Builder, ClassName);
+ } else if (isa<PreDefinedExpr>(E->getReceiver())) {
+ assert(cast<PreDefinedExpr>(E->getReceiver())->getIdentType() ==
+ PreDefinedExpr::ObjCSuper);
+ isSuperMessage = true;
+ Receiver = LoadObjCSelf();
+ } else {
+ Receiver = EmitScalarExpr(E->getReceiver());
+ }
+
+ // Process the arguments
+ unsigned ArgC = E->getNumArgs();
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ for (unsigned i = 0; i != ArgC; ++i) {
+ const Expr *ArgExpr = E->getArg(i);
+ QualType ArgTy = ArgExpr->getType();
+ if (!hasAggregateLLVMType(ArgTy)) {
+ // Scalar argument is passed by-value.
+ Args.push_back(EmitScalarExpr(ArgExpr));
+ } else if (ArgTy->isAnyComplexType()) {
+ // Make a temporary alloca to pass the argument.
+ llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
+ EmitComplexExprIntoAddr(ArgExpr, DestMem, false);
+ Args.push_back(DestMem);
+ } else {
+ llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
+ EmitAggExpr(ArgExpr, DestMem, false);
+ Args.push_back(DestMem);
+ }
+ }
+
+ if (isSuperMessage) {
+ // super is only valid in an Objective-C method
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ const char *SuperClass =
+ OMD->getClassInterface()->getSuperClass()->getName();
+ return Runtime->GenerateMessageSendSuper(Builder, ConvertType(E->getType()),
+ Receiver, SuperClass,
+ Receiver, E->getSelector(),
+ &Args[0], Args.size());
+ }
+ return Runtime->GenerateMessageSend(Builder, ConvertType(E->getType()),
+ LoadObjCSelf(),
+ Receiver, E->getSelector(),
+ &Args[0], Args.size());
+}
+
+/// Generate an Objective-C method. An Objective-C method is a C function with
+/// its pointer, name, and types registered in the class struture.
+void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
+
+ llvm::SmallVector<const llvm::Type *, 16> ParamTypes;
+ for (unsigned i=0 ; i<OMD->param_size() ; i++) {
+ const llvm::Type *Ty = ConvertType(OMD->getParamDecl(i)->getType());
+ if (Ty->isFirstClassType())
+ ParamTypes.push_back(Ty);
+ else
+ ParamTypes.push_back(llvm::PointerType::getUnqual(Ty));
+ }
+ std::string CategoryName = "";
+ if (ObjCCategoryImplDecl *OCD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getMethodContext())) {
+ CategoryName = OCD->getName();
+ }
+ const llvm::Type *ReturnTy =
+ CGM.getTypes().ConvertReturnType(OMD->getResultType());
+ CurFn = CGM.getObjCRuntime()->MethodPreamble(
+ OMD->getClassInterface()->getName(),
+ CategoryName,
+ OMD->getSelector().getName(),
+ ReturnTy,
+ llvm::PointerType::getUnqual(
+ llvm::Type::Int32Ty),
+ ParamTypes.begin(),
+ OMD->param_size(),
+ !OMD->isInstance(),
+ OMD->isVariadic());
+ llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", CurFn);
+
+ // Create a marker to make it easy to insert allocas into the entryblock
+ // later. Don't create this with the builder, because we don't want it
+ // folded.
+ llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty);
+ AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "allocapt",
+ EntryBB);
+
+ FnRetTy = OMD->getResultType();
+ CurFuncDecl = OMD;
+
+ Builder.SetInsertPoint(EntryBB);
+
+ // Emit allocs for param decls. Give the LLVM Argument nodes names.
+ llvm::Function::arg_iterator AI = CurFn->arg_begin();
+
+ if (hasAggregateLLVMType(OMD->getResultType())) {
+ ++AI;
+ }
+ // Add implicit parameters to the decl map.
+ // TODO: Add something to AST to let the runtime specify the names and types
+ // of these.
+
+ llvm::Value *&SelfEntry = LocalDeclMap[OMD->getSelfDecl()];
+ const llvm::Type *IPTy = AI->getType();
+ llvm::Value *DeclPtr = new llvm::AllocaInst(IPTy, 0, AI->getName() +
+ ".addr", AllocaInsertPt);
+ // Store the initial value into the alloca.
+ Builder.CreateStore(AI, DeclPtr);
+ SelfEntry = DeclPtr;
+ ++AI;
+ llvm::Value *&CmdEntry = LocalDeclMap[OMD->getCmdDecl()];
+ IPTy = AI->getType();
+ DeclPtr = new llvm::AllocaInst(IPTy, 0, AI->getName() +
+ ".addr", AllocaInsertPt);
+ // Store the initial value into the alloca.
+ Builder.CreateStore(AI, DeclPtr);
+ CmdEntry = DeclPtr;
+
+ for (unsigned i = 0, e = OMD->getNumParams(); i != e; ++i, ++AI) {
+ assert(AI != CurFn->arg_end() && "Argument mismatch!");
+ EmitParmDecl(*OMD->getParamDecl(i), AI);
+ }
+
+ GenerateFunction(OMD->getBody());
+}
+
+llvm::Value *CodeGenFunction::LoadObjCSelf(void)
+{
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurFuncDecl)) {
+ ValueDecl *Decl = OMD->getSelfDecl();
+ llvm::Value *SelfPtr = LocalDeclMap[&(*(Decl))];
+ return Builder.CreateLoad(SelfPtr, "self");
+ }
+ return NULL;
+}
+
+CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/Clang/CGObjCGNU.cpp b/Clang/CGObjCGNU.cpp
new file mode 100644
index 0000000..57c021f
--- /dev/null
+++ b/Clang/CGObjCGNU.cpp
@@ -0,0 +1,869 @@
+//===------- CGObjCGNU.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 GNU runtime. The
+// class in this file generates structures used by the GNU Objective-C runtime
+// library. These structures are defined in objc/objc.h and objc/objc-api.h in
+// the GNU runtime distribution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include <map>
+using namespace clang;
+using llvm::dyn_cast;
+
+// The version of the runtime that this class targets. Must match the version
+// in the runtime.
+static const int RuntimeVersion = 8;
+static const int ProtocolVersion = 2;
+
+namespace {
+class CGObjCGNU : public CodeGen::CGObjCRuntime {
+private:
+ CodeGen::CodeGenModule &CGM;
+ llvm::Module &TheModule;
+ const llvm::StructType *SelStructTy;
+ 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;
+ std::vector<llvm::Constant*> Classes;
+ std::vector<llvm::Constant*> Categories;
+ std::vector<llvm::Constant*> ConstantStrings;
+ llvm::Function *LoadFunction;
+ llvm::StringMap<llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors;
+ // Some zeros used for GEPs in lots of places.
+ llvm::Constant *Zeros[2];
+ llvm::Constant *NULLPtr;
+private:
+ llvm::Constant *GenerateIvarList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets);
+ llvm::Constant *GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName,
+ const llvm::SmallVectorImpl<Selector> &MethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ bool isClassMethodList);
+ llvm::Constant *GenerateProtocolList(
+ const llvm::SmallVectorImpl<std::string> &Protocols);
+ llvm::Constant *GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ const char *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols);
+ llvm::Constant *GenerateProtocolMethodList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
+ llvm::Constant *MakeConstantString(const std::string &Str, const std::string
+ &Name="");
+ llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name="");
+ llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name="");
+public:
+ CGObjCGNU(CodeGen::CodeGenModule &cgm);
+ virtual llvm::Constant *GenerateConstantString(const char *String,
+ const size_t length);
+ virtual llvm::Value *GenerateMessageSend(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ llvm::Value *Receiver,
+ Selector Sel,
+ llvm::Value** ArgV,
+ unsigned ArgC);
+ virtual llvm::Value *GenerateMessageSendSuper(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ Selector Sel,
+ llvm::Value** ArgV,
+ unsigned ArgC);
+ virtual llvm::Value *LookupClass(llvm::IRBuilder &Builder,
+ llvm::Value *ClassName);
+ virtual llvm::Value *GetSelector(llvm::IRBuilder &Builder, Selector Sel);
+
+ virtual llvm::Function *MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
+ const llvm::Type *ReturnTy,
+ const llvm::Type *SelfTy,
+ const llvm::Type **ArgTy,
+ unsigned ArgC,
+ bool isClassMethod,
+ bool isVarArg);
+ virtual void GenerateCategory(const char *ClassName, const char *CategoryName,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols);
+ virtual void GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols);
+ virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder &Builder, const char
+ *ProtocolName);
+ virtual void GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVectorImpl<std::string> &Protocols,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes);
+ virtual llvm::Function *ModuleInitFunction();
+};
+} // end anonymous namespace
+
+
+
+static std::string SymbolNameForClass(const std::string &ClassName) {
+ return ".objc_class_" + ClassName;
+}
+
+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
+{
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+
+ (isClassMethod ? "+" : "-") + MethodName;
+}
+
+CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
+ : CGM(cgm), TheModule(CGM.getModule()) {
+ IntTy = CGM.getTypes().ConvertType(CGM.getContext().IntTy);
+ LongTy = CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+
+ Zeros[0] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Zeros[1] = Zeros[0];
+ NULLPtr = llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
+ // C string type. Used in lots of places.
+ PtrToInt8Ty =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ // Get the selector Type.
+ SelStructTy = llvm::StructType::get(
+ PtrToInt8Ty,
+ PtrToInt8Ty,
+ NULL);
+ SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
+ PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
+ PtrTy = PtrToInt8Ty;
+
+ // Object type
+ llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
+ llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
+ IdTy = llvm::StructType::get(OpaqueIdTy, NULL);
+ llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
+ IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
+ IdTy = llvm::PointerType::getUnqual(IdTy);
+
+ // IMP type
+ std::vector<const llvm::Type*> IMPArgs;
+ IMPArgs.push_back(IdTy);
+ IMPArgs.push_back(SelectorTy);
+ IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+}
+// This has to perform the lookup every time, since posing and related
+// techniques can modify the name -> class mapping.
+llvm::Value *CGObjCGNU::LookupClass(llvm::IRBuilder &Builder,
+ llvm::Value *ClassName) {
+ llvm::Constant *ClassLookupFn =
+ TheModule.getOrInsertFunction("objc_lookup_class", IdTy, PtrToInt8Ty,
+ NULL);
+ return Builder.CreateCall(ClassLookupFn, ClassName);
+}
+
+/// GetSelector - Return the pointer to the unique'd string for this selector.
+llvm::Value *CGObjCGNU::GetSelector(llvm::IRBuilder &Builder, Selector Sel) {
+ // FIXME: uniquing on the string is wasteful, unique on Sel instead!
+ llvm::GlobalAlias *&US = UntypedSelectors[Sel.getName()];
+ if (US == 0)
+ US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage,
+ ".objc_untyped_selector_alias",
+ NULL, &TheModule);
+
+ return Builder.CreateLoad(US);
+
+}
+
+llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
+ const std::string &Name) {
+ llvm::Constant * ConstStr = llvm::ConstantArray::get(Str);
+ ConstStr = new llvm::GlobalVariable(ConstStr->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ ConstStr, Name, &TheModule);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name) {
+ llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name) {
+ llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+
+/// Generate an NSConstantString object.
+//TODO: In case there are any crazy people still using the GNU runtime without
+//an OpenStep implementation, this should let them select their own class for
+//constant strings.
+llvm::Constant *CGObjCGNU::GenerateConstantString(const char *String, const
+ size_t length) {
+ std::string Str(String, String +length);
+ std::vector<llvm::Constant*> Ivars;
+ Ivars.push_back(NULLPtr);
+ Ivars.push_back(MakeConstantString(Str));
+ Ivars.push_back(llvm::ConstantInt::get(IntTy, length));
+ llvm::Constant *ObjCStr = MakeGlobal(
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
+ Ivars, ".objc_str");
+ ConstantStrings.push_back(
+ llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
+ return ObjCStr;
+}
+
+///Generates a message send where the super is the receiver. This is a message
+///send to self with special delivery semantics indicating which class's method
+///should be called.
+llvm::Value *CGObjCGNU::GenerateMessageSendSuper(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ Selector Sel,
+ llvm::Value** ArgV,
+ unsigned ArgC) {
+ // TODO: This should be cached, not looked up every time.
+ llvm::Value *ReceiverClass = LookupClass(Builder,
+ MakeConstantString(SuperClassName));
+ llvm::Value *cmd = GetSelector(Builder, Sel);
+ std::vector<const llvm::Type*> impArgTypes;
+ impArgTypes.push_back(Receiver->getType());
+ impArgTypes.push_back(SelectorTy);
+
+ // Avoid an explicit cast on the IMP by getting a version that has the right
+ // return type.
+ llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes,
+ true);
+ // Construct the structure used to look up the IMP
+ llvm::StructType *ObjCSuperTy = llvm::StructType::get(Receiver->getType(),
+ IdTy, NULL);
+ llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
+ // FIXME: volatility
+ Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
+ Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
+
+ // Get the IMP
+ llvm::Constant *lookupFunction =
+ TheModule.getOrInsertFunction("objc_msg_lookup_super",
+ llvm::PointerType::getUnqual(impType),
+ llvm::PointerType::getUnqual(ObjCSuperTy),
+ SelectorTy, NULL);
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+ llvm::Value *imp = Builder.CreateCall(lookupFunction, lookupArgs,
+ lookupArgs+2);
+
+ // Call the method
+ llvm::SmallVector<llvm::Value*, 8> callArgs;
+ callArgs.push_back(Receiver);
+ callArgs.push_back(cmd);
+ callArgs.insert(callArgs.end(), ArgV, ArgV+ArgC);
+ return Builder.CreateCall(imp, callArgs.begin(), callArgs.end());
+}
+
+/// Generate code for a message send expression.
+llvm::Value *CGObjCGNU::GenerateMessageSend(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ llvm::Value *Receiver,
+ Selector Sel,
+ llvm::Value** ArgV,
+ unsigned ArgC) {
+ llvm::Value *cmd = GetSelector(Builder, Sel);
+
+ // Look up the method implementation.
+ std::vector<const llvm::Type*> impArgTypes;
+ const llvm::Type *RetTy;
+ //TODO: Revisit this when LLVM supports aggregate return types.
+ if (ReturnTy->isSingleValueType() && ReturnTy != llvm::Type::VoidTy) {
+ RetTy = ReturnTy;
+ } else {
+ // For struct returns allocate the space in the caller and pass it up to
+ // the sender.
+ RetTy = llvm::Type::VoidTy;
+ impArgTypes.push_back(llvm::PointerType::getUnqual(ReturnTy));
+ }
+ impArgTypes.push_back(Receiver->getType());
+ impArgTypes.push_back(SelectorTy);
+
+ // Avoid an explicit cast on the IMP by getting a version that has the right
+ // return type.
+ llvm::FunctionType *impType = llvm::FunctionType::get(RetTy, impArgTypes,
+ true);
+
+ llvm::Constant *lookupFunction =
+ TheModule.getOrInsertFunction("objc_msg_lookup",
+ llvm::PointerType::getUnqual(impType),
+ Receiver->getType(), SelectorTy, NULL);
+ llvm::Value *imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
+
+ // Call the method.
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ if (!ReturnTy->isSingleValueType()) {
+ llvm::Value *Return = Builder.CreateAlloca(ReturnTy);
+ Args.push_back(Return);
+ }
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ if (!ReturnTy->isSingleValueType()) {
+ Builder.CreateCall(imp, Args.begin(), Args.end());
+ return Args[0];
+ }
+ return Builder.CreateCall(imp, Args.begin(), Args.end());
+}
+
+/// Generates a MethodList. Used in construction of a objc_class and
+/// objc_category structures.
+llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName,
+ const llvm::SmallVectorImpl<Selector> &MethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ bool isClassMethodList) {
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodTy = llvm::StructType::get(
+ PtrToInt8Ty, // Really a selector, but the runtime creates it us.
+ PtrToInt8Ty, // Method types
+ llvm::PointerType::getUnqual(IMPTy), //Method pointer
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
+ Elements.clear();
+ llvm::Constant *C = CGM.GetAddrOfConstantString(MethodSels[i].getName());
+ Elements.push_back(llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ llvm::Constant *Method =
+ TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
+ MethodSels[i].getName(),
+ isClassMethodList));
+ Method = llvm::ConstantExpr::getBitCast(Method,
+ llvm::PointerType::getUnqual(IMPTy));
+ Elements.push_back(Method);
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy,
+ MethodSels.size());
+ llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy,
+ Methods);
+
+ // Structure containing list pointer, array and array count
+ llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
+ llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get();
+ llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
+ llvm::StructType *ObjCMethodListTy = llvm::StructType::get(NextPtrTy,
+ IntTy,
+ ObjCMethodArrayTy,
+ NULL);
+ // Refine next pointer type to concrete type
+ llvm::cast<llvm::OpaqueType>(
+ OpaqueNextTy.get())->refineAbstractTypeTo(ObjCMethodListTy);
+ ObjCMethodListTy = llvm::cast<llvm::StructType>(OpaqueNextTy.get());
+
+ Methods.clear();
+ Methods.push_back(llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(ObjCMethodListTy)));
+ Methods.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ MethodTypes.size()));
+ Methods.push_back(MethodArray);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list");
+}
+
+/// Generates an IvarList. Used in construction of a objc_class.
+llvm::Constant *CGObjCGNU::GenerateIvarList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
+ // Get the method structure type.
+ llvm::StructType *ObjCIvarTy = llvm::StructType::get(
+ PtrToInt8Ty,
+ PtrToInt8Ty,
+ IntTy,
+ NULL);
+ std::vector<llvm::Constant*> Ivars;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarNames[i],
+ Zeros, 2));
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarTypes[i],
+ Zeros, 2));
+ Elements.push_back(IvarOffsets[i]);
+ Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements));
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
+ IvarNames.size());
+
+
+ Elements.clear();
+ Elements.push_back(llvm::ConstantInt::get(
+ llvm::cast<llvm::IntegerType>(IntTy), (int)IvarNames.size()));
+ Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars));
+ // Structure containing array and array count
+ llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy,
+ ObjCIvarArrayTy,
+ NULL);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list");
+}
+
+/// Generate a class structure
+llvm::Constant *CGObjCGNU::GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ const char *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols) {
+ // Set up the class structure
+ // Note: Several of these are char*s when they should be ids. This is
+ // because the runtime performs this translation on load.
+ llvm::StructType *ClassTy = llvm::StructType::get(
+ PtrToInt8Ty, // class_pointer
+ PtrToInt8Ty, // super_class
+ PtrToInt8Ty, // name
+ LongTy, // version
+ LongTy, // info
+ LongTy, // instance_size
+ IVars->getType(), // ivars
+ Methods->getType(), // methods
+ // These are all filled in by the runtime, so we pretend
+ PtrTy, // dtable
+ PtrTy, // subclass_list
+ PtrTy, // sibling_class
+ PtrTy, // protocols
+ PtrTy, // gc_object_type
+ NULL);
+ llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
+ llvm::Constant *NullP =
+ llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(PtrTy));
+ // Fill in the structure
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty));
+ Elements.push_back(SuperClass);
+ Elements.push_back(MakeConstantString(Name, ".class_name"));
+ Elements.push_back(Zero);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, info));
+ Elements.push_back(InstanceSize);
+ Elements.push_back(IVars);
+ Elements.push_back(Methods);
+ Elements.push_back(NullP);
+ Elements.push_back(NullP);
+ Elements.push_back(NullP);
+ Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
+ Elements.push_back(NullP);
+ // Create an instance of the structure
+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name));
+}
+
+llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes) {
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
+ PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
+ PtrToInt8Ty,
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(MethodNames[i],
+ Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements));
+ }
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy,
+ MethodNames.size());
+ llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods);
+ llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(
+ IntTy, ObjCMethodArrayTy, NULL);
+ Methods.clear();
+ Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
+ Methods.push_back(Array);
+ return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list");
+}
+// Create the protocol list structure used in classes, categories and so on
+llvm::Constant *CGObjCGNU::GenerateProtocolList(
+ const llvm::SmallVectorImpl<std::string> &Protocols) {
+ llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Protocols.size());
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(
+ PtrTy, //Should be a recurisve pointer, but it's always NULL here.
+ LongTy,//FIXME: Should be size_t
+ ProtocolArrayTy,
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
+ iter != endIter ; iter++) {
+ llvm::Constant *Ptr =
+ llvm::ConstantExpr::getBitCast(ExistingProtocols[*iter], PtrToInt8Ty);
+ Elements.push_back(Ptr);
+ }
+ llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
+ Elements);
+ Elements.clear();
+ Elements.push_back(NULLPtr);
+ Elements.push_back(llvm::ConstantInt::get(
+ llvm::cast<llvm::IntegerType>(LongTy), Protocols.size()));
+ Elements.push_back(ProtocolArray);
+ return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
+}
+
+llvm::Value *CGObjCGNU::GenerateProtocolRef(llvm::IRBuilder &Builder, const
+ char *ProtocolName) {
+ return ExistingProtocols[ProtocolName];
+}
+
+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVectorImpl<std::string> &Protocols,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes) {
+
+ llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
+ llvm::Constant *InstanceMethodList =
+ GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes);
+ llvm::Constant *ClassMethodList =
+ GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
+ // Protocols are objects containing lists of the methods implemented and
+ // protocols adopted.
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ PtrToInt8Ty,
+ ProtocolList->getType(),
+ InstanceMethodList->getType(),
+ ClassMethodList->getType(),
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ // The isa pointer must be set to a magic number so the runtime knows it's
+ // the correct layout.
+ Elements.push_back(llvm::ConstantExpr::getIntToPtr(
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, ProtocolVersion), IdTy));
+ Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
+ Elements.push_back(ProtocolList);
+ Elements.push_back(InstanceMethodList);
+ Elements.push_back(ClassMethodList);
+ ExistingProtocols[ProtocolName] =
+ llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
+ ".objc_protocol"), IdTy);
+}
+
+void CGObjCGNU::GenerateCategory(
+ const char *ClassName,
+ const char *CategoryName,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols) {
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(MakeConstantString(CategoryName));
+ Elements.push_back(MakeConstantString(ClassName));
+ // Instance method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes,
+ false), PtrTy));
+ // Class method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, ClassMethodSels, ClassMethodTypes, true),
+ PtrTy));
+ // Protocol list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(
+ GenerateProtocolList(Protocols), PtrTy));
+ Categories.push_back(llvm::ConstantExpr::getBitCast(
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy,
+ PtrTy, PtrTy, NULL), Elements), PtrTy));
+}
+void CGObjCGNU::GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols) {
+ // Get the superclass pointer.
+ llvm::Constant *SuperClass;
+ if (SuperClassName) {
+ SuperClass = MakeConstantString(SuperClassName, ".super_class_name");
+ } else {
+ SuperClass = llvm::ConstantPointerNull::get(
+ llvm::cast<llvm::PointerType>(PtrToInt8Ty));
+ }
+ // Empty vector used to construct empty method lists
+ llvm::SmallVector<llvm::Constant*, 1> empty;
+ // Generate the method and instance variable lists
+ llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
+ InstanceMethodSels, InstanceMethodTypes, false);
+ llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
+ ClassMethodSels, ClassMethodTypes, true);
+ llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
+ IvarOffsets);
+ //Generate metaclass for class methods
+ llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
+ NULLPtr, 0x2L, /*name*/"", 0, Zeros[0], GenerateIvarList(
+ empty, empty, empty), ClassMethodList, NULLPtr);
+ // Generate the class structure
+ llvm::Constant *ClassStruct = GenerateClassStructure(MetaClassStruct,
+ SuperClass, 0x1L, ClassName, 0,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, instanceSize), IvarList,
+ MethodList, GenerateProtocolList(Protocols));
+ // Add class structure to list to be added to the symtab later
+ ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty);
+ Classes.push_back(ClassStruct);
+}
+
+llvm::Function *CGObjCGNU::ModuleInitFunction() {
+ // Only emit an ObjC load function if no Objective-C stuff has been called
+ if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
+ ExistingProtocols.empty() && TypedSelectors.empty() &&
+ UntypedSelectors.empty())
+ return NULL;
+
+ // Name the ObjC types to make the IR a bit easier to read
+ TheModule.addTypeName(".objc_selector", SelectorTy);
+ TheModule.addTypeName(".objc_id", IdTy);
+ TheModule.addTypeName(".objc_imp", IMPTy);
+
+ std::vector<llvm::Constant*> Elements;
+ // Generate statics list:
+ llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ ConstantStrings.size() + 1);
+ ConstantStrings.push_back(NULLPtr);
+ Elements.push_back(MakeConstantString("NSConstantString",
+ ".objc_static_class_name"));
+ Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, ConstantStrings));
+ llvm::StructType *StaticsListTy =
+ llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL);
+ llvm::Type *StaticsListPtrTy = llvm::PointerType::getUnqual(StaticsListTy);
+ llvm::Constant *Statics =
+ MakeGlobal(StaticsListTy, Elements, ".objc_statics");
+ llvm::ArrayType *StaticsListArrayTy =
+ llvm::ArrayType::get(StaticsListPtrTy, 2);
+ Elements.clear();
+ Elements.push_back(Statics);
+ Elements.push_back(llvm::Constant::getNullValue(StaticsListPtrTy));
+ Statics = MakeGlobal(StaticsListArrayTy, Elements, ".objc_statics_ptr");
+ Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy);
+ // Array of classes, categories, and constant objects
+ llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Classes.size() + Categories.size() + 2);
+ llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelectorTy,
+ llvm::Type::Int16Ty,
+ llvm::Type::Int16Ty,
+ ClassListTy, NULL);
+
+ Elements.clear();
+ // Pointer to an array of selectors used in this module.
+ std::vector<llvm::Constant*> Selectors;
+ for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter = TypedSelectors.begin(), iterEnd = TypedSelectors.end();
+ iter != iterEnd ; ++iter) {
+ Elements.push_back(MakeConstantString(iter->first.first, ".objc_sel_name"));
+ Elements.push_back(MakeConstantString(iter->first.second,
+ ".objc_sel_types"));
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ for (llvm::StringMap<llvm::GlobalAlias*>::iterator
+ iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
+ iter != iterEnd; ++iter) {
+ Elements.push_back(
+ MakeConstantString(iter->getKeyData(), ".objc_sel_name"));
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ Elements.push_back(NULLPtr);
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ // Number of static selectors
+ Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() ));
+ llvm::Constant *SelectorList = MakeGlobal(
+ llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
+ ".objc_selector_list");
+ Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelectorTy));
+
+ // Now that all of the static selectors exist, create pointers to them.
+ int index = 0;
+ for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
+ iter != iterEnd; ++iter) {
+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::GlobalVariable *SelPtr = new llvm::GlobalVariable(SelectorTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ (*iter).second->setAliasee(SelPtr);
+ }
+ for (llvm::StringMap<llvm::GlobalAlias*>::iterator
+ iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
+ iter != iterEnd; iter++) {
+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::GlobalVariable *SelPtr = new llvm::GlobalVariable(SelectorTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ (*iter).second->setAliasee(SelPtr);
+ }
+ // Number of classes defined.
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Classes.size()));
+ // Number of categories defined
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Categories.size()));
+ // Create an array of classes, then categories, then static object instances
+ Classes.insert(Classes.end(), Categories.begin(), Categories.end());
+ // NULL-terminated list of static object instances (mainly constant strings)
+ Classes.push_back(Statics);
+ Classes.push_back(NULLPtr);
+ llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes);
+ Elements.push_back(ClassList);
+ // Construct the symbol table
+ llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements);
+
+ // The symbol table is contained in a module which has some version-checking
+ // constants
+ llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy,
+ PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
+ Elements.clear();
+ // Runtime version used for compatibility checking.
+ Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
+ //FIXME: Should be sizeof(ModuleTy)
+ Elements.push_back(llvm::ConstantInt::get(LongTy, 16));
+ //FIXME: Should be the path to the file where this module was declared
+ Elements.push_back(NULLPtr);
+ Elements.push_back(SymTab);
+ llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
+
+ // Create the load function calling the runtime entry point with the module
+ // structure
+ std::vector<const llvm::Type*> VoidArgs;
+ llvm::Function * LoadFunction = llvm::Function::Create(
+ llvm::FunctionType::get(llvm::Type::VoidTy, VoidArgs, false),
+ llvm::GlobalValue::InternalLinkage, ".objc_load_function",
+ &TheModule);
+ llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", LoadFunction);
+ llvm::IRBuilder Builder;
+ Builder.SetInsertPoint(EntryBB);
+ llvm::Value *Register = TheModule.getOrInsertFunction("__objc_exec_class",
+ llvm::Type::VoidTy, llvm::PointerType::getUnqual(ModuleTy), NULL);
+ Builder.CreateCall(Register, Module);
+ Builder.CreateRetVoid();
+ return LoadFunction;
+}
+llvm::Function *CGObjCGNU::MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
+ const llvm::Type *ReturnTy,
+ const llvm::Type *SelfTy,
+ const llvm::Type **ArgTy,
+ unsigned ArgC,
+ bool isClassMethod,
+ bool isVarArg) {
+ std::vector<const llvm::Type*> Args;
+ if (!ReturnTy->isSingleValueType() && ReturnTy != llvm::Type::VoidTy) {
+ Args.push_back(llvm::PointerType::getUnqual(ReturnTy));
+ ReturnTy = llvm::Type::VoidTy;
+ }
+ Args.push_back(SelfTy);
+ Args.push_back(SelectorTy);
+ Args.insert(Args.end(), ArgTy, ArgTy+ArgC);
+
+ llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy,
+ Args,
+ isVarArg);
+ std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
+ MethodName, isClassMethod);
+
+ llvm::Function *Method = llvm::Function::Create(MethodTy,
+ llvm::GlobalValue::InternalLinkage,
+ FunctionName,
+ &TheModule);
+ llvm::Function::arg_iterator AI = Method->arg_begin();
+ // Name the struct return argument.
+ // FIXME: This is probably the wrong test.
+ if (!ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) {
+ AI->setName("agg.result");
+ ++AI;
+ }
+ AI->setName("self");
+ ++AI;
+ AI->setName("_cmd");
+ return Method;
+}
+
+CodeGen::CGObjCRuntime *CodeGen::CreateObjCRuntime(CodeGen::CodeGenModule &CGM){
+ return new CGObjCGNU(CGM);
+}
diff --git a/Clang/CGObjCRuntime.h b/Clang/CGObjCRuntime.h
new file mode 100644
index 0000000..a5d88c3
--- /dev/null
+++ b/Clang/CGObjCRuntime.h
@@ -0,0 +1,126 @@
+//===----- CGObjCRuntime.h - 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 an abstract class for Objective-C code generation. Concrete
+// subclasses of this implement code generation for specific Objective-C
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
+#define CLANG_CODEGEN_OBCJRUNTIME_H
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+
+namespace llvm {
+ class IRBuilder;
+ class Constant;
+ class Type;
+ class Value;
+ class Module;
+ class Function;
+}
+
+namespace clang {
+ class Selector;
+
+namespace CodeGen {
+ class CodeGenModule;
+
+//FIXME Several methods should be pure virtual but aren't to avoid the
+//partially-implemented subclass breaking.
+
+/// Implements runtime-specific code generation functions.
+class CGObjCRuntime {
+public:
+ virtual ~CGObjCRuntime();
+
+ /// Generate an Objective-C message send operation
+ virtual llvm::Value *GenerateMessageSend(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ llvm::Value *Receiver,
+ Selector Sel,
+ 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() =0;
+ /// Get a selector for the specified name and type values
+ virtual llvm::Value *GetSelector(llvm::IRBuilder &Builder, Selector Sel) = 0;
+ /// Generate a constant string object
+ virtual llvm::Constant *GenerateConstantString(const char *String,
+ const size_t Length) = 0;
+ /// Generate a category. A category contains a list of methods (and
+ /// accompanying metadata) and a list of protocols.
+ virtual void GenerateCategory(const char *ClassName, const char *CategoryName,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols) =0;
+ /// Generate a class stucture for this class.
+ virtual void GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets,
+ const llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<Selector> &ClassMethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes,
+ const llvm::SmallVectorImpl<std::string> &Protocols) =0;
+ /// Generate a reference to the named protocol.
+ virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder &Builder, const char
+ *ProtocolName) =0;
+ virtual llvm::Value *GenerateMessageSendSuper(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ Selector Sel,
+ llvm::Value** ArgV,
+ unsigned ArgC) = 0;
+ /// Generate the named protocol. Protocols contain method metadata but no
+ /// implementations.
+ virtual void GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVectorImpl<std::string> &Protocols,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &ClassMethodTypes) =0;
+ /// Generate a function preamble for a method with the specified types
+ virtual llvm::Function *MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
+ const llvm::Type *ReturnTy,
+ const llvm::Type *SelfTy,
+ const llvm::Type **ArgTy,
+ unsigned ArgC,
+ bool isClassMethod,
+ bool isVarArg) = 0;
+ /// Look up the class for the specified name
+ virtual llvm::Value *LookupClass(llvm::IRBuilder &Builder, llvm::Value
+ *ClassName) =0;
+ /// If instance variable addresses are determined at runtime then this should
+ /// return true, otherwise instance variables will be accessed directly from
+ /// the structure. If this returns true then @defs is invalid for this
+ /// runtime and a warning should be generated.
+ virtual bool LateBoundIVars() { return false; }
+};
+
+/// Creates an instance of an Objective-C runtime class.
+//TODO: This should include some way of selecting which runtime to target.
+CGObjCRuntime *CreateObjCRuntime(CodeGenModule &CGM);
+}
+}
+#endif