From 5f4e3a780f5a3d6abd9b55ea3106d1a171f68459 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Wed, 30 Nov 2011 01:57:58 +0000 Subject: [PATCH] Add bigger method type encodings to protocol objects. The new metadata are method @encode strings with additional data. 1. Each Objective-C object is marked with its class name and protocol names. The same is done for property @encode already. 2. Each block object is marked with its function prototype's @encoding. For example, a method parameter that is a block object that itself returns void and takes an int would look like: @? These new method @encode strings are stored in a single array pointed to by structs protocol_t and objc_protocol_ext. Patch provided by Greg Parker! llvm-svn: 145469 --- clang/include/clang/AST/ASTContext.h | 14 ++++- clang/lib/AST/ASTContext.cpp | 76 ++++++++++++++++++++----- clang/lib/CodeGen/CGObjCMac.cpp | 83 +++++++++++++++++++++++----- 3 files changed, 144 insertions(+), 29 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b093f2ce9f48..7d5d1f55ee66 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1007,7 +1007,8 @@ public: /// /// \returns true if an error occurred (e.g., because one of the parameter /// types is incomplete), false otherwise. - bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S) + bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S, + bool Extended = false) const; /// getObjCEncodingForBlock - Return the encoded type for this block @@ -1764,13 +1765,20 @@ private: const FieldDecl *Field, bool OutermostType = false, bool EncodingProperty = false, - bool StructField = false) const; + bool StructField = false, + bool EncodeBlockParameters = false, + bool EncodeClassNames = false) const; // Adds the encoding of the structure's members. void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, const FieldDecl *Field, bool includeVBases = true) const; - + + // Adds the encoding of a method parameter or return type. + void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, + QualType T, std::string& S, + bool Extended) const; + const ASTRecordLayout & getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) const; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2e898f188e56..22b5ed803db4 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4080,15 +4080,32 @@ bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, return false; } +/// getObjCEncodingForMethodParameter - Return the encoded type for a single +/// method parameter or return type. If Extended, include class names and +/// block object types. +void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, + QualType T, std::string& S, + bool Extended) const { + // Encode type qualifer, 'in', 'inout', etc. for the parameter. + getObjCEncodingForTypeQualifier(QT, S); + // Encode parameter type. + getObjCEncodingForTypeImpl(T, S, true, true, 0, + true /*OutermostType*/, + false /*EncodingProperty*/, + false /*StructField*/, + Extended /*EncodeBlockParameters*/, + Extended /*EncodeClassNames*/); +} + /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, - std::string& S) const { + std::string& S, + bool Extended) const { // FIXME: This is not very efficient. - // Encode type qualifer, 'in', 'inout', etc. for the return type. - getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); - // Encode result type. - getObjCEncodingForType(Decl->getResultType(), S); + // Encode return type. + getObjCEncodingForMethodParameter(Decl->getObjCDeclQualifier(), + Decl->getResultType(), S, Extended); // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! @@ -4126,10 +4143,8 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, PType = PVDecl->getType(); } else if (PType->isFunctionType()) PType = PVDecl->getType(); - // Process argument qualifiers for user supplied arguments; such as, - // 'in', 'inout', etc. - getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S); - getObjCEncodingForType(PType, S); + getObjCEncodingForMethodParameter(PVDecl->getObjCDeclQualifier(), + PType, S, Extended); S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } @@ -4355,7 +4370,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const FieldDecl *FD, bool OutermostType, bool EncodingProperty, - bool StructField) const { + bool StructField, + bool EncodeBlockParameters, + bool EncodeClassNames) const { if (T->getAs()) { if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); @@ -4534,8 +4551,40 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - if (T->isBlockPointerType()) { + if (const BlockPointerType *BT = T->getAs()) { S += "@?"; // Unlike a pointer-to-function, which is "^?". + if (EncodeBlockParameters) { + const FunctionType *FT = BT->getPointeeType()->getAs(); + + S += '<'; + // Block return type + getObjCEncodingForTypeImpl(FT->getResultType(), S, + ExpandPointedToStructures, ExpandStructures, + FD, + false /* OutermostType */, + EncodingProperty, + false /* StructField */, + EncodeBlockParameters, + EncodeClassNames); + // Block self + S += "@?"; + // Block parameters + if (const FunctionProtoType *FPT = dyn_cast(FT)) { + for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(), + E = FPT->arg_type_end(); I && (I != E); ++I) { + getObjCEncodingForTypeImpl(*I, S, + ExpandPointedToStructures, + ExpandStructures, + FD, + false /* OutermostType */, + EncodingProperty, + false /* StructField */, + EncodeBlockParameters, + EncodeClassNames); + } + } + S += '>'; + } return; } @@ -4581,7 +4630,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl(getObjCIdType(), S, ExpandPointedToStructures, ExpandStructures, FD); - if (FD || EncodingProperty) { + if (FD || EncodingProperty || EncodeClassNames) { // Note that we do extended encoding of protocol qualifer list // Only when doing ivar or property encoding. S += '"'; @@ -4610,7 +4659,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } S += '@'; - if (OPT->getInterfaceDecl() && (FD || EncodingProperty)) { + if (OPT->getInterfaceDecl() && + (FD || EncodingProperty || EncodeClassNames)) { S += '"'; S += OPT->getInterfaceDecl()->getIdentifier()->getName(); for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 1db50a8f578e..c3cca394a84c 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -175,7 +175,7 @@ protected: public: llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy; - llvm::Type *Int8PtrTy; + llvm::Type *Int8PtrTy, *Int8PtrPtrTy; /// ObjectPtrTy - LLVM type for object handles (typeof(id)) llvm::Type *ObjectPtrTy; @@ -766,10 +766,11 @@ protected: llvm::Constant *GetMethodVarName(IdentifierInfo *Ident); /// GetMethodVarType - Return a unique constant for the given - /// selector's name. The return value has type char *. + /// method's type encoding string. The return value has type char *. // FIXME: This is a horrible name. - llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D); + llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D, + bool Extended = false); llvm::Constant *GetMethodVarType(const FieldDecl *D); /// GetPropertyName - Return a unique constant for the given @@ -816,6 +817,12 @@ protected: const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); + /// EmitProtocolMethodTypes - Generate the array of extended method type + /// strings. The return value has type Int8PtrPtrTy. + llvm::Constant *EmitProtocolMethodTypes(Twine Name, + const ConstantVector &MethodTypes, + const ObjCCommonTypesHelper &ObjCTypes); + /// PushProtocolProperties - Push protocol's property on the input stack. void PushProtocolProperties(llvm::SmallPtrSet &PropertySet, std::vector &Properties, @@ -985,7 +992,8 @@ private: llvm::Constant * EmitProtocolExtension(const ObjCProtocolDecl *PD, const ConstantVector &OptInstanceMethods, - const ConstantVector &OptClassMethods); + const ConstantVector &OptClassMethods, + const ConstantVector &MethodTypesExt); /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. @@ -1786,6 +1794,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { // Construct method lists. std::vector InstanceMethods, ClassMethods; std::vector OptInstanceMethods, OptClassMethods; + std::vector MethodTypesExt, OptMethodTypesExt; for (ObjCProtocolDecl::instmeth_iterator i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; @@ -1795,8 +1804,10 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptInstanceMethods.push_back(C); + OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); } else { InstanceMethods.push_back(C); + MethodTypesExt.push_back(GetMethodVarType(MD, true)); } } @@ -1809,13 +1820,19 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptClassMethods.push_back(C); + OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); } else { ClassMethods.push_back(C); + MethodTypesExt.push_back(GetMethodVarType(MD, true)); } } + MethodTypesExt.insert(MethodTypesExt.end(), + OptMethodTypesExt.begin(), OptMethodTypesExt.end()); + llvm::Constant *Values[] = { - EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods), + EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods, + MethodTypesExt), GetClassName(PD->getIdentifier()), EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(), PD->protocol_begin(), @@ -1875,12 +1892,14 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { struct objc_method_description_list *optional_instance_methods; struct objc_method_description_list *optional_class_methods; struct objc_property_list *instance_properties; + const char ** extendedMethodTypes; }; */ llvm::Constant * CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, const ConstantVector &OptInstanceMethods, - const ConstantVector &OptClassMethods) { + const ConstantVector &OptClassMethods, + const ConstantVector &MethodTypesExt) { uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); llvm::Constant *Values[] = { @@ -1893,12 +1912,14 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, "__OBJC,__cat_cls_meth,regular,no_dead_strip", OptClassMethods), EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD, - ObjCTypes) + ObjCTypes), + EmitProtocolMethodTypes("\01L_OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(), + MethodTypesExt, ObjCTypes) }; // Return null if no extension bits are used. if (Values[1]->isNullValue() && Values[2]->isNullValue() && - Values[3]->isNullValue()) + Values[3]->isNullValue() && Values[4]->isNullValue()) return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy); llvm::Constant *Init = @@ -2037,6 +2058,25 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy); } +llvm::Constant *CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name, + const ConstantVector &MethodTypes, + const ObjCCommonTypesHelper &ObjCTypes) { + // Return null for empty list. + if (MethodTypes.empty()) + return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy); + + llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, + MethodTypes.size()); + llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes); + + llvm::GlobalVariable *GV = + CreateMetadataVar(Name, Init, + (ObjCABI == 2) ? "__DATA, __objc_const" : 0, + (ObjCABI == 2) ? 8 : 4, + true); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy); +} + /* struct objc_method_description_list { int count; @@ -4024,11 +4064,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { return getConstantGEP(VMContext, Entry, 0, 0); } -llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) { +llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D, + bool Extended) { std::string TypeStr; if (CGM.getContext().getObjCEncodingForMethodDecl( const_cast(D), - TypeStr)) + TypeStr, Extended)) return 0; llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr]; @@ -4152,6 +4193,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) LongTy = Types.ConvertType(Ctx.LongTy); LongLongTy = Types.ConvertType(Ctx.LongLongTy); Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + Int8PtrPtrTy = llvm::PointerType::getUnqual(Int8PtrTy); ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType()); PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy); @@ -4253,12 +4295,13 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_method_description_list *optional_instance_methods; // struct _objc_method_description_list *optional_class_methods; // struct _objc_property_list *instance_properties; + // const char ** extendedMethodTypes; // } ProtocolExtensionTy = llvm::StructType::create("struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy, MethodDescriptionListPtrTy, PropertyListPtrTy, - NULL); + Int8PtrPtrTy, NULL); // struct _objc_protocol_extension * ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy); @@ -4431,6 +4474,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // const struct _prop_list_t * properties; // const uint32_t size; // sizeof(struct _protocol_t) // const uint32_t flags; // = 0 + // const char ** extendedMethodTypes; // } // Holder for struct _protocol_list_t * @@ -4442,7 +4486,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy, - PropertyListPtrTy, IntTy, IntTy, NULL); + PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, + NULL); // struct _protocol_t* ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy); @@ -5353,6 +5398,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( /// const struct _prop_list_t * properties; /// const uint32_t size; // sizeof(struct _protocol_t) /// const uint32_t flags; // = 0 +/// const char ** extendedMethodTypes; /// } /// @endcode /// @@ -5368,6 +5414,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // Construct method lists. std::vector InstanceMethods, ClassMethods; std::vector OptInstanceMethods, OptClassMethods; + std::vector MethodTypesExt, OptMethodTypesExt; for (ObjCProtocolDecl::instmeth_iterator i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; @@ -5377,8 +5424,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptInstanceMethods.push_back(C); + OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); } else { InstanceMethods.push_back(C); + MethodTypesExt.push_back(GetMethodVarType(MD, true)); } } @@ -5391,12 +5440,17 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptClassMethods.push_back(C); + OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); } else { ClassMethods.push_back(C); + MethodTypesExt.push_back(GetMethodVarType(MD, true)); } } - llvm::Constant *Values[10]; + MethodTypesExt.insert(MethodTypesExt.end(), + OptMethodTypesExt.begin(), OptMethodTypesExt.end()); + + llvm::Constant *Values[11]; // isa is NULL Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy); Values[1] = GetClassName(PD->getIdentifier()); @@ -5426,6 +5480,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy); + Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_" + + PD->getName(), + MethodTypesExt, ObjCTypes); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy, Values);