[cfe-dev] Objective-C top-level constructs code generation
Devang Patel
dpatel at apple.com
Tue May 27 15:07:42 PDT 2008
Hi David,
>
> Index: CGObjCRuntime.h
> ===================================================================
> --- CGObjCRuntime.h (revision 51550)
> +++ CGObjCRuntime.h (working copy)
> @@ -15,6 +15,7 @@
>
> #ifndef CLANG_CODEGEN_OBCJRUNTIME_H
> #define CLANG_CODEGEN_OBCJRUNTIME_H
> +#include "llvm/ADT/SmallVector.h"
>
> namespace llvm {
> class IRBuilder;
> @@ -25,11 +26,15 @@
> class Function;
> }
>
> +//FIXME: The capitalisation of methods in this class is horribly
> inconsistent.
This is not useful. In some sense, it encourages someone to be sloppy
and hope that everything will be fixed!
>
> namespace clang {
> namespace CodeGen {
>
> -// Implements runtime-specific code generation functions
> +//FIXME Several methods should be pure virtual but aren't to avoid
> the
> +//partially-implemented subclass breaking.
This is not specific. Remove this from here and add individual FIXMEs.
> +
> +/// Implements runtime-specific code generation functions.
> class CGObjCRuntime {
> public:
> virtual ~CGObjCRuntime();
> @@ -41,16 +46,71 @@
> llvm::Value *Receiver,
> llvm::Value *Selector,
> llvm::Value** ArgV,
> - unsigned ArgC) = 0;
> + unsigned ArgC) =0;
> /// Generate the function required to register all Objective-C
> components in
> /// this compilation unit with the runtime library.
> - virtual llvm::Function *ModuleInitFunction() { return 0; }
> + virtual llvm::Function *ModuleInitFunction() =0;
> + /// Get a selector for the specified name and type values
> + virtual llvm::Value *getSelector(llvm::IRBuilder &Builder,
> + llvm::Value *SelName,
> + llvm::Value *SelTypes) =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::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
If use
llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames
then you do not hard code vector size here and let each runtime
implementation use it appropriate size.
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16> &Protocols) =0;
> + /// Generate a class stucture for this class.
> + virtual void GenerateClass(
> + const char *ClassName,
> + const char *SuperClassName,
> + const int instanceSize,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarOffsets,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16> &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,
GenereateMessage...
> + const llvm::Type
> *ReturnTy,
> + llvm::Value *Sender,
> + const char
> *SuperClassName,
> + llvm::Value *Receiver,
> + llvm::Value *Selector,
> + llvm::Value** ArgV,
> + unsigned ArgC) {return
> NULL;};
> + /// Generate the named protocol. Protocols contain method
> metadata but no
> + /// implementations.
> + virtual void GenerateProtocol(const char *ProtocolName,
> + const llvm::SmallVector<std::string, 16> &Protocols,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes) =0;
> /// Generate a function preamble for a method with the specified
> types
> - virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
> + 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
> Index: CGObjCGNU.cpp
> ===================================================================
> --- CGObjCGNU.cpp (revision 51550)
> +++ CGObjCGNU.cpp (working copy)
> @@ -16,11 +16,25 @@
> #include "llvm/Support/Compiler.h"
> #include "llvm/Support/IRBuilder.h"
> #include "llvm/ADT/SmallVector.h"
> +#include <cstdarg>
> +#include <map>
>
> +// Some zeros used for GEPs in lots of places.
> +static llvm::Constant *Zeros[] =
> {llvm::ConstantInt::get(llvm::Type::Int32Ty, 0),
> + llvm::ConstantInt::get(llvm::Type::Int32Ty, 0) };
> +static llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(
> + llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
> +
> +// The version of the runtime that this class targets. Must match
> the version
> +// in the runtime.
> +const static int RuntimeVersion = 8;
> +static llvm::Constant *ProtocolVersion =
> + llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);
> namespace {
> class CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
> private:
> llvm::Module &TheModule;
> + const llvm::StructType *SelStructTy;
> const llvm::Type *SelectorTy;
> const llvm::Type *PtrToInt8Ty;
> const llvm::Type *IMPTy;
> @@ -29,10 +43,51 @@
> 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;
> + std::map<std::string, llvm::Constant*> ExistingProtocols;
> + typedef std::pair<std::string, std::string> TypedSelector;
> + std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
> + std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;
> +private:
> + llvm::Constant *GenerateIvarList(
> + const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
> + const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
> + const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets);
> + llvm::Constant *GenerateMethodList(const std::string &ClassName,
> + const std::string &CategoryName,
> + const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16> &MethodTypes,
> + bool isClassMethodList);
> + llvm::Constant *GenerateProtocolList(
> + const llvm::SmallVector<std::string, 16> &Protocols);
> + llvm::Constant *GenerateClassStructure(
> + llvm::Constant *MetaClass,
> + llvm::Constant *SuperClass,
> + unsigned info,
> + llvm::Constant *Name,
> + llvm::Constant *Version,
> + llvm::Constant *InstanceSize,
> + llvm::Constant *IVars,
> + llvm::Constant *Methods,
> + llvm::Constant *Protocols);
> + llvm::Constant *GenerateProtocolMethodList(
> + const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16> &MethodTypes);
> + llvm::Constant *MakeConstantString(const std::string &Str, const
> std::string
> + &Name="");
> + llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
> + std::vector<llvm::Constant*> V, std::string Name="");
> + llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
> + std::vector<llvm::Constant*> V, std::string Name="");
> public:
> CGObjCGNU(llvm::Module &Mp,
> const llvm::Type *LLVMIntType,
> const llvm::Type *LLVMLongType);
> + 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,
> @@ -40,17 +95,74 @@
> llvm::Value *Selector,
> llvm::Value** ArgV,
> unsigned ArgC);
> - llvm::Value *getSelector(llvm::IRBuilder &Builder,
> + virtual llvm::Value *generateMessageSendSuper(llvm::IRBuilder
> &Builder,
> + const llvm::Type
> *ReturnTy,
> + llvm::Value *Sender,
> + const char
> *SuperClassName,
> + llvm::Value *Receiver,
> + llvm::Value *Selector,
> + llvm::Value** ArgV,
> + unsigned ArgC);
> + virtual llvm::Value *LookupClass(llvm::IRBuilder &Builder,
> llvm::Value
> + *ClassName);
> + virtual llvm::Value *getSelector(llvm::IRBuilder &Builder,
GetSelector ...
> llvm::Value *SelName,
> llvm::Value *SelTypes);
> - virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
> - const llvm::Type *SelfTy,
> - const llvm::Type **ArgTy,
> - unsigned ArgC,
> - bool isVarArg);
> + 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::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16>
> &Protocols);
> + virtual void GenerateClass(
> + const char *ClassName,
> + const char *SuperClassName,
> + const int instanceSize,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarOffsets,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16>
> &Protocols);
> + virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder
> &Builder, const char
> + *ProtocolName);
> + virtual void GenerateProtocol(const char *ProtocolName,
> + const llvm::SmallVector<std::string, 16> &Protocols,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes);
> + virtual llvm::Function *ModuleInitFunction();
> };
> } // end anonymous namespace
>
> +
> +
> +static std::string SymbolNameForClass(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)
> +{
> + if (isClassMethod) {
> + return "._objc_method_" + ClassName +"("+CategoryName+")"+ "+"
> + MethodName;
> + }
nit pick. Use { } only if the block is more then 1 line.
> + return "._objc_method_" + ClassName +"("+CategoryName+")"+ "-" +
> MethodName;
> +}
> +
> CGObjCGNU::CGObjCGNU(llvm::Module &M,
> const llvm::Type *LLVMIntType,
> const llvm::Type *LLVMLongType) :
> @@ -62,11 +174,12 @@
> PtrToInt8Ty =
> llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
> // Get the selector Type.
> - const llvm::Type *SelStructTy = llvm::StructType::get(
> + SelStructTy = llvm::StructType::get(
> PtrToInt8Ty,
> PtrToInt8Ty,
> NULL);
> SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
> + M.addTypeName(".objc_selector", SelectorTy);
> PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
> PtrTy = PtrToInt8Ty;
>
> @@ -77,24 +190,65 @@
> llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())-
> >refineAbstractTypeTo(IdTy);
> IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
> IdTy = llvm::PointerType::getUnqual(IdTy);
> + M.addTypeName(".objc_id", IdTy);
>
> // IMP type
> std::vector<const llvm::Type*> IMPArgs;
> IMPArgs.push_back(IdTy);
> IMPArgs.push_back(SelectorTy);
> IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
> -
> + M.addTypeName(".objc_imp", IMPTy);
> }
> +// 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);
> +}
>
> /// Looks up the selector for the specified name / type pair.
> // FIXME: Selectors should be statically cached, not looked up on
> every call.
> llvm::Value *CGObjCGNU::getSelector(llvm::IRBuilder &Builder,
> llvm::Value *SelName,
> - llvm::Value *SelTypes)
> -{
> - // Look up the selector.
> + llvm::Value *SelTypes) {
> + // For static selectors, we return an alias for now then store
> them all in a
> + // list that the runtime will initialise later.
> + if (llvm::Constant *CName =
> llvm::dyn_cast<llvm::Constant>(SelName)) {
> + // Untyped selector
> + if (SelTypes == 0) {
> + // If it's already cached, return it.
> + if (UntypedSelectors[CName->getStringValue()]) {
> + return Builder.CreateLoad(UntypedSelectors[CName-
> >getStringValue()]);
> + }
> + // If it isn't, cache it.
> + llvm::GlobalAlias *Sel = new
> llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
> + llvm::GlobalValue::InternalLinkage,
> ".objc_untyped_selector_alias", NULL,
> + &TheModule);
> + UntypedSelectors[CName->getStringValue()] = Sel;
> + return Builder.CreateLoad(Sel);
> + }
> + // Typed selectors
> + if (llvm::Constant *CTypes =
> llvm::dyn_cast<llvm::Constant>(SelTypes)) {
> + TypedSelector Selector = TypedSelector(CName->getStringValue(),
> + CTypes->getStringValue());
> + // If it's already cached, return it.
> + if (TypedSelectors[Selector]) {
> + return Builder.CreateLoad(TypedSelectors[Selector]);
> + }
> + // If it isn't, cache it.
> + llvm::GlobalAlias *Sel = new
> llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
> + llvm::GlobalValue::InternalLinkage,
> ".objc_typed_selector_alias", NULL,
> + &TheModule);
> + TypedSelectors[Selector] = Sel;
> + return Builder.CreateLoad(Sel);
> + }
> + }
> + // Dynamically look up selectors from non-constant sources
> llvm::Value *cmd;
> - if(SelTypes == 0) {
> + if (SelTypes == 0) {
> llvm::Constant *SelFunction =
> TheModule.getOrInsertFunction("sel_get_uid",
> SelectorTy,
> PtrToInt8Ty,
> @@ -114,10 +268,88 @@
> }
>
>
> +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, std::string Name) {
Please use vector reference here
> + 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, std::string Name) {
and here.
> + 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 Objective-C
> without an
> +//OpenStep implementation, this should let them select their own
> class for
> +//constant strings.
:) Here, you want to say "GNU Objective-C runtime" here.
> +llvm::Constant *CGObjCGNU::GenerateConstantString(const char
> *String, const
> + size_t length) {
> + std::vector<llvm::Constant*> Ivars;
> + Ivars.push_back(NULLPtr);
> + Ivars.push_back(MakeConstantString(String));
> + 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;
> +}
> +llvm::Value *CGObjCGNU::generateMessageSendSuper(llvm::IRBuilder
> &Builder,
> + const llvm::Type
> *ReturnTy,
> + llvm::Value *Sender,
> + const char
> *SuperClassName,
> + llvm::Value *Receiver,
> + llvm::Value *Selector,
> + 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, Selector, 0);
> + 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);
> + 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 on the GNU runtime.
> -// FIXME: Much of this code will need factoring out later.
> -// TODO: This should take a sender argument (pointer to self in the
> calling
> -// context)
> llvm::Value *CGObjCGNU::generateMessageSend(llvm::IRBuilder &Builder,
> const llvm::Type
> *ReturnTy,
> llvm::Value *Sender,
> @@ -129,12 +361,21 @@
>
> // Look up the method implementation.
> std::vector<const llvm::Type*> impArgTypes;
> + const llvm::Type *RetTy;
> + if (ReturnTy->isFirstClassType() && ReturnTy !=
> llvm::Type::VoidTy) {
Now, isSingleType() is now preferred over isFirstClassType() here and
other places where you check return type.
> + RetTy = ReturnTy;
> + } else {
> + // For struct returns allocate the space in the caller and pass
> it up to
> + // the sender.
Note, LLVM is moving in the direction to where return will be able to
return aggregates.
> + 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(ReturnTy,
> impArgTypes,
> + llvm::FunctionType *impType = llvm::FunctionType::get(RetTy,
> impArgTypes,
> true);
>
> llvm::Constant *lookupFunction =
> @@ -144,20 +385,480 @@
> llvm::Value *imp = Builder.CreateCall2(lookupFunction, Receiver,
> cmd);
>
> // Call the method.
> - llvm::SmallVector<llvm::Value*, 16> lookupArgs;
> - lookupArgs.push_back(Receiver);
> - lookupArgs.push_back(cmd);
> - lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC);
> - return Builder.CreateCall(imp, lookupArgs.begin(),
> lookupArgs.end());
> + if (ReturnTy->isFirstClassType() && ReturnTy !=
> llvm::Type::VoidTy) {
> + llvm::SmallVector<llvm::Value*, 16> Args;
> + Args.push_back(Receiver);
> + Args.push_back(cmd);
> + Args.insert(Args.end(), ArgV, ArgV+ArgC);
> + return Builder.CreateCall(imp, Args.begin(), Args.end());
> + } else {
> + llvm::SmallVector<llvm::Value*, 16> Args;
> + 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);
> + Builder.CreateCall(imp, Args.begin(), Args.end());
> + return Return;
> + }
> }
>
> +/// 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::SmallVector<llvm::Constant*,
> + 16> &MethodNames, const llvm::SmallVector<llvm::Constant*, 16>
> + &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 ; i<MethodTypes.size() ; i++) {
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));
> + llvm::Constant *Method =
> + TheModule.getFunction(SymbolNameForMethod(ClassName,
> CategoryName,
> + MethodNames[i]->getStringValue(), 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,
> + MethodNames.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::SmallVector<llvm::Constant*, 16> &IvarNames,
> + const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
> + const llvm::SmallVector<llvm::Constant*, 16> &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 ; i<IvarNames.size() ; 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,
> + llvm::Constant *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(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-
> >getStringValue()));
> +}
Add extra line before starting new function.
> +llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
> + const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16> &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 ; i<MethodTypes.size() ; 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::SmallVector<std::string, 16> &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() ; iter !=
> Protocols.end() ;
> + 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::SmallVector<std::string, 16> &Protocols,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &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(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::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16> &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, InstanceMethodNames, InstanceMethodTypes,
> false),
> + PtrTy));
> + // Class method list
> +
> Elements
> .push_back
> (llvm::ConstantExpr::getBitCast(GenerateMethodList(ClassName,
> + CategoryName, ClassMethodNames, 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::SmallVector<llvm::Constant*, 16>
> &IvarNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &IvarOffsets,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &InstanceMethodTypes,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodNames,
> + const llvm::SmallVector<llvm::Constant*, 16>
> &ClassMethodTypes,
> + const llvm::SmallVector<std::string, 16> &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));
> + }
> + llvm::Constant * Name = MakeConstantString(ClassName,
> ".class_name");
> + // Empty vector used to construct empty method lists
> + llvm::SmallVector<llvm::Constant*, 16> empty;
> + // Generate the method and instance variable lists
> + llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
> + InstanceMethodNames, InstanceMethodTypes, false);
> + llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
> + ClassMethodNames, ClassMethodTypes, true);
> + llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
> + IvarOffsets);
> + //Generate metaclass for class methods
> + llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
> + NULLPtr, 0x2L, NULLPtr, 0, Zeros[0], GenerateIvarList(
> + empty, empty, empty), ClassMethodList, NULLPtr);
> + // Generate the class structure
> + llvm::Constant *ClassStruct =
> GenerateClassStructure(MetaClassStruct,
> + SuperClass, 0x1L, Name, 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.size() + Categories.size() + ConstantStrings.size() +
> + ExistingProtocols.size() + TypedSelectors.size() +
> + UntypedSelectors.size() == 0) {
> + return NULL;
> + }
> + 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::Constant *Statics = MakeGlobal(StaticsListTy, Elements,
> ".objc_statics");
> + Statics = new
> +
> llvm::GlobalVariable(llvm::PointerType::getUnqual(StaticsListTy),
> false,
> + llvm::GlobalValue::InternalLinkage, Statics,
> ".objc_statics_ptr",
> + &TheModule);
> + 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() ; iter!=TypedSelectors.end() ;
> iter++) {
> + Elements.push_back(MakeConstantString((*iter).first.first,
> ".objc_sel_name"));
> + Elements.push_back(MakeConstantString((*iter).first.first,
> ".objc_sel_types"));
> + Selectors.push_back(llvm::ConstantStruct::get(SelStructTy,
> Elements));
> + Elements.clear();
> + }
> + for(std::map<std::string, llvm::GlobalAlias*>::iterator
> + iter=UntypedSelectors.begin() ; iter!
> =UntypedSelectors.end() ; iter++) {
> + Elements.push_back(MakeConstantString((*iter).first,
> ".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() ; iter!=TypedSelectors.end() ;
> iter++) {
Please use
for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
iter != iterEnd; ++iter)
form here and other places.
> + 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(std::map<std::string, llvm::GlobalAlias*>::iterator
> + iter=UntypedSelectors.begin() ; iter!
> =UntypedSelectors.end() ; 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->isFirstClassType() && 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);
> @@ -165,12 +866,20 @@
> 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,
> - ".objc.method",
> + FunctionName,
> &TheModule);
> - // Set the names of the hidden arguments
> 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");
> Index: CodeGenModule.cpp
> ===================================================================
> --- CodeGenModule.cpp (revision 51550)
> +++ CodeGenModule.cpp (working copy)
> @@ -25,6 +25,7 @@
> #include "llvm/DerivedTypes.h"
> #include "llvm/Module.h"
> #include "llvm/Intrinsics.h"
> +#include "llvm/Target/TargetData.h"
> #include "llvm/Analysis/Verifier.h"
> #include <algorithm>
> using namespace clang;
> @@ -49,10 +50,10 @@
> }
>
> CodeGenModule::~CodeGenModule() {
> + EmitStatics();
> llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction();
> if (ObjCInitFunction)
> AddGlobalCtor(ObjCInitFunction);
> - EmitStatics();
> EmitGlobalCtors();
> EmitAnnotations();
> delete Runtime;
> @@ -328,7 +329,159 @@
> if (OMD->getBody())
> CodeGenFunction(*this).GenerateObjCMethod(OMD);
> }
> +void CodeGenModule::EmitObjCProtocolImplementation(const
> ObjCProtocolDecl *PD){
Why are these methods not runtime specific ?
> + llvm::SmallVector<std::string, 16> Protocols;
> + for(unsigned i=0 ; i<PD->getNumReferencedProtocols() ; i++)
> + {
> + Protocols.push_back(PD->getReferencedProtocols()[i]->getName());
> + }
Avoid unnecessary { and }
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> + for(ObjCProtocolDecl::instmeth_iterator iter = PD-
> >instmeth_begin() ;
> + iter != PD->instmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + InstanceMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + InstanceMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> + // Collect information about class methods:
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> + for(ObjCProtocolDecl::classmeth_iterator iter = PD-
> >classmeth_begin() ;
> + iter != PD->classmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + ClassMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + ClassMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> + Runtime->GenerateProtocol(PD->getName(), Protocols,
> InstanceMethodNames,
> + InstanceMethodTypes, ClassMethodNames, ClassMethodTypes);
> +}
>
> +void CodeGenModule::EmitObjCCategoryImpl(const ObjCCategoryImplDecl
> *OCD) {
> +
> + // Collect information about instance methods
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> + for(ObjCCategoryDecl::instmeth_iterator iter = OCD-
> >instmeth_begin() ;
> + iter != OCD->instmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + InstanceMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + InstanceMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> +
> + // Collect information about class methods
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> + for(ObjCCategoryDecl::classmeth_iterator iter = OCD-
> >classmeth_begin() ;
> + iter != OCD->classmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + ClassMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + ClassMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> +
> + // Collect the names of referenced protocols
> + llvm::SmallVector<std::string, 16> Protocols;
> + ObjCInterfaceDecl * ClassDecl = (ObjCInterfaceDecl*)OCD-
> >getClassInterface();
> + for(unsigned i=0 ; i<ClassDecl->getNumIntfRefProtocols() ; i++) {
> + Protocols.push_back(ClassDecl->getReferencedProtocols()[i]-
> >getName());
> + }
> +
> + // Generate the category
> + Runtime->GenerateCategory(OCD->getClassInterface()->getName(),
> + OCD->getName(), InstanceMethodNames, InstanceMethodTypes,
> + ClassMethodNames, ClassMethodTypes, Protocols);
> +}
> +
> +void CodeGenModule::EmitObjCClassImplementation(
> + const ObjCImplementationDecl *OID) {
> + // Get the superclass name.
> + const ObjCInterfaceDecl * SCDecl = OID->getClassInterface()-
> >getSuperClass();
> + const char * SCName = NULL;
> + if (SCDecl) {
> + SCName = SCDecl->getName();
> + }
> +
> + // Get the class name
> + ObjCInterfaceDecl * ClassDecl = (ObjCInterfaceDecl*)OID-
> >getClassInterface();
> + const char * ClassName = ClassDecl->getName();
> +
> + // Get the size of instances. For runtimes that support late-
> bound instances
> + // this should probably be something different (size just of
> instance
> + // varaibles in this class, not superclasses?).
> + int instanceSize = 0;
> + const llvm::Type *ObjTy;
> + if (!Runtime->LateBoundIVars()) {
> + ObjTy =
> getTypes().ConvertType(Context.getObjCInterfaceType(ClassDecl));
> + instanceSize = TheTargetData.getABITypeSize(ObjTy);
> + }
> +
> + // Collect information about instance variables.
> + llvm::SmallVector<llvm::Constant*, 16> IvarNames;
> + llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
> + llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
> + const llvm::StructLayout *Layout =
> + TheTargetData.getStructLayout(llvm::cast<const
> llvm::StructType>(ObjTy));
> + ObjTy = llvm::PointerType::getUnqual(ObjTy);
> + for(ObjCInterfaceDecl::ivar_iterator iter = ClassDecl-
> >ivar_begin() ;
> + iter != ClassDecl->ivar_end() ; iter++) {
> + // Store the name
> + IvarNames.push_back(GetAddrOfConstantString((*iter)-
> >getName()));
> + // Get the type encoding for this ivar
> + std::string TypeStr;
> + llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
> + Context.getObjCEncodingForType((*iter)->getType(), TypeStr,
> + EncodingRecordTypes);
> + IvarTypes.push_back(GetAddrOfConstantString(TypeStr));
> + // Get the offset
> + int offset =
> + (int)Layout-
> >getElementOffset(getTypes().getLLVMFieldNo(*iter));
> + IvarOffsets.push_back(
> + llvm::ConstantInt::get(llvm::Type::Int32Ty, offset));
> + }
> +
> + // Collect information about instance methods
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> + for(ObjCImplementationDecl::instmeth_iterator iter = OID-
> >instmeth_begin() ;
> + iter != OID->instmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + InstanceMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + InstanceMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> +
> + // Collect information about class methods
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
> + llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> + for(ObjCImplementationDecl::classmeth_iterator iter = OID-
> >classmeth_begin() ;
> + iter != OID->classmeth_end() ; iter++) {
> + std::string TypeStr;
> + Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
> + ClassMethodNames.push_back(
> + GetAddrOfConstantString((*iter)->getSelector().getName()));
> + ClassMethodTypes.push_back(GetAddrOfConstantString(TypeStr));
> + }
> + // Collect the names of referenced protocols
> + llvm::SmallVector<std::string, 16> Protocols;
> + for(unsigned i=0 ; i<ClassDecl->getNumIntfRefProtocols() ; i++) {
> + Protocols.push_back(ClassDecl->getReferencedProtocols()[i]-
> >getName());
> + }
> +
> + // Generate the category
> + Runtime->GenerateClass(ClassName, SCName, instanceSize,
> IvarNames, IvarTypes,
> + IvarOffsets, InstanceMethodNames, InstanceMethodTypes,
> ClassMethodNames,
> + ClassMethodTypes, Protocols);
> +}
> +
> +
> void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
> // If this is not a prototype, emit the body.
> if (!FD->isThisDeclarationADefinition())
> @@ -600,6 +753,7 @@
> return MemSetFn = getIntrinsic(IID);
> }
>
> +// FIXME: This needs moving into an Apple Objective-C runtime class
> llvm::Constant *CodeGenModule::
> GetAddrOfConstantCFString(const std::string &str) {
> llvm::StringMapEntry<llvm::Constant *> &Entry =
> Index: CodeGenFunction.cpp
> ===================================================================
> --- CodeGenFunction.cpp (revision 51550)
> +++ CodeGenFunction.cpp (working copy)
> @@ -65,11 +65,22 @@
> for (unsigned i=0 ; i<OMD->param_size() ; i++) {
> ParamTypes.push_back(ConvertType(OMD->getParamDecl(i)-
> >getType()));
> }
> - CurFn =CGM.getObjCRuntime()->MethodPreamble(ConvertType(OMD-
> >getResultType()),
> -
> llvm::PointerType::getUnqual(llvm::Type::Int32Ty),
> - ParamTypes.begin(),
> - OMD->param_size(),
> - OMD->isVariadic());
> + std::string CategoryName = "";
> + if (ObjCCategoryImplDecl *OCD =
> + dyn_cast<ObjCCategoryImplDecl>(OMD->getMethodContext())) {
> + CategoryName = OCD->getName();
> + }
> +
> + CurFn =CGM.getObjCRuntime()->MethodPreamble(
> + OMD->getClassInterface()->getName(),
> + CategoryName,
> + OMD->getSelector().getName(),
> + ConvertType(OMD->getResultType()),
> +
> 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
> Index: CodeGenModule.h
> ===================================================================
> --- CodeGenModule.h (revision 51550)
> +++ CodeGenModule.h (working copy)
> @@ -32,6 +32,9 @@
> class ASTContext;
> class FunctionDecl;
> class ObjCMethodDecl;
> + class ObjCImplementationDecl;
> + class ObjCCategoryImplDecl;
> + class ObjCProtocolDecl;
> class Decl;
> class Expr;
> class Stmt;
> @@ -112,6 +115,9 @@
> void EmitStatics(void);
>
> void EmitObjCMethod(const ObjCMethodDecl *OMD);
> + void EmitObjCCategoryImpl(const ObjCCategoryImplDecl *OCD);
> + void EmitObjCClassImplementation(const ObjCImplementationDecl
> *OID);
> + void EmitObjCProtocolImplementation(const ObjCProtocolDecl *PD);
> void EmitFunction(const FunctionDecl *FD);
> void EmitGlobalVar(const VarDecl *D);
> void EmitGlobalVarInit(const VarDecl *D);
> Index: ModuleBuilder.cpp
> ===================================================================
> --- ModuleBuilder.cpp (revision 51550)
> +++ ModuleBuilder.cpp (working copy)
> @@ -66,6 +66,24 @@
>
> if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
> Builder->EmitFunction(FD);
> + } else if (dyn_cast<ObjCClassDecl>(D)){
> + //Forward declaration. Only used for type checking.
> + } else if (ObjCProtocolDecl *PD =
> dyn_cast<ObjCProtocolDecl>(D)){
> + // Generate Protocol object.
> + Builder->EmitObjCProtocolImplementation(PD);
> + } else if (dyn_cast<ObjCCategoryDecl>(D)){
> + //Only used for typechecking.
> + } else if (ObjCCategoryImplDecl *OCD =
> dyn_cast<ObjCCategoryImplDecl>(D)){
> + // Generate methods, attach to category structure
> + Builder->EmitObjCCategoryImpl(OCD);
> + } else if (ObjCImplementationDecl * OID =
> + dyn_cast<ObjCImplementationDecl>(D)){
> + // Generate methods, attach to class structure
> + Builder->EmitObjCClassImplementation(OID);
> + } else if (dyn_cast<ObjCInterfaceDecl>(D)){
> + // Ignore - generated when the implementation decl is
> CodeGen'd
> + } else if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)){
> + Builder->EmitObjCMethod(OMD);
> } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
> if (VD->isFileVarDecl())
> Builder->EmitGlobalVarDeclarator(VD);
>
-
Devang
More information about the cfe-dev
mailing list