diff options
-rw-r--r-- | COPYING.Clang | 63 | ||||
-rw-r--r-- | Clang/CGObjC.cpp | 193 | ||||
-rw-r--r-- | Clang/CGObjCGNU.cpp | 869 | ||||
-rw-r--r-- | Clang/CGObjCRuntime.h | 126 |
4 files changed, 1251 insertions, 0 deletions
diff --git a/COPYING.Clang b/COPYING.Clang new file mode 100644 index 0000000..21cb5c7 --- /dev/null +++ b/COPYING.Clang @@ -0,0 +1,63 @@ +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2007 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +<none yet> + 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 |