2008-06-01 22:13:53 +08:00
|
|
|
//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
2008-03-01 16:50:34 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-06-01 22:13:53 +08:00
|
|
|
// 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.
|
2008-03-01 16:50:34 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "CGObjCRuntime.h"
|
2008-06-26 12:19:03 +08:00
|
|
|
#include "CodeGenModule.h"
|
2008-08-23 11:46:30 +08:00
|
|
|
#include "CodeGenFunction.h"
|
2009-05-08 08:11:50 +08:00
|
|
|
|
2008-06-26 12:19:03 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2008-08-13 08:59:25 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-07-19 03:43:29 +08:00
|
|
|
#include "clang/AST/RecordLayout.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/StmtObjC.h"
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
#include "llvm/Intrinsics.h"
|
2008-03-01 16:50:34 +08:00
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2008-06-01 22:13:53 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2008-08-16 06:20:32 +08:00
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Target/TargetData.h"
|
2009-05-08 08:11:50 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
#include <map>
|
2009-01-27 13:06:01 +08:00
|
|
|
|
|
|
|
|
2008-06-26 12:19:03 +08:00
|
|
|
using namespace clang;
|
2008-09-09 09:06:48 +08:00
|
|
|
using namespace CodeGen;
|
2008-06-01 22:13:53 +08:00
|
|
|
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;
|
2009-05-21 02:41:51 +08:00
|
|
|
static const int NonFragileRuntimeVersion = 9;
|
2008-06-01 22:13:53 +08:00
|
|
|
static const int ProtocolVersion = 2;
|
2009-09-11 05:48:21 +08:00
|
|
|
static const int NonFragileProtocolVersion = 3;
|
2008-03-01 16:50:34 +08:00
|
|
|
|
|
|
|
namespace {
|
2008-06-26 12:19:03 +08:00
|
|
|
class CGObjCGNU : public CodeGen::CGObjCRuntime {
|
2008-03-01 16:50:34 +08:00
|
|
|
private:
|
2008-06-26 12:19:03 +08:00
|
|
|
CodeGen::CodeGenModule &CGM;
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Module &TheModule;
|
2009-01-27 13:06:01 +08:00
|
|
|
const llvm::PointerType *SelectorTy;
|
2009-09-11 05:48:21 +08:00
|
|
|
const llvm::IntegerType *Int8Ty;
|
2009-01-27 13:06:01 +08:00
|
|
|
const llvm::PointerType *PtrToInt8Ty;
|
2009-02-05 04:31:19 +08:00
|
|
|
const llvm::FunctionType *IMPTy;
|
2009-01-27 13:06:01 +08:00
|
|
|
const llvm::PointerType *IdTy;
|
2009-08-18 00:35:33 +08:00
|
|
|
QualType ASTIdTy;
|
2009-01-27 13:06:01 +08:00
|
|
|
const llvm::IntegerType *IntTy;
|
|
|
|
const llvm::PointerType *PtrTy;
|
|
|
|
const llvm::IntegerType *LongTy;
|
|
|
|
const llvm::PointerType *PtrToIntTy;
|
2009-05-04 23:31:17 +08:00
|
|
|
llvm::GlobalAlias *ClassPtrAlias;
|
|
|
|
llvm::GlobalAlias *MetaClassPtrAlias;
|
2008-06-01 22:13:53 +08:00
|
|
|
std::vector<llvm::Constant*> Classes;
|
|
|
|
std::vector<llvm::Constant*> Categories;
|
|
|
|
std::vector<llvm::Constant*> ConstantStrings;
|
2010-01-27 20:49:23 +08:00
|
|
|
llvm::StringMap<llvm::Constant*> ObjCStrings;
|
2008-06-01 22:13:53 +08:00
|
|
|
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;
|
2009-07-15 07:10:40 +08:00
|
|
|
llvm::LLVMContext &VMContext;
|
2008-06-01 22:13:53 +08:00
|
|
|
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,
|
2009-09-09 23:08:12 +08:00
|
|
|
const llvm::SmallVectorImpl<Selector> &MethodSels,
|
|
|
|
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
|
2008-06-01 22:13:53 +08:00
|
|
|
bool isClassMethodList);
|
2009-04-01 02:27:22 +08:00
|
|
|
llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName);
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID,
|
|
|
|
llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
|
|
|
|
llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *GenerateProtocolList(
|
|
|
|
const llvm::SmallVectorImpl<std::string> &Protocols);
|
2009-09-11 05:48:21 +08:00
|
|
|
// To ensure that all protocols are seen by the runtime, we add a category on
|
|
|
|
// a class defined in the runtime, declaring no methods, but adopting the
|
|
|
|
// protocols.
|
|
|
|
void GenerateProtocolHolderCategory(void);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *GenerateClassStructure(
|
|
|
|
llvm::Constant *MetaClass,
|
|
|
|
llvm::Constant *SuperClass,
|
|
|
|
unsigned info,
|
2008-06-26 12:47:04 +08:00
|
|
|
const char *Name,
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *Version,
|
|
|
|
llvm::Constant *InstanceSize,
|
|
|
|
llvm::Constant *IVars,
|
|
|
|
llvm::Constant *Methods,
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *Protocols,
|
|
|
|
llvm::Constant *IvarOffsets,
|
|
|
|
llvm::Constant *Properties);
|
2008-06-01 22:13:53 +08:00
|
|
|
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="");
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
|
|
|
|
prefix);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
|
2010-01-08 08:14:31 +08:00
|
|
|
std::vector<llvm::Constant*> &V, const std::string &Name="",
|
|
|
|
llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
|
2010-01-08 08:14:31 +08:00
|
|
|
std::vector<llvm::Constant*> &V, const std::string &Name="",
|
|
|
|
llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
|
2009-05-21 02:41:51 +08:00
|
|
|
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
|
|
|
|
const ObjCIvarDecl *Ivar);
|
2009-06-15 09:09:11 +08:00
|
|
|
void EmitClassRef(const std::string &className);
|
2008-03-01 16:50:34 +08:00
|
|
|
public:
|
2008-06-26 12:19:03 +08:00
|
|
|
CGObjCGNU(CodeGen::CodeGenModule &cgm);
|
2010-01-23 10:40:42 +08:00
|
|
|
virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
|
2009-09-09 23:08:12 +08:00
|
|
|
virtual CodeGen::RValue
|
2008-08-23 11:46:30 +08:00
|
|
|
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
2009-05-06 05:36:57 +08:00
|
|
|
const CallArgList &CallArgs,
|
|
|
|
const ObjCMethodDecl *Method);
|
2009-09-09 23:08:12 +08:00
|
|
|
virtual CodeGen::RValue
|
2008-08-23 11:46:30 +08:00
|
|
|
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
const ObjCInterfaceDecl *Class,
|
2009-03-01 04:07:56 +08:00
|
|
|
bool isCategoryImpl,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
2009-09-17 12:01:22 +08:00
|
|
|
const CallArgList &CallArgs,
|
|
|
|
const ObjCMethodDecl *Method);
|
2008-11-01 09:53:16 +08:00
|
|
|
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
|
2008-08-16 08:25:02 +08:00
|
|
|
const ObjCInterfaceDecl *OID);
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
virtual llvm::Constant *GetConstantSelector(Selector Sel);
|
|
|
|
virtual llvm::Constant *GetConstantTypedSelector(
|
|
|
|
const ObjCMethodDecl *Method);
|
|
|
|
llvm::Value *GetSelector(CGBuilderTy &Builder,
|
|
|
|
Selector Sel) {
|
|
|
|
return cast<llvm::Constant>((GetConstantSelector(Sel)));
|
|
|
|
}
|
|
|
|
llvm::Value *GetSelector(CGBuilderTy &Builder,
|
|
|
|
const ObjCMethodDecl *Method) {
|
|
|
|
return cast<llvm::Constant>(GetConstantTypedSelector(Method));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
|
2009-01-11 05:06:09 +08:00
|
|
|
const ObjCContainerDecl *CD);
|
2008-08-16 06:20:32 +08:00
|
|
|
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
|
|
|
|
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
|
2008-11-01 09:53:16 +08:00
|
|
|
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
|
2008-08-13 08:59:25 +08:00
|
|
|
const ObjCProtocolDecl *PD);
|
|
|
|
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
|
2008-06-01 22:13:53 +08:00
|
|
|
virtual llvm::Function *ModuleInitFunction();
|
2008-09-24 11:38:44 +08:00
|
|
|
virtual llvm::Function *GetPropertyGetFunction();
|
|
|
|
virtual llvm::Function *GetPropertySetFunction();
|
2009-07-24 15:40:24 +08:00
|
|
|
virtual llvm::Constant *EnumerationMutationFunction();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-21 08:49:24 +08:00
|
|
|
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
|
|
|
const Stmt &S);
|
2008-09-09 18:04:29 +08:00
|
|
|
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
|
|
|
|
const ObjCAtThrowStmt &S);
|
2008-11-19 06:37:34 +08:00
|
|
|
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
|
2008-11-19 05:45:40 +08:00
|
|
|
llvm::Value *AddrWeakObj);
|
2008-11-19 06:37:34 +08:00
|
|
|
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
|
|
|
|
llvm::Value *src, llvm::Value *dst);
|
2008-11-19 08:59:10 +08:00
|
|
|
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
|
|
|
|
llvm::Value *src, llvm::Value *dest);
|
2008-11-21 03:23:36 +08:00
|
|
|
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
|
2009-09-25 06:25:38 +08:00
|
|
|
llvm::Value *src, llvm::Value *dest,
|
|
|
|
llvm::Value *ivarOffset);
|
2008-11-19 08:59:10 +08:00
|
|
|
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
|
|
|
|
llvm::Value *src, llvm::Value *dest);
|
2009-07-08 09:18:33 +08:00
|
|
|
virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *DestPtr,
|
2009-07-08 09:18:33 +08:00
|
|
|
llvm::Value *SrcPtr,
|
2009-09-01 03:33:16 +08:00
|
|
|
QualType Ty);
|
2009-02-04 03:03:09 +08:00
|
|
|
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
|
|
|
|
QualType ObjectTy,
|
|
|
|
llvm::Value *BaseValue,
|
|
|
|
const ObjCIvarDecl *Ivar,
|
|
|
|
unsigned CVRQualifiers);
|
2009-02-11 03:02:04 +08:00
|
|
|
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
|
2009-04-22 13:08:15 +08:00
|
|
|
const ObjCInterfaceDecl *Interface,
|
2009-02-11 03:02:04 +08:00
|
|
|
const ObjCIvarDecl *Ivar);
|
2008-03-01 16:50:34 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
|
2009-06-15 09:09:11 +08:00
|
|
|
/// Emits a reference to a dummy variable which is emitted with each class.
|
|
|
|
/// This ensures that a linker error will be generated when trying to link
|
|
|
|
/// together modules where a referenced class is not defined.
|
2009-08-01 05:31:32 +08:00
|
|
|
void CGObjCGNU::EmitClassRef(const std::string &className) {
|
2009-06-15 09:09:11 +08:00
|
|
|
std::string symbolRef = "__objc_class_ref_" + className;
|
|
|
|
// Don't emit two copies of the same symbol
|
2009-08-01 05:31:32 +08:00
|
|
|
if (TheModule.getGlobalVariable(symbolRef))
|
|
|
|
return;
|
2009-06-15 09:09:11 +08:00
|
|
|
std::string symbolName = "__objc_class_name_" + className;
|
|
|
|
llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
|
|
|
|
if (!ClassSymbol) {
|
2009-07-09 03:05:04 +08:00
|
|
|
ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
|
|
|
|
llvm::GlobalValue::ExternalLinkage, 0, symbolName);
|
2009-06-15 09:09:11 +08:00
|
|
|
}
|
2009-07-09 03:05:04 +08:00
|
|
|
new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true,
|
2009-08-05 13:25:18 +08:00
|
|
|
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
|
2009-06-15 09:09:11 +08:00
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
static std::string SymbolNameForClass(const std::string &ClassName) {
|
2009-06-15 09:09:11 +08:00
|
|
|
return "_OBJC_CLASS_" + ClassName;
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
static std::string SymbolNameForMethod(const std::string &ClassName, const
|
|
|
|
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
|
|
|
|
{
|
2010-01-14 22:08:19 +08:00
|
|
|
std::string MethodNameColonStripped = MethodName;
|
|
|
|
std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
|
|
|
|
':', '_');
|
|
|
|
return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
|
|
|
|
CategoryName + "_" + MethodNameColonStripped;
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
2008-06-26 12:19:03 +08:00
|
|
|
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
|
2009-05-04 23:31:17 +08:00
|
|
|
: CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
|
2009-07-15 07:10:40 +08:00
|
|
|
MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) {
|
2009-01-27 13:06:01 +08:00
|
|
|
IntTy = cast<llvm::IntegerType>(
|
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().IntTy));
|
|
|
|
LongTy = cast<llvm::IntegerType>(
|
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().LongTy));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
Int8Ty = llvm::Type::getInt8Ty(VMContext);
|
|
|
|
// C string type. Used in lots of places.
|
|
|
|
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
|
|
|
|
|
2009-07-25 07:12:58 +08:00
|
|
|
Zeros[0] = llvm::ConstantInt::get(LongTy, 0);
|
2008-06-01 22:13:53 +08:00
|
|
|
Zeros[1] = Zeros[0];
|
2009-09-11 05:48:21 +08:00
|
|
|
NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty);
|
2008-03-31 07:03:07 +08:00
|
|
|
// Get the selector Type.
|
2010-01-23 10:40:42 +08:00
|
|
|
QualType selTy = CGM.getContext().getObjCSelType();
|
|
|
|
if (QualType() == selTy) {
|
|
|
|
SelectorTy = PtrToInt8Ty;
|
|
|
|
} else {
|
|
|
|
SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy));
|
|
|
|
}
|
2009-01-27 13:06:01 +08:00
|
|
|
|
2009-07-30 06:16:19 +08:00
|
|
|
PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
|
2008-03-31 07:03:07 +08:00
|
|
|
PtrTy = PtrToInt8Ty;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-31 07:03:07 +08:00
|
|
|
// Object type
|
2009-08-18 00:35:33 +08:00
|
|
|
ASTIdTy = CGM.getContext().getObjCIdType();
|
2010-01-23 10:40:42 +08:00
|
|
|
if (QualType() == ASTIdTy) {
|
|
|
|
IdTy = PtrToInt8Ty;
|
|
|
|
} else {
|
|
|
|
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-31 07:03:07 +08:00
|
|
|
// IMP type
|
|
|
|
std::vector<const llvm::Type*> IMPArgs;
|
|
|
|
IMPArgs.push_back(IdTy);
|
|
|
|
IMPArgs.push_back(SelectorTy);
|
2009-07-30 06:16:19 +08:00
|
|
|
IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
2009-08-01 05:31:32 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// This has to perform the lookup every time, since posing and related
|
|
|
|
// techniques can modify the name -> class mapping.
|
2008-11-01 09:53:16 +08:00
|
|
|
llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
|
2008-08-16 08:25:02 +08:00
|
|
|
const ObjCInterfaceDecl *OID) {
|
2008-11-24 13:29:24 +08:00
|
|
|
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
|
2010-01-08 08:14:31 +08:00
|
|
|
// With the incompatible ABI, this will need to be replaced with a direct
|
|
|
|
// reference to the class symbol. For the compatible nonfragile ABI we are
|
|
|
|
// still performing this lookup at run time but emitting the symbol for the
|
|
|
|
// class externally so that we can make the switch later.
|
2009-06-15 09:09:11 +08:00
|
|
|
EmitClassRef(OID->getNameAsString());
|
2008-08-16 08:25:02 +08:00
|
|
|
ClassName = Builder.CreateStructGEP(ClassName, 0);
|
|
|
|
|
2009-03-31 02:02:14 +08:00
|
|
|
std::vector<const llvm::Type*> Params(1, PtrToInt8Ty);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *ClassLookupFn =
|
2009-07-30 06:16:19 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy,
|
2009-03-31 02:02:14 +08:00
|
|
|
Params,
|
|
|
|
true),
|
|
|
|
"objc_lookup_class");
|
2008-06-01 22:13:53 +08:00
|
|
|
return Builder.CreateCall(ClassLookupFn, ClassName);
|
2008-03-31 07:03:07 +08:00
|
|
|
}
|
|
|
|
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
llvm::Constant *CGObjCGNU::GetConstantSelector(Selector Sel) {
|
2008-11-24 11:33:13 +08:00
|
|
|
llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()];
|
2008-06-26 12:37:12 +08:00
|
|
|
if (US == 0)
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
US = new llvm::GlobalAlias(SelectorTy,
|
2009-08-18 00:35:33 +08:00
|
|
|
llvm::GlobalValue::PrivateLinkage,
|
|
|
|
".objc_untyped_selector_alias"+Sel.getAsString(),
|
2008-06-26 12:37:12 +08:00
|
|
|
NULL, &TheModule);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
return US;
|
2009-05-06 05:36:57 +08:00
|
|
|
}
|
|
|
|
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
llvm::Constant *CGObjCGNU::GetConstantTypedSelector(const ObjCMethodDecl
|
2009-05-06 05:36:57 +08:00
|
|
|
*Method) {
|
|
|
|
|
|
|
|
std::string SelName = Method->getSelector().getAsString();
|
|
|
|
std::string SelTypes;
|
|
|
|
CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
|
|
|
|
// Typed selectors
|
|
|
|
TypedSelector Selector = TypedSelector(SelName,
|
|
|
|
SelTypes);
|
|
|
|
|
|
|
|
// If it's already cached, return it.
|
2009-08-01 05:31:32 +08:00
|
|
|
if (TypedSelectors[Selector]) {
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
return TypedSelectors[Selector];
|
2009-05-06 05:36:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If it isn't, cache it.
|
|
|
|
llvm::GlobalAlias *Sel = new llvm::GlobalAlias(
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
SelectorTy,
|
2009-08-18 00:35:33 +08:00
|
|
|
llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName,
|
2009-05-06 05:36:57 +08:00
|
|
|
NULL, &TheModule);
|
|
|
|
TypedSelectors[Selector] = Sel;
|
|
|
|
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
return Sel;
|
2008-06-26 12:37:12 +08:00
|
|
|
}
|
|
|
|
|
2008-06-26 12:44:19 +08:00
|
|
|
llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
|
|
|
|
const std::string &Name) {
|
2009-09-01 00:41:57 +08:00
|
|
|
llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
|
2009-07-30 02:54:39 +08:00
|
|
|
return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
|
|
|
|
const std::string prefix) {
|
|
|
|
std::string name = prefix + Str;
|
|
|
|
llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
|
|
|
|
if (!ConstStr) {
|
|
|
|
llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true);
|
|
|
|
ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
|
|
|
|
llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
|
|
|
|
}
|
|
|
|
return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
|
|
|
|
}
|
2009-08-01 05:31:32 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
|
2010-01-08 08:14:31 +08:00
|
|
|
std::vector<llvm::Constant*> &V, const std::string &Name,
|
|
|
|
llvm::GlobalValue::LinkageTypes linkage) {
|
2009-07-28 06:29:56 +08:00
|
|
|
llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
|
2009-07-09 03:05:04 +08:00
|
|
|
return new llvm::GlobalVariable(TheModule, Ty, false,
|
|
|
|
llvm::GlobalValue::InternalLinkage, C, Name);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
2009-08-01 05:31:32 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
|
2010-01-08 08:14:31 +08:00
|
|
|
std::vector<llvm::Constant*> &V, const std::string &Name,
|
|
|
|
llvm::GlobalValue::LinkageTypes linkage) {
|
2009-07-29 02:33:04 +08:00
|
|
|
llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
|
2009-07-09 03:05:04 +08:00
|
|
|
return new llvm::GlobalVariable(TheModule, Ty, false,
|
2009-08-01 05:31:32 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage, C, Name);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate an NSConstantString object.
|
2010-01-23 10:40:42 +08:00
|
|
|
llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
|
2010-01-27 20:49:23 +08:00
|
|
|
|
2010-01-23 10:40:42 +08:00
|
|
|
std::string Str(SL->getStrData(), SL->getByteLength());
|
|
|
|
|
2010-01-27 20:49:23 +08:00
|
|
|
// Look for an existing one
|
|
|
|
llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str);
|
|
|
|
if (old != ObjCStrings.end())
|
|
|
|
return old->getValue();
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
std::vector<llvm::Constant*> Ivars;
|
|
|
|
Ivars.push_back(NULLPtr);
|
2008-06-22 05:44:18 +08:00
|
|
|
Ivars.push_back(MakeConstantString(Str));
|
2009-07-25 07:12:58 +08:00
|
|
|
Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size()));
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *ObjCStr = MakeGlobal(
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
|
2008-06-01 22:13:53 +08:00
|
|
|
Ivars, ".objc_str");
|
2010-01-27 20:49:23 +08:00
|
|
|
ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
|
|
|
|
ObjCStrings[Str] = ObjCStr;
|
|
|
|
ConstantStrings.push_back(ObjCStr);
|
2008-06-01 22:13:53 +08:00
|
|
|
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.
|
2008-08-23 11:46:30 +08:00
|
|
|
CodeGen::RValue
|
|
|
|
CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
const ObjCInterfaceDecl *Class,
|
2009-03-01 04:07:56 +08:00
|
|
|
bool isCategoryImpl,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
2009-09-17 12:01:22 +08:00
|
|
|
const CallArgList &CallArgs,
|
|
|
|
const ObjCMethodDecl *Method) {
|
2009-02-05 04:31:19 +08:00
|
|
|
llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
|
|
|
|
|
|
|
|
CallArgList ActualArgs;
|
|
|
|
|
|
|
|
ActualArgs.push_back(
|
2009-08-18 00:35:33 +08:00
|
|
|
std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
|
|
|
|
ASTIdTy));
|
2009-02-05 04:31:19 +08:00
|
|
|
ActualArgs.push_back(std::make_pair(RValue::get(cmd),
|
|
|
|
CGF.getContext().getObjCSelType()));
|
|
|
|
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
|
|
|
|
|
|
|
|
CodeGenTypes &Types = CGM.getTypes();
|
|
|
|
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
|
2009-09-17 12:01:40 +08:00
|
|
|
const llvm::FunctionType *impType =
|
|
|
|
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
|
2009-02-05 04:31:19 +08:00
|
|
|
|
2009-05-04 23:31:17 +08:00
|
|
|
llvm::Value *ReceiverClass = 0;
|
2009-05-08 23:39:58 +08:00
|
|
|
if (isCategoryImpl) {
|
|
|
|
llvm::Constant *classLookupFunction = 0;
|
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
Params.push_back(PtrTy);
|
|
|
|
if (IsClassMessage) {
|
2009-07-30 06:16:19 +08:00
|
|
|
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
2009-05-08 23:39:58 +08:00
|
|
|
IdTy, Params, true), "objc_get_meta_class");
|
|
|
|
} else {
|
2009-07-30 06:16:19 +08:00
|
|
|
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
2009-05-08 23:39:58 +08:00
|
|
|
IdTy, Params, true), "objc_get_class");
|
2009-05-04 23:31:17 +08:00
|
|
|
}
|
2009-05-08 23:39:58 +08:00
|
|
|
ReceiverClass = CGF.Builder.CreateCall(classLookupFunction,
|
|
|
|
MakeConstantString(Class->getNameAsString()));
|
2009-05-04 23:31:17 +08:00
|
|
|
} else {
|
2009-05-08 23:39:58 +08:00
|
|
|
// Set up global aliases for the metaclass or class pointer if they do not
|
|
|
|
// already exist. These will are forward-references which will be set to
|
2009-08-01 05:31:32 +08:00
|
|
|
// pointers to the class and metaclass structure created for the runtime
|
|
|
|
// load function. To send a message to super, we look up the value of the
|
2009-05-08 23:39:58 +08:00
|
|
|
// super_class pointer from either the class or metaclass structure.
|
|
|
|
if (IsClassMessage) {
|
|
|
|
if (!MetaClassPtrAlias) {
|
|
|
|
MetaClassPtrAlias = new llvm::GlobalAlias(IdTy,
|
|
|
|
llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" +
|
|
|
|
Class->getNameAsString(), NULL, &TheModule);
|
|
|
|
}
|
|
|
|
ReceiverClass = MetaClassPtrAlias;
|
|
|
|
} else {
|
|
|
|
if (!ClassPtrAlias) {
|
|
|
|
ClassPtrAlias = new llvm::GlobalAlias(IdTy,
|
|
|
|
llvm::GlobalValue::InternalLinkage, ".objc_class_ref" +
|
|
|
|
Class->getNameAsString(), NULL, &TheModule);
|
|
|
|
}
|
|
|
|
ReceiverClass = ClassPtrAlias;
|
2009-05-04 23:31:17 +08:00
|
|
|
}
|
2009-04-26 07:19:45 +08:00
|
|
|
}
|
2009-05-04 23:31:17 +08:00
|
|
|
// Cast the pointer to a simplified version of the class structure
|
2009-09-09 23:08:12 +08:00
|
|
|
ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass,
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType::get(VMContext, IdTy, IdTy, NULL)));
|
2009-05-04 23:31:17 +08:00
|
|
|
// Get the superclass pointer
|
|
|
|
ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1);
|
|
|
|
// Load the superclass pointer
|
|
|
|
ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass);
|
2008-06-01 22:13:53 +08:00
|
|
|
// Construct the structure used to look up the IMP
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext,
|
|
|
|
Receiver->getType(), IdTy, NULL);
|
2008-08-23 11:46:30 +08:00
|
|
|
llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy);
|
2009-02-05 04:31:19 +08:00
|
|
|
|
2008-08-23 11:46:30 +08:00
|
|
|
CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0));
|
2009-05-04 23:31:17 +08:00
|
|
|
CGF.Builder.CreateStore(ReceiverClass,
|
|
|
|
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
// Get the IMP
|
2009-03-31 02:02:14 +08:00
|
|
|
std::vector<const llvm::Type*> Params;
|
2009-07-30 06:16:19 +08:00
|
|
|
Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
|
2009-03-31 02:02:14 +08:00
|
|
|
Params.push_back(SelectorTy);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Constant *lookupFunction =
|
2009-07-30 06:16:19 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
|
|
|
llvm::PointerType::getUnqual(impType), Params, true),
|
2009-03-31 02:02:14 +08:00
|
|
|
"objc_msg_lookup_super");
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
|
2008-08-23 11:46:30 +08:00
|
|
|
llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs,
|
2008-06-01 22:13:53 +08:00
|
|
|
lookupArgs+2);
|
|
|
|
|
2009-12-25 03:25:24 +08:00
|
|
|
return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Generate code for a message send expression.
|
2008-08-23 11:46:30 +08:00
|
|
|
CodeGen::RValue
|
|
|
|
CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
|
2008-08-30 13:35:15 +08:00
|
|
|
QualType ResultType,
|
|
|
|
Selector Sel,
|
2008-08-25 16:19:24 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-08-30 11:02:31 +08:00
|
|
|
bool IsClassMessage,
|
2009-05-06 05:36:57 +08:00
|
|
|
const CallArgList &CallArgs,
|
|
|
|
const ObjCMethodDecl *Method) {
|
2009-09-11 05:48:21 +08:00
|
|
|
CGBuilderTy &Builder = CGF.Builder;
|
2009-08-18 00:35:33 +08:00
|
|
|
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
|
2009-05-06 05:36:57 +08:00
|
|
|
llvm::Value *cmd;
|
|
|
|
if (Method)
|
2009-09-11 05:48:21 +08:00
|
|
|
cmd = GetSelector(Builder, Method);
|
2009-05-06 05:36:57 +08:00
|
|
|
else
|
2009-09-11 05:48:21 +08:00
|
|
|
cmd = GetSelector(Builder, Sel);
|
2009-02-05 04:31:19 +08:00
|
|
|
CallArgList ActualArgs;
|
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
Receiver = Builder.CreateBitCast(Receiver, IdTy);
|
2009-02-05 04:31:19 +08:00
|
|
|
ActualArgs.push_back(
|
2009-09-11 05:48:21 +08:00
|
|
|
std::make_pair(RValue::get(Receiver), ASTIdTy));
|
2009-02-05 04:31:19 +08:00
|
|
|
ActualArgs.push_back(std::make_pair(RValue::get(cmd),
|
|
|
|
CGF.getContext().getObjCSelType()));
|
|
|
|
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
|
|
|
|
|
|
|
|
CodeGenTypes &Types = CGM.getTypes();
|
|
|
|
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
|
2009-09-17 12:01:40 +08:00
|
|
|
const llvm::FunctionType *impType =
|
|
|
|
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
|
2008-03-01 16:50:34 +08:00
|
|
|
|
2009-05-23 04:17:16 +08:00
|
|
|
llvm::Value *imp;
|
|
|
|
// For sender-aware dispatch, we pass the sender as the third argument to a
|
|
|
|
// lookup function. When sending messages from C code, the sender is nil.
|
2009-09-11 05:48:21 +08:00
|
|
|
// objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
|
|
|
|
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
|
|
|
|
|
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType());
|
|
|
|
Builder.CreateStore(Receiver, ReceiverPtr);
|
|
|
|
Params.push_back(ReceiverPtr->getType());
|
|
|
|
Params.push_back(SelectorTy);
|
2009-05-23 04:17:16 +08:00
|
|
|
llvm::Value *self;
|
|
|
|
|
|
|
|
if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) {
|
|
|
|
self = CGF.LoadObjCSelf();
|
|
|
|
} else {
|
2009-07-31 07:11:26 +08:00
|
|
|
self = llvm::ConstantPointerNull::get(IdTy);
|
2009-05-23 04:17:16 +08:00
|
|
|
}
|
2009-09-11 05:48:21 +08:00
|
|
|
|
2009-05-23 04:17:16 +08:00
|
|
|
Params.push_back(self->getType());
|
2009-09-11 05:48:21 +08:00
|
|
|
|
|
|
|
// The lookup function returns a slot, which can be safely cached.
|
|
|
|
llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
|
|
|
|
IntTy, llvm::PointerType::getUnqual(impType), NULL);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Constant *lookupFunction =
|
2009-07-30 06:16:19 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::PointerType::getUnqual(SlotTy), Params, true),
|
2009-05-23 04:17:16 +08:00
|
|
|
"objc_msg_lookup_sender");
|
2009-03-31 02:02:14 +08:00
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
// The lookup function is guaranteed not to capture the receiver pointer.
|
|
|
|
if (llvm::Function *LookupFn = dyn_cast<llvm::Function>(lookupFunction)) {
|
|
|
|
LookupFn->setDoesNotCapture(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Value *slot =
|
|
|
|
Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self);
|
|
|
|
imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
|
|
|
|
// The lookup function may have changed the receiver, so make sure we use
|
|
|
|
// the new one.
|
|
|
|
ActualArgs[0] =
|
|
|
|
std::make_pair(RValue::get(Builder.CreateLoad(ReceiverPtr)), ASTIdTy);
|
2009-05-23 04:17:16 +08:00
|
|
|
} else {
|
2009-09-11 05:48:21 +08:00
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
Params.push_back(Receiver->getType());
|
|
|
|
Params.push_back(SelectorTy);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Constant *lookupFunction =
|
2009-07-30 06:16:19 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
|
|
|
llvm::PointerType::getUnqual(impType), Params, true),
|
2009-05-23 04:17:16 +08:00
|
|
|
"objc_msg_lookup");
|
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
|
2009-05-23 04:17:16 +08:00
|
|
|
}
|
2008-05-06 08:56:42 +08:00
|
|
|
|
2009-12-25 03:25:24 +08:00
|
|
|
return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Generates a MethodList. Used in construction of a objc_class and
|
2008-06-01 22:13:53 +08:00
|
|
|
/// objc_category structures.
|
|
|
|
llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
|
2009-09-09 23:08:12 +08:00
|
|
|
const std::string &CategoryName,
|
|
|
|
const llvm::SmallVectorImpl<Selector> &MethodSels,
|
|
|
|
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
|
2008-06-01 22:13:53 +08:00
|
|
|
bool isClassMethodList) {
|
2009-08-18 00:35:33 +08:00
|
|
|
if (MethodSels.empty())
|
|
|
|
return NULLPtr;
|
2009-09-09 23:08:12 +08:00
|
|
|
// Get the method structure type.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrToInt8Ty, // Really a selector, but the runtime creates it us.
|
|
|
|
PtrToInt8Ty, // Method types
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(IMPTy), //Method pointer
|
2008-06-01 22:13:53 +08:00
|
|
|
NULL);
|
|
|
|
std::vector<llvm::Constant*> Methods;
|
|
|
|
std::vector<llvm::Constant*> Elements;
|
|
|
|
for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
|
|
|
|
Elements.clear();
|
2009-05-18 00:49:27 +08:00
|
|
|
if (llvm::Constant *Method =
|
2008-06-01 22:13:53 +08:00
|
|
|
TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
|
2008-11-24 11:33:13 +08:00
|
|
|
MethodSels[i].getAsString(),
|
2009-05-18 00:49:27 +08:00
|
|
|
isClassMethodList))) {
|
2009-09-01 00:41:57 +08:00
|
|
|
llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString());
|
|
|
|
Elements.push_back(C);
|
|
|
|
Elements.push_back(MethodTypes[i]);
|
2009-07-30 02:54:39 +08:00
|
|
|
Method = llvm::ConstantExpr::getBitCast(Method,
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(IMPTy));
|
2009-05-18 00:49:27 +08:00
|
|
|
Elements.push_back(Method);
|
2009-07-28 06:29:56 +08:00
|
|
|
Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
|
2009-05-18 00:49:27 +08:00
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Array of method structures
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy,
|
2009-05-18 00:49:27 +08:00
|
|
|
Methods.size());
|
2009-07-29 02:33:04 +08:00
|
|
|
llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy,
|
2008-06-26 12:52:29 +08:00
|
|
|
Methods);
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
// Structure containing list pointer, array and array count
|
|
|
|
llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
|
2009-08-14 07:27:53 +08:00
|
|
|
llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get(VMContext);
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCMethodListTy = llvm::StructType::get(VMContext,
|
2009-09-09 23:08:12 +08:00
|
|
|
NextPtrTy,
|
|
|
|
IntTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
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();
|
2009-07-31 07:11:26 +08:00
|
|
|
Methods.push_back(llvm::ConstantPointerNull::get(
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(ObjCMethodListTy)));
|
2009-08-14 05:57:51 +08:00
|
|
|
Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
|
2008-06-01 22:13:53 +08:00
|
|
|
MethodTypes.size()));
|
|
|
|
Methods.push_back(MethodArray);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// 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) {
|
2009-11-17 03:05:54 +08:00
|
|
|
if (IvarNames.size() == 0)
|
|
|
|
return NULLPtr;
|
2009-09-09 23:08:12 +08:00
|
|
|
// Get the method structure type.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
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();
|
2009-09-01 00:41:57 +08:00
|
|
|
Elements.push_back(IvarNames[i]);
|
|
|
|
Elements.push_back(IvarTypes[i]);
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(IvarOffsets[i]);
|
2009-07-28 06:29:56 +08:00
|
|
|
Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements));
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Array of method structures
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
IvarNames.size());
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.clear();
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(IntTy, (int)IvarNames.size()));
|
2009-07-29 02:33:04 +08:00
|
|
|
Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars));
|
2008-06-01 22:13:53 +08:00
|
|
|
// Structure containing array and array count
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCIvarListTy = llvm::StructType::get(VMContext, IntTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
ObjCIvarArrayTy,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
// Create an instance of the structure
|
|
|
|
return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list");
|
2008-03-01 16:50:34 +08:00
|
|
|
}
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
/// Generate a class structure
|
|
|
|
llvm::Constant *CGObjCGNU::GenerateClassStructure(
|
|
|
|
llvm::Constant *MetaClass,
|
|
|
|
llvm::Constant *SuperClass,
|
|
|
|
unsigned info,
|
2008-06-26 12:47:04 +08:00
|
|
|
const char *Name,
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *Version,
|
|
|
|
llvm::Constant *InstanceSize,
|
|
|
|
llvm::Constant *IVars,
|
|
|
|
llvm::Constant *Methods,
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *Protocols,
|
|
|
|
llvm::Constant *IvarOffsets,
|
|
|
|
llvm::Constant *Properties) {
|
2008-06-01 22:13:53 +08:00
|
|
|
// 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.
|
2009-09-11 05:48:21 +08:00
|
|
|
//
|
|
|
|
// Fields marked New ABI are part of the GNUstep runtime. We emit them
|
|
|
|
// anyway; the classes will still work with the GNU runtime, they will just
|
|
|
|
// be ignored.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ClassTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrToInt8Ty, // class_pointer
|
|
|
|
PtrToInt8Ty, // super_class
|
|
|
|
PtrToInt8Ty, // name
|
|
|
|
LongTy, // version
|
|
|
|
LongTy, // info
|
|
|
|
LongTy, // instance_size
|
|
|
|
IVars->getType(), // ivars
|
|
|
|
Methods->getType(), // methods
|
2009-09-09 23:08:12 +08:00
|
|
|
// These are all filled in by the runtime, so we pretend
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrTy, // dtable
|
|
|
|
PtrTy, // subclass_list
|
|
|
|
PtrTy, // sibling_class
|
|
|
|
PtrTy, // protocols
|
|
|
|
PtrTy, // gc_object_type
|
2009-09-11 05:48:21 +08:00
|
|
|
// New ABI:
|
|
|
|
LongTy, // abi_version
|
|
|
|
IvarOffsets->getType(), // ivar_offsets
|
|
|
|
Properties->getType(), // properties
|
2008-06-01 22:13:53 +08:00
|
|
|
NULL);
|
2009-07-25 07:12:58 +08:00
|
|
|
llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
|
2008-06-01 22:13:53 +08:00
|
|
|
// Fill in the structure
|
|
|
|
std::vector<llvm::Constant*> Elements;
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(SuperClass);
|
2008-06-26 12:47:04 +08:00
|
|
|
Elements.push_back(MakeConstantString(Name, ".class_name"));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(Zero);
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy, info));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(InstanceSize);
|
|
|
|
Elements.push_back(IVars);
|
|
|
|
Elements.push_back(Methods);
|
2009-09-11 05:48:21 +08:00
|
|
|
Elements.push_back(NULLPtr);
|
|
|
|
Elements.push_back(NULLPtr);
|
|
|
|
Elements.push_back(NULLPtr);
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
|
2009-09-11 05:48:21 +08:00
|
|
|
Elements.push_back(NULLPtr);
|
|
|
|
Elements.push_back(Zero);
|
|
|
|
Elements.push_back(IvarOffsets);
|
|
|
|
Elements.push_back(Properties);
|
2008-06-01 22:13:53 +08:00
|
|
|
// Create an instance of the structure
|
2010-01-08 08:14:31 +08:00
|
|
|
// This is now an externally visible symbol, so that we can speed up class
|
|
|
|
// messages in the next ABI.
|
|
|
|
return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name),
|
|
|
|
llvm::GlobalValue::ExternalLinkage);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
|
|
|
|
const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
|
|
|
|
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Get the method structure type.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
Elements.push_back(MethodNames[i]);
|
2009-09-01 00:41:57 +08:00
|
|
|
Elements.push_back(MethodTypes[i]);
|
2009-07-28 06:29:56 +08:00
|
|
|
Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements));
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
MethodNames.size());
|
2009-07-29 02:33:04 +08:00
|
|
|
llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy,
|
2009-08-01 05:31:32 +08:00
|
|
|
Methods);
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
IntTy, ObjCMethodArrayTy, NULL);
|
|
|
|
Methods.clear();
|
2009-07-25 07:12:58 +08:00
|
|
|
Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
|
2008-06-01 22:13:53 +08:00
|
|
|
Methods.push_back(Array);
|
|
|
|
return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list");
|
|
|
|
}
|
2009-08-01 05:31:32 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// Create the protocol list structure used in classes, categories and so on
|
|
|
|
llvm::Constant *CGObjCGNU::GenerateProtocolList(
|
|
|
|
const llvm::SmallVectorImpl<std::string> &Protocols) {
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
|
2008-06-01 22:13:53 +08:00
|
|
|
Protocols.size());
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
|
|
|
|
LongTy,//FIXME: Should be size_t
|
|
|
|
ProtocolArrayTy,
|
|
|
|
NULL);
|
2009-09-09 23:08:12 +08:00
|
|
|
std::vector<llvm::Constant*> Elements;
|
2008-06-01 22:13:53 +08:00
|
|
|
for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
|
|
|
|
iter != endIter ; iter++) {
|
2009-11-20 22:50:59 +08:00
|
|
|
llvm::Constant *protocol = 0;
|
|
|
|
llvm::StringMap<llvm::Constant*>::iterator value =
|
|
|
|
ExistingProtocols.find(*iter);
|
|
|
|
if (value == ExistingProtocols.end()) {
|
2009-04-01 02:27:22 +08:00
|
|
|
protocol = GenerateEmptyProtocol(*iter);
|
2009-11-20 22:50:59 +08:00
|
|
|
} else {
|
|
|
|
protocol = value->getValue();
|
|
|
|
}
|
2009-07-30 02:54:39 +08:00
|
|
|
llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol,
|
2009-07-15 07:10:40 +08:00
|
|
|
PtrToInt8Ty);
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(Ptr);
|
|
|
|
}
|
2009-07-29 02:33:04 +08:00
|
|
|
llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements);
|
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(NULLPtr);
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy, Protocols.size()));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(ProtocolArray);
|
|
|
|
return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
|
2008-08-13 08:59:25 +08:00
|
|
|
const ObjCProtocolDecl *PD) {
|
2009-04-01 02:27:22 +08:00
|
|
|
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
|
2009-09-09 23:08:12 +08:00
|
|
|
const llvm::Type *T =
|
2009-04-01 02:27:22 +08:00
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
|
2009-07-30 06:16:19 +08:00
|
|
|
return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
|
2009-04-01 02:27:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
|
|
|
|
const std::string &ProtocolName) {
|
|
|
|
llvm::SmallVector<std::string, 0> EmptyStringVector;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 0> EmptyConstantVector;
|
|
|
|
|
|
|
|
llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector);
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *MethodList =
|
2009-04-01 02:27:22 +08:00
|
|
|
GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
|
|
|
|
// Protocols are objects containing lists of the methods implemented and
|
|
|
|
// protocols adopted.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
|
2009-04-01 02:27:22 +08:00
|
|
|
PtrToInt8Ty,
|
|
|
|
ProtocolList->getType(),
|
2009-09-11 05:48:21 +08:00
|
|
|
MethodList->getType(),
|
|
|
|
MethodList->getType(),
|
|
|
|
MethodList->getType(),
|
|
|
|
MethodList->getType(),
|
2009-04-01 02:27:22 +08:00
|
|
|
NULL);
|
2009-09-09 23:08:12 +08:00
|
|
|
std::vector<llvm::Constant*> Elements;
|
2009-04-01 02:27:22 +08:00
|
|
|
// The isa pointer must be set to a magic number so the runtime knows it's
|
|
|
|
// the correct layout.
|
2009-09-11 05:48:21 +08:00
|
|
|
int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
|
|
|
|
NonFragileProtocolVersion : ProtocolVersion;
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
|
2009-04-01 02:27:22 +08:00
|
|
|
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
|
|
|
|
Elements.push_back(ProtocolList);
|
2009-09-11 05:48:21 +08:00
|
|
|
Elements.push_back(MethodList);
|
|
|
|
Elements.push_back(MethodList);
|
|
|
|
Elements.push_back(MethodList);
|
|
|
|
Elements.push_back(MethodList);
|
2009-04-01 02:27:22 +08:00
|
|
|
return MakeGlobal(ProtocolTy, Elements, ".objc_protocol");
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
|
2008-08-13 08:59:25 +08:00
|
|
|
void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
|
|
|
|
ASTContext &Context = CGM.getContext();
|
2008-11-24 11:54:41 +08:00
|
|
|
std::string ProtocolName = PD->getNameAsString();
|
2008-08-13 08:59:25 +08:00
|
|
|
llvm::SmallVector<std::string, 16> Protocols;
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
|
|
|
|
E = PD->protocol_end(); PI != E; ++PI)
|
2008-11-24 13:29:24 +08:00
|
|
|
Protocols.push_back((*PI)->getNameAsString());
|
2008-08-13 08:59:25 +08:00
|
|
|
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(),
|
|
|
|
E = PD->instmeth_end(); iter != E; iter++) {
|
2008-08-13 08:59:25 +08:00
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
|
2009-09-11 05:48:21 +08:00
|
|
|
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
|
|
|
|
InstanceMethodNames.push_back(
|
|
|
|
MakeConstantString((*iter)->getSelector().getAsString()));
|
|
|
|
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
|
|
|
|
} else {
|
|
|
|
OptionalInstanceMethodNames.push_back(
|
|
|
|
MakeConstantString((*iter)->getSelector().getAsString()));
|
|
|
|
OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
|
|
|
|
}
|
2008-08-13 08:59:25 +08:00
|
|
|
}
|
|
|
|
// Collect information about class methods:
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (ObjCProtocolDecl::classmeth_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
iter = PD->classmeth_begin(), endIter = PD->classmeth_end();
|
|
|
|
iter != endIter ; iter++) {
|
2008-08-13 08:59:25 +08:00
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
|
2009-09-11 05:48:21 +08:00
|
|
|
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
|
|
|
|
ClassMethodNames.push_back(
|
|
|
|
MakeConstantString((*iter)->getSelector().getAsString()));
|
|
|
|
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
|
|
|
|
} else {
|
|
|
|
OptionalClassMethodNames.push_back(
|
|
|
|
MakeConstantString((*iter)->getSelector().getAsString()));
|
|
|
|
OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
|
|
|
|
}
|
2008-08-13 08:59:25 +08:00
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
|
|
|
|
llvm::Constant *InstanceMethodList =
|
|
|
|
GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes);
|
|
|
|
llvm::Constant *ClassMethodList =
|
|
|
|
GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *OptionalInstanceMethodList =
|
|
|
|
GenerateProtocolMethodList(OptionalInstanceMethodNames,
|
|
|
|
OptionalInstanceMethodTypes);
|
|
|
|
llvm::Constant *OptionalClassMethodList =
|
|
|
|
GenerateProtocolMethodList(OptionalClassMethodNames,
|
|
|
|
OptionalClassMethodTypes);
|
|
|
|
|
|
|
|
// Property metadata: name, attributes, isSynthesized, setter name, setter
|
|
|
|
// types, getter name, getter types.
|
|
|
|
// The isSynthesized value is always set to 0 in a protocol. It exists to
|
|
|
|
// simplify the runtime library by allowing it to use the same data
|
|
|
|
// structures for protocol metadata everywhere.
|
|
|
|
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
|
|
|
|
PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
|
|
|
|
PtrToInt8Ty, NULL);
|
|
|
|
std::vector<llvm::Constant*> Properties;
|
|
|
|
std::vector<llvm::Constant*> OptionalProperties;
|
|
|
|
|
|
|
|
// Add all of the property methods need adding to the method list and to the
|
|
|
|
// property metadata list.
|
|
|
|
for (ObjCContainerDecl::prop_iterator
|
|
|
|
iter = PD->prop_begin(), endIter = PD->prop_end();
|
|
|
|
iter != endIter ; iter++) {
|
|
|
|
std::vector<llvm::Constant*> Fields;
|
|
|
|
ObjCPropertyDecl *property = (*iter);
|
|
|
|
|
|
|
|
Fields.push_back(MakeConstantString(property->getNameAsString()));
|
|
|
|
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
|
|
|
|
property->getPropertyAttributes()));
|
|
|
|
Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
|
|
|
|
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
|
|
|
|
llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
|
|
|
|
InstanceMethodTypes.push_back(TypeEncoding);
|
|
|
|
Fields.push_back(MakeConstantString(getter->getSelector().getAsString()));
|
|
|
|
Fields.push_back(TypeEncoding);
|
|
|
|
} else {
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
}
|
|
|
|
if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl(setter,TypeStr);
|
|
|
|
llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
|
|
|
|
InstanceMethodTypes.push_back(TypeEncoding);
|
|
|
|
Fields.push_back(MakeConstantString(setter->getSelector().getAsString()));
|
|
|
|
Fields.push_back(TypeEncoding);
|
|
|
|
} else {
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
}
|
|
|
|
if (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) {
|
|
|
|
OptionalProperties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
|
|
|
|
} else {
|
|
|
|
Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm::Constant *PropertyArray = llvm::ConstantArray::get(
|
|
|
|
llvm::ArrayType::get(PropertyMetadataTy, Properties.size()), Properties);
|
|
|
|
llvm::Constant* PropertyListInitFields[] =
|
|
|
|
{llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
|
|
|
|
|
|
|
|
llvm::Constant *PropertyListInit =
|
2009-09-20 04:00:52 +08:00
|
|
|
llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule,
|
|
|
|
PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage,
|
|
|
|
PropertyListInit, ".objc_property_list");
|
|
|
|
|
|
|
|
llvm::Constant *OptionalPropertyArray =
|
|
|
|
llvm::ConstantArray::get(llvm::ArrayType::get(PropertyMetadataTy,
|
|
|
|
OptionalProperties.size()) , OptionalProperties);
|
|
|
|
llvm::Constant* OptionalPropertyListInitFields[] = {
|
|
|
|
llvm::ConstantInt::get(IntTy, OptionalProperties.size()), NULLPtr,
|
|
|
|
OptionalPropertyArray };
|
|
|
|
|
|
|
|
llvm::Constant *OptionalPropertyListInit =
|
2009-09-20 04:00:52 +08:00
|
|
|
llvm::ConstantStruct::get(VMContext, OptionalPropertyListInitFields, 3, false);
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule,
|
|
|
|
OptionalPropertyListInit->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit,
|
|
|
|
".objc_property_list");
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// Protocols are objects containing lists of the methods implemented and
|
|
|
|
// protocols adopted.
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy,
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrToInt8Ty,
|
|
|
|
ProtocolList->getType(),
|
|
|
|
InstanceMethodList->getType(),
|
|
|
|
ClassMethodList->getType(),
|
2009-09-11 05:48:21 +08:00
|
|
|
OptionalInstanceMethodList->getType(),
|
|
|
|
OptionalClassMethodList->getType(),
|
|
|
|
PropertyList->getType(),
|
|
|
|
OptionalPropertyList->getType(),
|
2008-06-01 22:13:53 +08:00
|
|
|
NULL);
|
2009-09-09 23:08:12 +08:00
|
|
|
std::vector<llvm::Constant*> Elements;
|
2008-06-01 22:13:53 +08:00
|
|
|
// The isa pointer must be set to a magic number so the runtime knows it's
|
|
|
|
// the correct layout.
|
2009-09-11 05:48:21 +08:00
|
|
|
int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
|
|
|
|
NonFragileProtocolVersion : ProtocolVersion;
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
|
|
|
|
Elements.push_back(ProtocolList);
|
|
|
|
Elements.push_back(InstanceMethodList);
|
|
|
|
Elements.push_back(ClassMethodList);
|
2009-09-11 05:48:21 +08:00
|
|
|
Elements.push_back(OptionalInstanceMethodList);
|
|
|
|
Elements.push_back(OptionalClassMethodList);
|
|
|
|
Elements.push_back(PropertyList);
|
|
|
|
Elements.push_back(OptionalPropertyList);
|
2009-09-09 23:08:12 +08:00
|
|
|
ExistingProtocols[ProtocolName] =
|
2009-07-30 02:54:39 +08:00
|
|
|
llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
|
2008-06-01 22:13:53 +08:00
|
|
|
".objc_protocol"), IdTy);
|
|
|
|
}
|
2009-09-11 05:48:21 +08:00
|
|
|
void CGObjCGNU::GenerateProtocolHolderCategory(void) {
|
|
|
|
// Collect information about instance methods
|
|
|
|
llvm::SmallVector<Selector, 1> MethodSels;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 1> MethodTypes;
|
|
|
|
|
|
|
|
std::vector<llvm::Constant*> Elements;
|
|
|
|
const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack";
|
|
|
|
const std::string CategoryName = "AnotherHack";
|
|
|
|
Elements.push_back(MakeConstantString(CategoryName));
|
|
|
|
Elements.push_back(MakeConstantString(ClassName));
|
|
|
|
// Instance method list
|
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
|
|
|
|
ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy));
|
|
|
|
// Class method list
|
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
|
|
|
|
ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy));
|
|
|
|
// Protocol list
|
|
|
|
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy,
|
|
|
|
ExistingProtocols.size());
|
|
|
|
llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext,
|
|
|
|
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
|
|
|
|
LongTy,//FIXME: Should be size_t
|
|
|
|
ProtocolArrayTy,
|
|
|
|
NULL);
|
|
|
|
std::vector<llvm::Constant*> ProtocolElements;
|
|
|
|
for (llvm::StringMapIterator<llvm::Constant*> iter =
|
|
|
|
ExistingProtocols.begin(), endIter = ExistingProtocols.end();
|
|
|
|
iter != endIter ; iter++) {
|
|
|
|
llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(iter->getValue(),
|
|
|
|
PtrTy);
|
|
|
|
ProtocolElements.push_back(Ptr);
|
|
|
|
}
|
|
|
|
llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
|
|
|
|
ProtocolElements);
|
|
|
|
ProtocolElements.clear();
|
|
|
|
ProtocolElements.push_back(NULLPtr);
|
|
|
|
ProtocolElements.push_back(llvm::ConstantInt::get(LongTy,
|
|
|
|
ExistingProtocols.size()));
|
|
|
|
ProtocolElements.push_back(ProtocolArray);
|
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy,
|
|
|
|
ProtocolElements, ".objc_protocol_list"), PtrTy));
|
|
|
|
Categories.push_back(llvm::ConstantExpr::getBitCast(
|
|
|
|
MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
|
|
|
|
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
|
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
|
2008-08-16 06:20:32 +08:00
|
|
|
void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
|
2008-11-24 11:54:41 +08:00
|
|
|
std::string ClassName = OCD->getClassInterface()->getNameAsString();
|
|
|
|
std::string CategoryName = OCD->getNameAsString();
|
2008-08-16 06:20:32 +08:00
|
|
|
// Collect information about instance methods
|
|
|
|
llvm::SmallVector<Selector, 16> InstanceMethodSels;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
|
2009-04-23 09:02:12 +08:00
|
|
|
for (ObjCCategoryImplDecl::instmeth_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
iter = OCD->instmeth_begin(), endIter = OCD->instmeth_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
iter != endIter ; iter++) {
|
2008-08-16 06:20:32 +08:00
|
|
|
InstanceMethodSels.push_back((*iter)->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
|
2009-09-01 00:41:57 +08:00
|
|
|
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
|
2008-08-16 06:20:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Collect information about class methods
|
|
|
|
llvm::SmallVector<Selector, 16> ClassMethodSels;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (ObjCCategoryImplDecl::classmeth_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
iter != endIter ; iter++) {
|
2008-08-16 06:20:32 +08:00
|
|
|
ClassMethodSels.push_back((*iter)->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
|
2009-09-01 00:41:57 +08:00
|
|
|
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
|
2008-08-16 06:20:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Collect the names of referenced protocols
|
|
|
|
llvm::SmallVector<std::string, 16> Protocols;
|
|
|
|
const ObjCInterfaceDecl *ClassDecl = OCD->getClassInterface();
|
|
|
|
const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
|
|
|
|
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
|
|
|
|
E = Protos.end(); I != E; ++I)
|
2008-11-24 13:29:24 +08:00
|
|
|
Protocols.push_back((*I)->getNameAsString());
|
2008-08-16 06:20:32 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
std::vector<llvm::Constant*> Elements;
|
|
|
|
Elements.push_back(MakeConstantString(CategoryName));
|
|
|
|
Elements.push_back(MakeConstantString(ClassName));
|
2009-09-09 23:08:12 +08:00
|
|
|
// Instance method list
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
|
2008-06-26 13:08:00 +08:00
|
|
|
ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes,
|
2008-06-01 22:13:53 +08:00
|
|
|
false), PtrTy));
|
|
|
|
// Class method list
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
|
2008-06-26 13:08:00 +08:00
|
|
|
ClassName, CategoryName, ClassMethodSels, ClassMethodTypes, true),
|
2008-06-01 22:13:53 +08:00
|
|
|
PtrTy));
|
|
|
|
// Protocol list
|
2009-07-30 02:54:39 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(
|
2008-06-01 22:13:53 +08:00
|
|
|
GenerateProtocolList(Protocols), PtrTy));
|
2009-07-30 02:54:39 +08:00
|
|
|
Categories.push_back(llvm::ConstantExpr::getBitCast(
|
2009-09-09 23:08:12 +08:00
|
|
|
MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
|
2009-08-06 07:18:46 +08:00
|
|
|
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
2008-08-16 06:20:32 +08:00
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID,
|
|
|
|
llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
|
|
|
|
llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
|
|
|
|
ASTContext &Context = CGM.getContext();
|
|
|
|
//
|
|
|
|
// Property metadata: name, attributes, isSynthesized, setter name, setter
|
|
|
|
// types, getter name, getter types.
|
|
|
|
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext,
|
|
|
|
PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
|
|
|
|
PtrToInt8Ty, NULL);
|
|
|
|
std::vector<llvm::Constant*> Properties;
|
|
|
|
|
|
|
|
|
|
|
|
// Add all of the property methods need adding to the method list and to the
|
|
|
|
// property metadata list.
|
|
|
|
for (ObjCImplDecl::propimpl_iterator
|
|
|
|
iter = OID->propimpl_begin(), endIter = OID->propimpl_end();
|
|
|
|
iter != endIter ; iter++) {
|
|
|
|
std::vector<llvm::Constant*> Fields;
|
|
|
|
ObjCPropertyDecl *property = (*iter)->getPropertyDecl();
|
|
|
|
|
|
|
|
Fields.push_back(MakeConstantString(property->getNameAsString()));
|
|
|
|
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
|
|
|
|
property->getPropertyAttributes()));
|
|
|
|
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
|
|
|
|
(*iter)->getPropertyImplementation() ==
|
|
|
|
ObjCPropertyImplDecl::Synthesize));
|
|
|
|
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
|
|
|
|
InstanceMethodSels.push_back(getter->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
|
|
|
|
llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
|
|
|
|
InstanceMethodTypes.push_back(TypeEncoding);
|
|
|
|
Fields.push_back(MakeConstantString(getter->getSelector().getAsString()));
|
|
|
|
Fields.push_back(TypeEncoding);
|
|
|
|
} else {
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
}
|
|
|
|
if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
|
|
|
|
InstanceMethodSels.push_back(setter->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl(setter,TypeStr);
|
|
|
|
llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
|
|
|
|
InstanceMethodTypes.push_back(TypeEncoding);
|
|
|
|
Fields.push_back(MakeConstantString(setter->getSelector().getAsString()));
|
|
|
|
Fields.push_back(TypeEncoding);
|
|
|
|
} else {
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
Fields.push_back(NULLPtr);
|
|
|
|
}
|
|
|
|
Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields));
|
|
|
|
}
|
|
|
|
llvm::ArrayType *PropertyArrayTy =
|
|
|
|
llvm::ArrayType::get(PropertyMetadataTy, Properties.size());
|
|
|
|
llvm::Constant *PropertyArray = llvm::ConstantArray::get(PropertyArrayTy,
|
|
|
|
Properties);
|
|
|
|
llvm::Constant* PropertyListInitFields[] =
|
|
|
|
{llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray};
|
|
|
|
|
|
|
|
llvm::Constant *PropertyListInit =
|
2009-09-20 04:00:52 +08:00
|
|
|
llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false);
|
2009-09-11 05:48:21 +08:00
|
|
|
return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage, PropertyListInit,
|
|
|
|
".objc_property_list");
|
|
|
|
}
|
|
|
|
|
2008-08-16 06:20:32 +08:00
|
|
|
void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|
|
|
ASTContext &Context = CGM.getContext();
|
|
|
|
|
|
|
|
// Get the superclass name.
|
2009-09-09 23:08:12 +08:00
|
|
|
const ObjCInterfaceDecl * SuperClassDecl =
|
2008-08-16 06:20:32 +08:00
|
|
|
OID->getClassInterface()->getSuperClass();
|
2008-11-24 11:54:41 +08:00
|
|
|
std::string SuperClassName;
|
2009-06-15 09:09:11 +08:00
|
|
|
if (SuperClassDecl) {
|
2008-11-24 11:54:41 +08:00
|
|
|
SuperClassName = SuperClassDecl->getNameAsString();
|
2009-06-15 09:09:11 +08:00
|
|
|
EmitClassRef(SuperClassName);
|
|
|
|
}
|
2008-08-16 06:20:32 +08:00
|
|
|
|
|
|
|
// Get the class name
|
2009-04-01 10:00:48 +08:00
|
|
|
ObjCInterfaceDecl *ClassDecl =
|
|
|
|
const_cast<ObjCInterfaceDecl *>(OID->getClassInterface());
|
2008-11-24 11:54:41 +08:00
|
|
|
std::string ClassName = ClassDecl->getNameAsString();
|
2009-06-15 09:09:11 +08:00
|
|
|
// Emit the symbol that is used to generate linker errors if this class is
|
|
|
|
// referenced in other modules but not declared.
|
2009-07-03 23:10:14 +08:00
|
|
|
std::string classSymbolName = "__objc_class_name_" + ClassName;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (llvm::GlobalVariable *symbol =
|
2009-07-03 23:10:14 +08:00
|
|
|
TheModule.getGlobalVariable(classSymbolName)) {
|
2009-07-25 07:12:58 +08:00
|
|
|
symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0));
|
2009-07-03 23:10:14 +08:00
|
|
|
} else {
|
2009-07-09 03:05:04 +08:00
|
|
|
new llvm::GlobalVariable(TheModule, LongTy, false,
|
2009-07-25 07:12:58 +08:00
|
|
|
llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(LongTy, 0),
|
2009-07-09 03:05:04 +08:00
|
|
|
classSymbolName);
|
2009-07-03 23:10:14 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 18:46:44 +08:00
|
|
|
// Get the size of instances.
|
|
|
|
int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize() / 8;
|
2008-08-16 06:20:32 +08:00
|
|
|
|
|
|
|
// Collect information about instance variables.
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> IvarNames;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
std::vector<llvm::Constant*> IvarOffsetValues;
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
int superInstanceSize = !SuperClassDecl ? 0 :
|
2009-05-21 02:41:51 +08:00
|
|
|
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize() / 8;
|
|
|
|
// For non-fragile ivars, set the instance size to 0 - {the size of just this
|
|
|
|
// class}. The runtime will then set this to the correct value on load.
|
|
|
|
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
|
|
|
|
instanceSize = 0 - (instanceSize - superInstanceSize);
|
|
|
|
}
|
2008-08-16 06:20:32 +08:00
|
|
|
for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
|
|
|
|
endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
|
|
|
|
// Store the name
|
2009-09-01 00:41:57 +08:00
|
|
|
IvarNames.push_back(MakeConstantString((*iter)->getNameAsString()));
|
2008-08-16 06:20:32 +08:00
|
|
|
// Get the type encoding for this ivar
|
|
|
|
std::string TypeStr;
|
2008-10-18 04:21:44 +08:00
|
|
|
Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
|
2009-09-01 00:41:57 +08:00
|
|
|
IvarTypes.push_back(MakeConstantString(TypeStr));
|
2008-08-16 06:20:32 +08:00
|
|
|
// Get the offset
|
2009-09-11 05:48:21 +08:00
|
|
|
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
|
2009-11-18 03:32:15 +08:00
|
|
|
uint64_t Offset = BaseOffset;
|
2009-05-21 02:41:51 +08:00
|
|
|
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
|
2009-09-11 05:48:21 +08:00
|
|
|
Offset = BaseOffset - superInstanceSize;
|
2009-05-21 02:41:51 +08:00
|
|
|
}
|
2008-08-16 06:20:32 +08:00
|
|
|
IvarOffsets.push_back(
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset));
|
2009-09-11 05:48:21 +08:00
|
|
|
IvarOffsetValues.push_back(new llvm::GlobalVariable(TheModule, IntTy,
|
|
|
|
false, llvm::GlobalValue::ExternalLinkage,
|
|
|
|
llvm::ConstantInt::get(IntTy, BaseOffset),
|
|
|
|
"__objc_ivar_offset_value_" + ClassName +"." +
|
|
|
|
(*iter)->getNameAsString()));
|
2008-08-16 06:20:32 +08:00
|
|
|
}
|
2009-09-11 05:48:21 +08:00
|
|
|
llvm::Constant *IvarOffsetArrayInit =
|
|
|
|
llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy,
|
|
|
|
IvarOffsetValues.size()), IvarOffsetValues);
|
|
|
|
llvm::GlobalVariable *IvarOffsetArray = new llvm::GlobalVariable(TheModule,
|
|
|
|
IvarOffsetArrayInit->getType(), false,
|
|
|
|
llvm::GlobalValue::InternalLinkage, IvarOffsetArrayInit,
|
|
|
|
".ivar.offsets");
|
2008-08-16 06:20:32 +08:00
|
|
|
|
|
|
|
// Collect information about instance methods
|
|
|
|
llvm::SmallVector<Selector, 16> InstanceMethodSels;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (ObjCImplementationDecl::instmeth_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
iter = OID->instmeth_begin(), endIter = OID->instmeth_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
iter != endIter ; iter++) {
|
2008-08-16 06:20:32 +08:00
|
|
|
InstanceMethodSels.push_back((*iter)->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
|
2009-09-01 00:41:57 +08:00
|
|
|
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
|
2008-08-16 06:20:32 +08:00
|
|
|
}
|
2009-09-11 05:48:21 +08:00
|
|
|
|
|
|
|
llvm::Constant *Properties = GeneratePropertyList(OID, InstanceMethodSels,
|
|
|
|
InstanceMethodTypes);
|
|
|
|
|
2008-08-16 06:20:32 +08:00
|
|
|
|
|
|
|
// Collect information about class methods
|
|
|
|
llvm::SmallVector<Selector, 16> ClassMethodSels;
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
|
2009-04-23 09:02:12 +08:00
|
|
|
for (ObjCImplementationDecl::classmeth_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
iter = OID->classmeth_begin(), endIter = OID->classmeth_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
iter != endIter ; iter++) {
|
2008-08-16 06:20:32 +08:00
|
|
|
ClassMethodSels.push_back((*iter)->getSelector());
|
|
|
|
std::string TypeStr;
|
|
|
|
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
|
2009-09-01 00:41:57 +08:00
|
|
|
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
|
2008-08-16 06:20:32 +08:00
|
|
|
}
|
|
|
|
// Collect the names of referenced protocols
|
|
|
|
llvm::SmallVector<std::string, 16> Protocols;
|
|
|
|
const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
|
|
|
|
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
|
|
|
|
E = Protos.end(); I != E; ++I)
|
2008-11-24 13:29:24 +08:00
|
|
|
Protocols.push_back((*I)->getNameAsString());
|
2008-08-16 06:20:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// Get the superclass pointer.
|
|
|
|
llvm::Constant *SuperClass;
|
2008-11-24 11:54:41 +08:00
|
|
|
if (!SuperClassName.empty()) {
|
2008-06-01 22:13:53 +08:00
|
|
|
SuperClass = MakeConstantString(SuperClassName, ".super_class_name");
|
|
|
|
} else {
|
2009-07-31 07:11:26 +08:00
|
|
|
SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty);
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
// 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, "",
|
2008-06-26 13:08:00 +08:00
|
|
|
InstanceMethodSels, InstanceMethodTypes, false);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
|
2008-06-26 13:08:00 +08:00
|
|
|
ClassMethodSels, ClassMethodTypes, true);
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
|
|
|
|
IvarOffsets);
|
2009-09-09 23:08:12 +08:00
|
|
|
// Irrespective of whether we are compiling for a fragile or non-fragile ABI,
|
2009-09-01 00:41:57 +08:00
|
|
|
// we emit a symbol containing the offset for each ivar in the class. This
|
|
|
|
// allows code compiled for the non-Fragile ABI to inherit from code compiled
|
|
|
|
// for the legacy ABI, without causing problems. The converse is also
|
|
|
|
// possible, but causes all ivar accesses to be fragile.
|
|
|
|
int i = 0;
|
|
|
|
// Offset pointer for getting at the correct field in the ivar list when
|
|
|
|
// setting up the alias. These are: The base address for the global, the
|
|
|
|
// ivar array (second field), the ivar in this list (set for each ivar), and
|
|
|
|
// the offset (third field in ivar structure)
|
|
|
|
const llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext);
|
|
|
|
llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::ConstantInt::get(IndexTy, 1), 0,
|
2009-09-01 00:41:57 +08:00
|
|
|
llvm::ConstantInt::get(IndexTy, 2) };
|
|
|
|
|
|
|
|
for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
|
|
|
|
endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
|
|
|
|
const std::string Name = "__objc_ivar_offset_" + ClassName + '.'
|
|
|
|
+(*iter)->getNameAsString();
|
|
|
|
offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, i++);
|
|
|
|
// Get the correct ivar field
|
|
|
|
llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr(
|
|
|
|
IvarList, offsetPointerIndexes, 4);
|
|
|
|
// Get the existing alias, if one exists.
|
|
|
|
llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
|
|
|
|
if (offset) {
|
|
|
|
offset->setInitializer(offsetValue);
|
|
|
|
// If this is the real definition, change its linkage type so that
|
|
|
|
// different modules will use this one, rather than their private
|
|
|
|
// copy.
|
|
|
|
offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
|
|
|
|
} else {
|
|
|
|
// Add a new alias if there isn't one already.
|
|
|
|
offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
|
|
|
|
false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
|
|
|
|
}
|
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
//Generate metaclass for class methods
|
|
|
|
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
|
2009-11-17 03:05:54 +08:00
|
|
|
NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
|
2009-09-11 05:48:21 +08:00
|
|
|
empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
|
2009-05-04 23:31:17 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// Generate the class structure
|
2008-11-24 11:54:41 +08:00
|
|
|
llvm::Constant *ClassStruct =
|
2009-09-11 05:48:21 +08:00
|
|
|
GenerateClassStructure(MetaClassStruct, SuperClass, 0x11L,
|
2008-11-24 11:54:41 +08:00
|
|
|
ClassName.c_str(), 0,
|
2009-07-25 07:12:58 +08:00
|
|
|
llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
|
2009-09-11 05:48:21 +08:00
|
|
|
MethodList, GenerateProtocolList(Protocols), IvarOffsetArray,
|
|
|
|
Properties);
|
2009-05-04 23:31:17 +08:00
|
|
|
|
|
|
|
// Resolve the class aliases, if they exist.
|
|
|
|
if (ClassPtrAlias) {
|
|
|
|
ClassPtrAlias->setAliasee(
|
2009-07-30 02:54:39 +08:00
|
|
|
llvm::ConstantExpr::getBitCast(ClassStruct, IdTy));
|
2009-05-04 23:31:17 +08:00
|
|
|
ClassPtrAlias = 0;
|
|
|
|
}
|
|
|
|
if (MetaClassPtrAlias) {
|
|
|
|
MetaClassPtrAlias->setAliasee(
|
2009-07-30 02:54:39 +08:00
|
|
|
llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy));
|
2009-05-04 23:31:17 +08:00
|
|
|
MetaClassPtrAlias = 0;
|
|
|
|
}
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
// Add class structure to list to be added to the symtab later
|
2009-07-30 02:54:39 +08:00
|
|
|
ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty);
|
2008-06-01 22:13:53 +08:00
|
|
|
Classes.push_back(ClassStruct);
|
|
|
|
}
|
|
|
|
|
2009-06-24 05:47:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Function *CGObjCGNU::ModuleInitFunction() {
|
2008-06-01 22:13:53 +08:00
|
|
|
// 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() &&
|
2008-06-01 23:14:46 +08:00
|
|
|
UntypedSelectors.empty())
|
2008-06-01 22:13:53 +08:00
|
|
|
return NULL;
|
2008-06-02 00:00:02 +08:00
|
|
|
|
2009-09-11 05:48:21 +08:00
|
|
|
// Add all referenced protocols to a category.
|
|
|
|
GenerateProtocolHolderCategory();
|
|
|
|
|
2009-01-27 13:06:01 +08:00
|
|
|
const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
|
|
|
|
SelectorTy->getElementType());
|
|
|
|
const llvm::Type *SelStructPtrTy = SelectorTy;
|
|
|
|
bool isSelOpaque = false;
|
|
|
|
if (SelStructTy == 0) {
|
2009-08-06 07:18:46 +08:00
|
|
|
SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty,
|
|
|
|
PtrToInt8Ty, NULL);
|
2009-07-30 06:16:19 +08:00
|
|
|
SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
|
2009-01-27 13:06:01 +08:00
|
|
|
isSelOpaque = true;
|
|
|
|
}
|
|
|
|
|
2008-06-02 00:00:02 +08:00
|
|
|
// Name the ObjC types to make the IR a bit easier to read
|
2009-01-27 13:06:01 +08:00
|
|
|
TheModule.addTypeName(".objc_selector", SelStructPtrTy);
|
2008-06-02 00:00:02 +08:00
|
|
|
TheModule.addTypeName(".objc_id", IdTy);
|
|
|
|
TheModule.addTypeName(".objc_imp", IMPTy);
|
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
std::vector<llvm::Constant*> Elements;
|
2009-04-26 07:19:45 +08:00
|
|
|
llvm::Constant *Statics = NULLPtr;
|
2008-06-01 22:13:53 +08:00
|
|
|
// Generate statics list:
|
2009-04-26 07:19:45 +08:00
|
|
|
if (ConstantStrings.size()) {
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
|
2009-04-26 07:19:45 +08:00
|
|
|
ConstantStrings.size() + 1);
|
|
|
|
ConstantStrings.push_back(NULLPtr);
|
2009-09-01 00:41:57 +08:00
|
|
|
|
2009-11-29 10:38:47 +08:00
|
|
|
llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
|
|
|
|
if (StringClass.empty()) StringClass = "NXConstantString";
|
2009-09-01 00:41:57 +08:00
|
|
|
Elements.push_back(MakeConstantString(StringClass,
|
|
|
|
".objc_static_class_name"));
|
2009-07-29 02:33:04 +08:00
|
|
|
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
|
2009-04-26 07:19:45 +08:00
|
|
|
ConstantStrings));
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::StructType *StaticsListTy =
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType::get(VMContext, PtrToInt8Ty, StaticsArrayTy, NULL);
|
2009-07-15 07:10:40 +08:00
|
|
|
llvm::Type *StaticsListPtrTy =
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(StaticsListTy);
|
2009-04-26 07:19:45 +08:00
|
|
|
Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::ArrayType *StaticsListArrayTy =
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType::get(StaticsListPtrTy, 2);
|
2009-04-26 07:19:45 +08:00
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(Statics);
|
2009-08-01 04:28:54 +08:00
|
|
|
Elements.push_back(llvm::Constant::getNullValue(StaticsListPtrTy));
|
2009-04-26 07:19:45 +08:00
|
|
|
Statics = MakeGlobal(StaticsListArrayTy, Elements, ".objc_statics_ptr");
|
2009-07-30 02:54:39 +08:00
|
|
|
Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy);
|
2009-04-26 07:19:45 +08:00
|
|
|
}
|
2008-06-01 22:13:53 +08:00
|
|
|
// Array of classes, categories, and constant objects
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty,
|
2008-06-01 22:13:53 +08:00
|
|
|
Classes.size() + Categories.size() + 2);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::StructType *SymTabTy = llvm::StructType::get(VMContext,
|
2009-08-06 07:18:46 +08:00
|
|
|
LongTy, SelStructPtrTy,
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::Type::getInt16Ty(VMContext),
|
|
|
|
llvm::Type::getInt16Ty(VMContext),
|
2008-06-26 12:10:42 +08:00
|
|
|
ClassListTy, NULL);
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
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) {
|
2009-09-11 05:48:21 +08:00
|
|
|
Elements.push_back(ExportUniqueString(iter->first.first, ".objc_sel_name"));
|
2009-09-15 03:04:10 +08:00
|
|
|
Elements.push_back(MakeConstantString(iter->first.second,
|
2008-06-26 12:10:42 +08:00
|
|
|
".objc_sel_types"));
|
2009-07-28 06:29:56 +08:00
|
|
|
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.clear();
|
|
|
|
}
|
|
|
|
for (llvm::StringMap<llvm::GlobalAlias*>::iterator
|
|
|
|
iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
|
2008-06-26 12:10:42 +08:00
|
|
|
iter != iterEnd; ++iter) {
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(
|
2009-09-11 05:48:21 +08:00
|
|
|
ExportUniqueString(iter->getKeyData(), ".objc_sel_name"));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(NULLPtr);
|
2009-07-28 06:29:56 +08:00
|
|
|
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.clear();
|
|
|
|
}
|
|
|
|
Elements.push_back(NULLPtr);
|
|
|
|
Elements.push_back(NULLPtr);
|
2009-07-28 06:29:56 +08:00
|
|
|
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.clear();
|
|
|
|
// Number of static selectors
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() ));
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *SelectorList = MakeGlobal(
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
|
2008-06-01 22:13:53 +08:00
|
|
|
".objc_selector_list");
|
2009-09-09 23:08:12 +08:00
|
|
|
Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
|
2009-01-27 13:06:01 +08:00
|
|
|
SelStructPtrTy));
|
2008-06-01 22:13:53 +08:00
|
|
|
|
|
|
|
// Now that all of the static selectors exist, create pointers to them.
|
|
|
|
int index = 0;
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
llvm::SmallVector<std::pair<llvm::GlobalAlias*,llvm::Value*>, 16> selectors;
|
2008-06-01 22:13:53 +08:00
|
|
|
for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
|
|
|
|
iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
|
|
|
|
iter != iterEnd; ++iter) {
|
|
|
|
llvm::Constant *Idxs[] = {Zeros[0],
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
llvm::Constant *SelPtr =
|
|
|
|
llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2);
|
2009-01-27 13:06:01 +08:00
|
|
|
// If selectors are defined as an opaque type, cast the pointer to this
|
|
|
|
// type.
|
|
|
|
if (isSelOpaque) {
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,SelectorTy);
|
2009-01-27 13:06:01 +08:00
|
|
|
}
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
selectors.push_back(
|
|
|
|
std::pair<llvm::GlobalAlias*,llvm::Value*>((*iter).second, SelPtr));
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
for (llvm::StringMap<llvm::GlobalAlias*>::iterator
|
|
|
|
iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
|
|
|
|
iter != iterEnd; iter++) {
|
|
|
|
llvm::Constant *Idxs[] = {Zeros[0],
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
llvm::Constant *SelPtr =
|
|
|
|
llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2);
|
2009-01-27 13:06:01 +08:00
|
|
|
// If selectors are defined as an opaque type, cast the pointer to this
|
|
|
|
// type.
|
|
|
|
if (isSelOpaque) {
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy);
|
2009-01-27 13:06:01 +08:00
|
|
|
}
|
Numerous changes to selector handling:
- Don't use GlobalAliases with non-0 GEPs (GNU runtime) - this was unsupported and LLVM will be generating errors if you do it soon. This also simplifies the code generated by the GNU runtime a bit.
- Make GetSelector() return a constant (GNU runtime), not a load of a store of a constant.
- Recognise @selector() expressions as valid static initialisers (as GCC does).
- Add methods to GCObjCRuntime to emit selectors as constants (needed for using @selector() expressions as constants. These need implementing for the Mac runtimes - I couldn't figure out how to do this, they seem to require a load.
- Store an ObjCMethodDecl in an ObjCSelectorExpr so that we can get at the type information for the selector. This is needed for generating typed selectors from @selector() expressions (as GCC does). Ideally, this information should be stored in the Selector, but that would be an invasive change. We should eventually add checks for common uses of @selector() expressions. Possibly adding an attribute that can be applied to method args providing the types of a selector so, for example, you'd do something like this:
- (id)performSelector: __attribute__((selector_types(id, SEL, id)))(SEL)
withObject: (id)object;
Then, any @selector() expressions passed to the method will be check to ensure that it conforms to this signature. We do this at run time on the GNU runtime already, but it would be nice to do it at compile time on all runtimes.
- Made @selector() expressions emit type info if available and the runtime supports it.
Someone more familiar with the Mac runtime needs to implement the GetConstantSelector() function in CGObjCMac. This currently just assert()s.
llvm-svn: 95189
2010-02-03 10:09:30 +08:00
|
|
|
selectors.push_back(
|
|
|
|
std::pair<llvm::GlobalAlias*,llvm::Value*>((*iter).second, SelPtr));
|
|
|
|
}
|
|
|
|
for (llvm::SmallVectorImpl<std::pair<
|
|
|
|
llvm::GlobalAlias*,llvm::Value*> >::iterator
|
|
|
|
iter=selectors.begin(), iterEnd =selectors.end();
|
|
|
|
iter != iterEnd; ++iter) {
|
|
|
|
iter->first->replaceAllUsesWith(iter->second);
|
|
|
|
iter->first->eraseFromParent();
|
2008-06-01 22:13:53 +08:00
|
|
|
}
|
|
|
|
// Number of classes defined.
|
2009-09-09 23:08:12 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
|
2008-06-01 22:13:53 +08:00
|
|
|
Classes.size()));
|
|
|
|
// Number of categories defined
|
2009-09-09 23:08:12 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
|
2008-06-01 22:13:53 +08:00
|
|
|
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);
|
2009-07-29 02:33:04 +08:00
|
|
|
llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes);
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.push_back(ClassList);
|
2009-09-09 23:08:12 +08:00
|
|
|
// Construct the symbol table
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements);
|
|
|
|
|
|
|
|
// The symbol table is contained in a module which has some version-checking
|
|
|
|
// constants
|
2009-08-06 07:18:46 +08:00
|
|
|
llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy,
|
2009-07-30 06:16:19 +08:00
|
|
|
PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
|
2008-06-01 22:13:53 +08:00
|
|
|
Elements.clear();
|
|
|
|
// Runtime version used for compatibility checking.
|
2009-05-21 02:41:51 +08:00
|
|
|
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy,
|
2009-09-11 05:48:21 +08:00
|
|
|
NonFragileRuntimeVersion));
|
2009-05-21 02:41:51 +08:00
|
|
|
} else {
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
|
2009-05-21 02:41:51 +08:00
|
|
|
}
|
2009-04-02 03:49:42 +08:00
|
|
|
// sizeof(ModuleTy)
|
|
|
|
llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
|
2009-07-25 07:12:58 +08:00
|
|
|
Elements.push_back(llvm::ConstantInt::get(LongTy,
|
2009-07-15 07:10:40 +08:00
|
|
|
td.getTypeSizeInBits(ModuleTy)/8));
|
2008-06-01 22:13:53 +08:00
|
|
|
//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
|
|
|
|
llvm::Function * LoadFunction = llvm::Function::Create(
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false),
|
2008-06-01 22:13:53 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage, ".objc_load_function",
|
|
|
|
&TheModule);
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::BasicBlock *EntryBB =
|
|
|
|
llvm::BasicBlock::Create(VMContext, "entry", LoadFunction);
|
2009-07-15 07:10:40 +08:00
|
|
|
CGBuilderTy Builder(VMContext);
|
2008-06-01 22:13:53 +08:00
|
|
|
Builder.SetInsertPoint(EntryBB);
|
2009-03-31 02:02:14 +08:00
|
|
|
|
|
|
|
std::vector<const llvm::Type*> Params(1,
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::PointerType::getUnqual(ModuleTy));
|
|
|
|
llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class");
|
2008-06-01 22:13:53 +08:00
|
|
|
Builder.CreateCall(Register, Module);
|
|
|
|
Builder.CreateRetVoid();
|
2009-05-21 02:41:51 +08:00
|
|
|
|
2008-06-01 22:13:53 +08:00
|
|
|
return LoadFunction;
|
|
|
|
}
|
2008-08-16 06:20:32 +08:00
|
|
|
|
2009-01-11 05:06:09 +08:00
|
|
|
llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
|
2009-09-09 23:08:12 +08:00
|
|
|
const ObjCContainerDecl *CD) {
|
|
|
|
const ObjCCategoryImplDecl *OCD =
|
2009-01-09 03:41:02 +08:00
|
|
|
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
|
2008-11-24 11:33:13 +08:00
|
|
|
std::string CategoryName = OCD ? OCD->getNameAsString() : "";
|
|
|
|
std::string ClassName = OMD->getClassInterface()->getNameAsString();
|
|
|
|
std::string MethodName = OMD->getSelector().getAsString();
|
2009-01-10 01:18:27 +08:00
|
|
|
bool isClassMethod = !OMD->isInstanceMethod();
|
2008-03-31 07:03:07 +08:00
|
|
|
|
2009-02-03 07:23:47 +08:00
|
|
|
CodeGenTypes &Types = CGM.getTypes();
|
2009-09-09 23:08:12 +08:00
|
|
|
const llvm::FunctionType *MethodTy =
|
2009-02-03 07:23:47 +08:00
|
|
|
Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
|
2008-06-01 22:13:53 +08:00
|
|
|
std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
|
|
|
|
MethodName, isClassMethod);
|
|
|
|
|
2009-09-17 12:01:22 +08:00
|
|
|
llvm::Function *Method
|
2009-09-09 23:08:12 +08:00
|
|
|
= llvm::Function::Create(MethodTy,
|
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
FunctionName,
|
|
|
|
&TheModule);
|
2008-03-31 07:03:07 +08:00
|
|
|
return Method;
|
|
|
|
}
|
|
|
|
|
2008-09-24 11:38:44 +08:00
|
|
|
llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
|
2009-09-09 23:08:12 +08:00
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
const llvm::Type *BoolTy =
|
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
|
|
|
|
Params.push_back(IdTy);
|
|
|
|
Params.push_back(SelectorTy);
|
|
|
|
// FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
|
|
|
|
Params.push_back(LongTy);
|
|
|
|
Params.push_back(BoolTy);
|
|
|
|
// void objc_getProperty (id, SEL, ptrdiff_t, bool)
|
|
|
|
const llvm::FunctionType *FTy =
|
|
|
|
llvm::FunctionType::get(IdTy, Params, false);
|
|
|
|
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
|
|
|
|
"objc_getProperty"));
|
2008-09-24 11:38:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Function *CGObjCGNU::GetPropertySetFunction() {
|
2009-09-09 23:08:12 +08:00
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
const llvm::Type *BoolTy =
|
|
|
|
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
|
|
|
|
Params.push_back(IdTy);
|
|
|
|
Params.push_back(SelectorTy);
|
|
|
|
// FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
|
|
|
|
Params.push_back(LongTy);
|
|
|
|
Params.push_back(IdTy);
|
|
|
|
Params.push_back(BoolTy);
|
|
|
|
Params.push_back(BoolTy);
|
|
|
|
// void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
|
|
|
|
const llvm::FunctionType *FTy =
|
|
|
|
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
|
|
|
|
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
|
|
|
|
"objc_setProperty"));
|
2008-09-24 11:38:44 +08:00
|
|
|
}
|
|
|
|
|
2009-07-24 15:40:24 +08:00
|
|
|
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
|
|
|
|
CodeGen::CodeGenTypes &Types = CGM.getTypes();
|
|
|
|
ASTContext &Ctx = CGM.getContext();
|
|
|
|
// void objc_enumerationMutation (id)
|
|
|
|
llvm::SmallVector<QualType,16> Params;
|
2009-08-18 00:35:33 +08:00
|
|
|
Params.push_back(ASTIdTy);
|
2009-07-24 15:40:24 +08:00
|
|
|
const llvm::FunctionType *FTy =
|
|
|
|
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
|
|
|
|
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
|
2008-08-31 12:05:03 +08:00
|
|
|
}
|
|
|
|
|
2008-11-21 08:49:24 +08:00
|
|
|
void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
|
|
|
const Stmt &S) {
|
2009-05-08 08:11:50 +08:00
|
|
|
// Pointer to the personality function
|
|
|
|
llvm::Constant *Personality =
|
2009-08-14 05:57:51 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
|
2009-07-01 12:13:52 +08:00
|
|
|
true),
|
2009-05-08 08:11:50 +08:00
|
|
|
"__gnu_objc_personality_v0");
|
2009-07-30 02:54:39 +08:00
|
|
|
Personality = llvm::ConstantExpr::getBitCast(Personality, PtrTy);
|
2009-05-08 08:11:50 +08:00
|
|
|
std::vector<const llvm::Type*> Params;
|
|
|
|
Params.push_back(PtrTy);
|
|
|
|
llvm::Value *RethrowFn =
|
2009-08-14 05:57:51 +08:00
|
|
|
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
|
2010-01-07 02:02:59 +08:00
|
|
|
Params, false), "_Unwind_Resume");
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
bool isTry = isa<ObjCAtTryStmt>(S);
|
|
|
|
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
|
|
|
|
llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
|
|
|
|
llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
|
2009-05-12 02:16:28 +08:00
|
|
|
llvm::BasicBlock *CatchInCatch = CGF.createBasicBlock("catch.rethrow");
|
2009-05-08 08:11:50 +08:00
|
|
|
llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally");
|
|
|
|
llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw");
|
|
|
|
llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
|
|
|
|
|
2009-12-24 10:26:34 +08:00
|
|
|
// @synchronized()
|
2009-05-08 08:11:50 +08:00
|
|
|
if (!isTry) {
|
2009-05-12 02:16:28 +08:00
|
|
|
std::vector<const llvm::Type*> Args(1, IdTy);
|
|
|
|
llvm::FunctionType *FTy =
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
|
2009-05-12 02:16:28 +08:00
|
|
|
llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *SyncArg =
|
2009-05-12 02:16:28 +08:00
|
|
|
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
|
|
|
|
SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
|
|
|
|
CGF.Builder.CreateCall(SyncEnter, SyncArg);
|
2009-05-08 08:11:50 +08:00
|
|
|
}
|
|
|
|
|
2009-05-12 02:16:28 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
// Push an EH context entry, used for handling rethrows and jumps
|
|
|
|
// through finally.
|
|
|
|
CGF.PushCleanupBlock(FinallyBlock);
|
|
|
|
|
|
|
|
// Emit the statements in the @try {} block
|
|
|
|
CGF.setInvokeDest(TryHandler);
|
|
|
|
|
|
|
|
CGF.EmitBlock(TryBlock);
|
2009-09-09 23:08:12 +08:00
|
|
|
CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
|
2009-05-08 08:11:50 +08:00
|
|
|
: cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
|
|
|
|
|
|
|
|
// Jump to @finally if there is no exception
|
|
|
|
CGF.EmitBranchThroughCleanup(FinallyEnd);
|
|
|
|
|
|
|
|
// Emit the handlers
|
|
|
|
CGF.EmitBlock(TryHandler);
|
|
|
|
|
2009-05-09 01:36:08 +08:00
|
|
|
// Get the correct versions of the exception handling intrinsics
|
|
|
|
llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *llvm_eh_exception =
|
2009-05-08 08:11:50 +08:00
|
|
|
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
|
2009-10-15 00:13:30 +08:00
|
|
|
llvm::Value *llvm_eh_selector =
|
|
|
|
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
|
|
|
|
llvm::Value *llvm_eh_typeid_for =
|
|
|
|
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
// Exception object
|
|
|
|
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
|
|
|
|
llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
|
|
|
|
|
|
|
|
llvm::SmallVector<llvm::Value*, 8> ESelArgs;
|
|
|
|
llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
|
|
|
|
|
|
|
|
ESelArgs.push_back(Exc);
|
|
|
|
ESelArgs.push_back(Personality);
|
|
|
|
|
|
|
|
bool HasCatchAll = false;
|
|
|
|
// Only @try blocks are allowed @catch blocks, but both can have @finally
|
|
|
|
if (isTry) {
|
|
|
|
if (const ObjCAtCatchStmt* CatchStmt =
|
|
|
|
cast<ObjCAtTryStmt>(S).getCatchStmts()) {
|
2009-05-12 02:16:28 +08:00
|
|
|
CGF.setInvokeDest(CatchInCatch);
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
|
|
|
|
const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
|
2009-08-01 05:31:32 +08:00
|
|
|
Handlers.push_back(std::make_pair(CatchDecl,
|
|
|
|
CatchStmt->getCatchBody()));
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
// @catch() and @catch(id) both catch any ObjC exception
|
2009-07-11 07:34:53 +08:00
|
|
|
if (!CatchDecl || CatchDecl->getType()->isObjCIdType()
|
2009-05-08 08:11:50 +08:00
|
|
|
|| CatchDecl->getType()->isObjCQualifiedIdType()) {
|
|
|
|
// Use i8* null here to signal this is a catch all, not a cleanup.
|
|
|
|
ESelArgs.push_back(NULLPtr);
|
|
|
|
HasCatchAll = true;
|
|
|
|
// No further catches after this one will ever by reached
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-05-08 08:11:50 +08:00
|
|
|
|
|
|
|
// All other types should be Objective-C interface pointer types.
|
2009-09-09 23:08:12 +08:00
|
|
|
const ObjCObjectPointerType *OPT =
|
2009-09-22 07:43:11 +08:00
|
|
|
CatchDecl->getType()->getAs<ObjCObjectPointerType>();
|
2009-07-11 07:34:53 +08:00
|
|
|
assert(OPT && "Invalid @catch type.");
|
2009-09-09 23:08:12 +08:00
|
|
|
const ObjCInterfaceType *IT =
|
2009-09-22 07:43:11 +08:00
|
|
|
OPT->getPointeeType()->getAs<ObjCInterfaceType>();
|
2009-05-08 08:11:50 +08:00
|
|
|
assert(IT && "Invalid @catch type.");
|
2009-05-09 01:36:08 +08:00
|
|
|
llvm::Value *EHType =
|
|
|
|
MakeConstantString(IT->getDecl()->getNameAsString());
|
2009-05-08 08:11:50 +08:00
|
|
|
ESelArgs.push_back(EHType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We use a cleanup unless there was already a catch all.
|
|
|
|
if (!HasCatchAll) {
|
2009-08-14 05:57:51 +08:00
|
|
|
ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
|
2009-05-08 08:11:50 +08:00
|
|
|
Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find which handler was matched.
|
2009-05-09 01:36:08 +08:00
|
|
|
llvm::Value *ESelector = CGF.Builder.CreateCall(llvm_eh_selector,
|
2009-05-08 08:11:50 +08:00
|
|
|
ESelArgs.begin(), ESelArgs.end(), "selector");
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
|
|
|
|
const ParmVarDecl *CatchParam = Handlers[i].first;
|
|
|
|
const Stmt *CatchBody = Handlers[i].second;
|
|
|
|
|
|
|
|
llvm::BasicBlock *Next = 0;
|
|
|
|
|
|
|
|
// The last handler always matches.
|
|
|
|
if (i + 1 != e) {
|
|
|
|
assert(CatchParam && "Only last handler can be a catch all.");
|
|
|
|
|
|
|
|
// Test whether this block matches the type for the selector and branch
|
|
|
|
// to Match if it does, or to the next BB if it doesn't.
|
|
|
|
llvm::BasicBlock *Match = CGF.createBasicBlock("match");
|
|
|
|
Next = CGF.createBasicBlock("catch.next");
|
2009-05-09 01:36:08 +08:00
|
|
|
llvm::Value *Id = CGF.Builder.CreateCall(llvm_eh_typeid_for,
|
2009-05-08 08:11:50 +08:00
|
|
|
CGF.Builder.CreateBitCast(ESelArgs[i+2], PtrTy));
|
|
|
|
CGF.Builder.CreateCondBr(CGF.Builder.CreateICmpEQ(ESelector, Id), Match,
|
|
|
|
Next);
|
|
|
|
|
|
|
|
CGF.EmitBlock(Match);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
if (CatchBody) {
|
|
|
|
llvm::Value *ExcObject = CGF.Builder.CreateBitCast(Exc,
|
|
|
|
CGF.ConvertType(CatchParam->getType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
// Bind the catch parameter if it exists.
|
|
|
|
if (CatchParam) {
|
|
|
|
// CatchParam is a ParmVarDecl because of the grammar
|
|
|
|
// construction used to handle this, but for codegen purposes
|
|
|
|
// we treat this as a local decl.
|
|
|
|
CGF.EmitLocalBlockVarDecl(*CatchParam);
|
|
|
|
CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam));
|
|
|
|
}
|
|
|
|
|
|
|
|
CGF.ObjCEHValueStack.push_back(ExcObject);
|
|
|
|
CGF.EmitStmt(CatchBody);
|
|
|
|
CGF.ObjCEHValueStack.pop_back();
|
|
|
|
|
|
|
|
CGF.EmitBranchThroughCleanup(FinallyEnd);
|
|
|
|
|
|
|
|
if (Next)
|
|
|
|
CGF.EmitBlock(Next);
|
|
|
|
} else {
|
|
|
|
assert(!Next && "catchup should be last handler.");
|
|
|
|
|
|
|
|
CGF.Builder.CreateStore(Exc, RethrowPtr);
|
|
|
|
CGF.EmitBranchThroughCleanup(FinallyRethrow);
|
|
|
|
}
|
|
|
|
}
|
2009-05-12 02:16:28 +08:00
|
|
|
// The @finally block is a secondary landing pad for any exceptions thrown in
|
|
|
|
// @catch() blocks
|
|
|
|
CGF.EmitBlock(CatchInCatch);
|
|
|
|
Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
|
|
|
|
ESelArgs.clear();
|
|
|
|
ESelArgs.push_back(Exc);
|
|
|
|
ESelArgs.push_back(Personality);
|
2009-12-24 10:26:34 +08:00
|
|
|
// If there is a @catch or @finally clause in outside of this one then we
|
|
|
|
// need to make sure that we catch and rethrow it.
|
|
|
|
if (PrevLandingPad) {
|
|
|
|
ESelArgs.push_back(NULLPtr);
|
|
|
|
} else {
|
|
|
|
ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
|
|
|
|
}
|
2009-05-12 02:16:28 +08:00
|
|
|
CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(),
|
|
|
|
"selector");
|
|
|
|
CGF.Builder.CreateCall(llvm_eh_typeid_for,
|
|
|
|
CGF.Builder.CreateIntToPtr(ESelArgs[2], PtrTy));
|
|
|
|
CGF.Builder.CreateStore(Exc, RethrowPtr);
|
|
|
|
CGF.EmitBranchThroughCleanup(FinallyRethrow);
|
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
|
|
|
|
|
|
|
|
CGF.setInvokeDest(PrevLandingPad);
|
|
|
|
|
|
|
|
CGF.EmitBlock(FinallyBlock);
|
|
|
|
|
2009-05-12 02:16:28 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
if (isTry) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const ObjCAtFinallyStmt* FinallyStmt =
|
2009-05-08 08:11:50 +08:00
|
|
|
cast<ObjCAtTryStmt>(S).getFinallyStmt())
|
|
|
|
CGF.EmitStmt(FinallyStmt->getFinallyBody());
|
|
|
|
} else {
|
2009-05-12 02:16:28 +08:00
|
|
|
// Emit 'objc_sync_exit(expr)' as finally's sole statement for
|
2009-05-08 08:11:50 +08:00
|
|
|
// @synchronized.
|
2009-05-12 02:16:28 +08:00
|
|
|
std::vector<const llvm::Type*> Args(1, IdTy);
|
|
|
|
llvm::FunctionType *FTy =
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
|
2009-05-12 02:16:28 +08:00
|
|
|
llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *SyncArg =
|
2009-05-12 02:16:28 +08:00
|
|
|
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
|
|
|
|
SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
|
|
|
|
CGF.Builder.CreateCall(SyncExit, SyncArg);
|
2009-05-08 08:11:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Info.SwitchBlock)
|
|
|
|
CGF.EmitBlock(Info.SwitchBlock);
|
|
|
|
if (Info.EndBlock)
|
|
|
|
CGF.EmitBlock(Info.EndBlock);
|
|
|
|
|
|
|
|
// Branch around the rethrow code.
|
|
|
|
CGF.EmitBranch(FinallyEnd);
|
|
|
|
|
|
|
|
CGF.EmitBlock(FinallyRethrow);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-24 10:26:34 +08:00
|
|
|
llvm::Value *ExceptionObject = CGF.Builder.CreateLoad(RethrowPtr);
|
|
|
|
llvm::BasicBlock *UnwindBB = CGF.getInvokeDest();
|
|
|
|
if (!UnwindBB) {
|
|
|
|
CGF.Builder.CreateCall(RethrowFn, ExceptionObject);
|
|
|
|
// Exception always thrown, next instruction is never reached.
|
|
|
|
CGF.Builder.CreateUnreachable();
|
|
|
|
} else {
|
|
|
|
// If there is a @catch block outside this scope, we invoke instead of
|
|
|
|
// calling because we may return to this function. This is very slow, but
|
|
|
|
// some people still do it. It would be nice to add an optimised path for
|
|
|
|
// this.
|
|
|
|
CGF.Builder.CreateInvoke(RethrowFn, UnwindBB, UnwindBB, &ExceptionObject,
|
|
|
|
&ExceptionObject+1);
|
|
|
|
}
|
2009-05-08 08:11:50 +08:00
|
|
|
|
2009-12-24 10:26:34 +08:00
|
|
|
CGF.EmitBlock(FinallyEnd);
|
2008-09-09 18:04:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
|
2008-09-24 11:38:44 +08:00
|
|
|
const ObjCAtThrowStmt &S) {
|
2009-05-08 08:11:50 +08:00
|
|
|
llvm::Value *ExceptionAsObject;
|
|
|
|
|
|
|
|
std::vector<const llvm::Type*> Args(1, IdTy);
|
|
|
|
llvm::FunctionType *FTy =
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *ThrowFn =
|
2009-05-08 08:11:50 +08:00
|
|
|
CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
if (const Expr *ThrowExpr = S.getThrowExpr()) {
|
|
|
|
llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
|
2009-05-18 00:49:27 +08:00
|
|
|
ExceptionAsObject = Exception;
|
2009-05-08 08:11:50 +08:00
|
|
|
} else {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
|
2009-05-08 08:11:50 +08:00
|
|
|
"Unexpected rethrow outside @catch block.");
|
|
|
|
ExceptionAsObject = CGF.ObjCEHValueStack.back();
|
|
|
|
}
|
2009-05-18 00:49:27 +08:00
|
|
|
ExceptionAsObject =
|
|
|
|
CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy, "tmp");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 08:11:50 +08:00
|
|
|
// Note: This may have to be an invoke, if we want to support constructs like:
|
|
|
|
// @try {
|
|
|
|
// @throw(obj);
|
|
|
|
// }
|
|
|
|
// @catch(id) ...
|
|
|
|
//
|
|
|
|
// This is effectively turning @throw into an incredibly-expensive goto, but
|
|
|
|
// it may happen as a result of inlining followed by missed optimizations, or
|
|
|
|
// as a result of stupidity.
|
|
|
|
llvm::BasicBlock *UnwindBB = CGF.getInvokeDest();
|
|
|
|
if (!UnwindBB) {
|
|
|
|
CGF.Builder.CreateCall(ThrowFn, ExceptionAsObject);
|
|
|
|
CGF.Builder.CreateUnreachable();
|
|
|
|
} else {
|
|
|
|
CGF.Builder.CreateInvoke(ThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject,
|
|
|
|
&ExceptionAsObject+1);
|
|
|
|
}
|
|
|
|
// Clear the insertion point to indicate we are in unreachable code.
|
|
|
|
CGF.Builder.ClearInsertionPoint();
|
2008-09-09 18:04:29 +08:00
|
|
|
}
|
|
|
|
|
2008-11-19 06:37:34 +08:00
|
|
|
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *AddrWeakObj) {
|
2008-11-19 05:45:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-19 06:37:34 +08:00
|
|
|
void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *src, llvm::Value *dst) {
|
2008-11-19 06:37:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-19 08:59:10 +08:00
|
|
|
void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *src, llvm::Value *dst) {
|
2008-11-19 08:59:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-21 03:23:36 +08:00
|
|
|
void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
|
2009-09-25 06:25:38 +08:00
|
|
|
llvm::Value *src, llvm::Value *dst,
|
|
|
|
llvm::Value *ivarOffset) {
|
2008-11-21 03:23:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-19 08:59:10 +08:00
|
|
|
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *src, llvm::Value *dst) {
|
2008-11-19 08:59:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-08 09:18:33 +08:00
|
|
|
void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Value *DestPtr,
|
2009-07-08 09:18:33 +08:00
|
|
|
llvm::Value *SrcPtr,
|
2009-09-01 03:33:16 +08:00
|
|
|
QualType Ty) {
|
2009-07-08 09:18:33 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-21 02:41:51 +08:00
|
|
|
llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
|
|
|
|
const ObjCInterfaceDecl *ID,
|
|
|
|
const ObjCIvarDecl *Ivar) {
|
|
|
|
const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
|
|
|
|
+ '.' + Ivar->getNameAsString();
|
|
|
|
// Emit the variable and initialize it with what we think the correct value
|
|
|
|
// is. This allows code compiled with non-fragile ivars to work correctly
|
|
|
|
// when linked against code which isn't (most of the time).
|
2009-09-01 00:41:57 +08:00
|
|
|
llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
|
|
|
|
if (!IvarOffsetPointer) {
|
2009-05-21 02:41:51 +08:00
|
|
|
uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
|
|
|
|
llvm::ConstantInt *OffsetGuess =
|
2010-01-12 03:02:35 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar");
|
2009-09-01 00:41:57 +08:00
|
|
|
// Don't emit the guess in non-PIC code because the linker will not be able
|
|
|
|
// to replace it with the real version for a library. In non-PIC code you
|
|
|
|
// must compile with the fragile ABI if you want to use ivars from a
|
2009-09-09 23:08:12 +08:00
|
|
|
// GCC-compiled class.
|
2009-09-01 00:41:57 +08:00
|
|
|
if (CGM.getLangOptions().PICLevel) {
|
|
|
|
llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule,
|
|
|
|
llvm::Type::getInt32Ty(VMContext), false,
|
|
|
|
llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess");
|
|
|
|
IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
|
|
|
|
IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage,
|
|
|
|
IvarOffsetGV, Name);
|
|
|
|
} else {
|
|
|
|
IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
|
2009-10-13 18:07:13 +08:00
|
|
|
llvm::Type::getInt32PtrTy(VMContext), false,
|
|
|
|
llvm::GlobalValue::ExternalLinkage, 0, Name);
|
2009-09-01 00:41:57 +08:00
|
|
|
}
|
2009-05-21 02:41:51 +08:00
|
|
|
}
|
2009-09-01 00:41:57 +08:00
|
|
|
return IvarOffsetPointer;
|
2009-05-21 02:41:51 +08:00
|
|
|
}
|
|
|
|
|
2009-02-04 03:03:09 +08:00
|
|
|
LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
|
|
|
|
QualType ObjectTy,
|
|
|
|
llvm::Value *BaseValue,
|
|
|
|
const ObjCIvarDecl *Ivar,
|
|
|
|
unsigned CVRQualifiers) {
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
|
2009-04-22 15:32:20 +08:00
|
|
|
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
|
|
|
|
EmitIvarOffset(CGF, ID, Ivar));
|
2009-02-03 04:02:29 +08:00
|
|
|
}
|
2009-08-01 05:31:32 +08:00
|
|
|
|
2009-05-21 02:41:51 +08:00
|
|
|
static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
|
|
|
|
const ObjCInterfaceDecl *OID,
|
|
|
|
const ObjCIvarDecl *OIVD) {
|
|
|
|
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
|
2009-06-04 09:19:09 +08:00
|
|
|
Context.ShallowCollectObjCIvars(OID, Ivars);
|
2009-05-21 02:41:51 +08:00
|
|
|
for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
|
|
|
|
if (OIVD == Ivars[k])
|
|
|
|
return OID;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-21 02:41:51 +08:00
|
|
|
// Otherwise check in the super class.
|
|
|
|
if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
|
|
|
|
return FindIvarInterface(Context, Super, OIVD);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-21 02:41:51 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-02-03 04:02:29 +08:00
|
|
|
|
2009-02-11 03:02:04 +08:00
|
|
|
llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
|
2009-04-22 13:08:15 +08:00
|
|
|
const ObjCInterfaceDecl *Interface,
|
2009-02-11 03:02:04 +08:00
|
|
|
const ObjCIvarDecl *Ivar) {
|
2009-09-01 00:41:57 +08:00
|
|
|
if (CGM.getLangOptions().ObjCNonFragileABI) {
|
2009-05-21 02:41:51 +08:00
|
|
|
Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
|
2009-09-01 00:41:57 +08:00
|
|
|
return CGF.Builder.CreateLoad(CGF.Builder.CreateLoad(
|
|
|
|
ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar"));
|
2009-05-21 02:41:51 +08:00
|
|
|
}
|
2009-04-22 15:32:20 +08:00
|
|
|
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
|
2009-07-25 07:12:58 +08:00
|
|
|
return llvm::ConstantInt::get(LongTy, Offset, "ivar");
|
2009-02-11 03:02:04 +08:00
|
|
|
}
|
|
|
|
|
2009-08-01 05:31:32 +08:00
|
|
|
CodeGen::CGObjCRuntime *
|
|
|
|
CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM) {
|
2008-06-26 12:19:03 +08:00
|
|
|
return new CGObjCGNU(CGM);
|
2008-03-01 16:50:34 +08:00
|
|
|
}
|