[cfe-commits] r146160 - /cfe/trunk/lib/Rewrite/RewriteObjC.cpp
Fariborz Jahanian
fjahanian at apple.com
Thu Dec 8 10:25:15 PST 2011
Author: fjahanian
Date: Thu Dec 8 12:25:15 2011
New Revision: 146160
URL: http://llvm.org/viewvc/llvm-project?rev=146160&view=rev
Log:
More refactoring of objective-C rewriter.
Modified:
cfe/trunk/lib/Rewrite/RewriteObjC.cpp
Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=146160&r1=146159&r2=146160&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original)
+++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Thu Dec 8 12:25:15 2011
@@ -32,6 +32,8 @@
namespace {
class RewriteObjC : public ASTConsumer {
+ protected:
+
enum {
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
block, ... */
@@ -54,7 +56,7 @@
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};
static const int OBJC_ABI_VERSION = 7;
-
+
Rewriter Rewrite;
DiagnosticsEngine &Diags;
const LangOptions &LangOpts;
@@ -72,7 +74,6 @@
TypeDecl *ProtocolTypeDecl;
VarDecl *GlobalVarDecl;
unsigned RewriteFailedDiag;
- unsigned TryFinallyContainsReturnDiag;
// ObjC string constant support.
unsigned NumObjCStringLiterals;
VarDecl *ConstantStringClassReference;
@@ -81,6 +82,7 @@
// ObjC foreach break/continue generation support.
int BcLabelCount;
+ unsigned TryFinallyContainsReturnDiag;
// Needed for super.
ObjCMethodDecl *CurMethodDef;
RecordDecl *SuperStructDecl;
@@ -156,9 +158,9 @@
R.DisableReplaceStmt = SavedValue;
}
};
+ void InitializeCommon(ASTContext &context);
public:
- virtual void Initialize(ASTContext &context);
// Top Level Driver code.
virtual bool HandleTopLevelDecl(DeclGroupRef D) {
@@ -284,7 +286,6 @@
// Expression Rewriting.
Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
- Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);
Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);
Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
@@ -301,31 +302,7 @@
Stmt *RewriteBreakStmt(BreakStmt *S);
Stmt *RewriteContinueStmt(ContinueStmt *S);
void RewriteCastExpr(CStyleCastExpr *CE);
-
- // Metadata Rewriting.
- void RewriteMetaDataIntoBuffer(std::string &Result);
- void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
- std::string &Result);
-
- void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
- std::string &Result);
-
- template<typename MethodIterator>
- void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
- MethodIterator MethodEnd,
- bool IsInstanceMethod,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
-
- void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
- void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
+
// Block rewriting.
void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
@@ -338,8 +315,28 @@
void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result);
- void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
- std::string &Result);
+
+ virtual void Initialize(ASTContext &context) = 0;
+
+ // Metadata Rewriting.
+ virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0;
+ virtual void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) = 0;
+ virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result) = 0;
+ virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) = 0;
+ virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) = 0;
+
+ // Rewriting ivar access
+ virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0;
+ virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) = 0;
// Misc. AST transformation routines. Somtimes they end up calling
// rewriting routines on the new ASTs.
@@ -488,6 +485,45 @@
SourceLocation(), SourceLocation());
}
};
+
+ class RewriteObjCFragileABI : public RewriteObjC {
+ public:
+
+ RewriteObjCFragileABI(std::string inFile, raw_ostream *OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
+ bool silenceMacroWarn) : RewriteObjC(inFile, OS,
+ D, LOpts,
+ silenceMacroWarn) {}
+
+ ~RewriteObjCFragileABI() {}
+ virtual void Initialize(ASTContext &context);
+
+ // Rewriting metadata
+ template<typename MethodIterator>
+ void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result);
+ virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result);
+ virtual void RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix, StringRef ClassName, std::string &Result);
+ virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result);
+ virtual void RewriteMetaDataIntoBuffer(std::string &Result);
+ virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result);
+
+ // Rewriting ivar
+ virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result);
+ virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
+ };
}
void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
@@ -543,10 +579,15 @@
DiagnosticsEngine &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning) {
- return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+ if (true /*!LOpts.ObjCNonFragileABI*/)
+ return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+ else {
+ assert(false && "objective-C rewriter for nonfragile ABI = NYI");
+ return 0;
+ }
}
-void RewriteObjC::Initialize(ASTContext &context) {
+void RewriteObjC::InitializeCommon(ASTContext &context) {
Context = &context;
SM = &Context->getSourceManager();
TUDecl = Context->getTranslationUnitDecl();
@@ -584,120 +625,8 @@
MainFileEnd = MainBuf->getBufferEnd();
Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOptions());
-
- // declaring objc_selector outside the parameter list removes a silly
- // scope related warning...
- if (IsHeader)
- Preamble = "#pragma once\n";
- Preamble += "struct objc_selector; struct objc_class;\n";
- Preamble += "struct __rw_objc_super { struct objc_object *object; ";
- Preamble += "struct objc_object *superClass; ";
- if (LangOpts.MicrosoftExt) {
- // Add a constructor for creating temporary objects.
- Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
- ": ";
- Preamble += "object(o), superClass(s) {} ";
- }
- Preamble += "};\n";
- Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
- Preamble += "typedef struct objc_object Protocol;\n";
- Preamble += "#define _REWRITER_typedef_Protocol\n";
- Preamble += "#endif\n";
- if (LangOpts.MicrosoftExt) {
- Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
- Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
- } else
- Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
- Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";
- Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
- Preamble += "(const char *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
- Preamble += "(struct objc_class *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
- Preamble += "(const char *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
- Preamble += "(struct objc_class *, struct objc_object *);\n";
- // @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
- Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
- Preamble += "struct __objcFastEnumerationState {\n\t";
- Preamble += "unsigned long state;\n\t";
- Preamble += "void **itemsPtr;\n\t";
- Preamble += "unsigned long *mutationsPtr;\n\t";
- Preamble += "unsigned long extra[5];\n};\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
- Preamble += "#define __FASTENUMERATIONSTATE\n";
- Preamble += "#endif\n";
- Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
- Preamble += "struct __NSConstantStringImpl {\n";
- Preamble += " int *isa;\n";
- Preamble += " int flags;\n";
- Preamble += " char *str;\n";
- Preamble += " long length;\n";
- Preamble += "};\n";
- Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
- Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
- Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
- Preamble += "#endif\n";
- Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
- Preamble += "#endif\n";
- // Blocks preamble.
- Preamble += "#ifndef BLOCK_IMPL\n";
- Preamble += "#define BLOCK_IMPL\n";
- Preamble += "struct __block_impl {\n";
- Preamble += " void *isa;\n";
- Preamble += " int Flags;\n";
- Preamble += " int Reserved;\n";
- Preamble += " void *FuncPtr;\n";
- Preamble += "};\n";
- Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
- Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
- Preamble += "extern \"C\" __declspec(dllexport) "
- "void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
- Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
- Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
- Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
- Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
- Preamble += "#endif\n";
- Preamble += "#endif\n";
- if (LangOpts.MicrosoftExt) {
- Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
- Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
- Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
- Preamble += "#define __attribute__(X)\n";
- Preamble += "#endif\n";
- Preamble += "#define __weak\n";
- }
- else {
- Preamble += "#define __block\n";
- Preamble += "#define __weak\n";
- }
- // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
- // as this avoids warning in any 64bit/32bit compilation model.
- Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-
//===----------------------------------------------------------------------===//
// Top Level Driver Code
//===----------------------------------------------------------------------===//
@@ -1436,98 +1365,6 @@
return Replacement;
}
-Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
- SourceRange OldRange = IV->getSourceRange();
- Expr *BaseExpr = IV->getBase();
-
- // Rewrite the base, but without actually doing replaces.
- {
- DisableReplaceStmtScope S(*this);
- BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));
- IV->setBase(BaseExpr);
- }
-
- ObjCIvarDecl *D = IV->getDecl();
-
- Expr *Replacement = IV;
- if (CurMethodDef) {
- if (BaseExpr->getType()->isObjCObjectPointerType()) {
- const ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
- assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
- // lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
- clsDeclared);
- assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
-
- // Synthesize an explicit cast to gain access to the ivar.
- std::string RecName = clsDeclared->getIdentifier()->getName();
- RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- II);
- assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
- QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
- CK_BitCast,
- IV->getBase());
- // Don't forget the parens to enforce the proper binding.
- ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),
- OldRange.getEnd(),
- castExpr);
- if (IV->isFreeIvar() &&
- CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
- MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
- IV->getLocation(),
- D->getType(),
- VK_LValue, OK_Ordinary);
- Replacement = ME;
- } else {
- IV->setBase(PE);
- }
- }
- } else { // we are outside a method.
- assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
-
- // Explicit ivar refs need to have a cast inserted.
- // FIXME: consider sharing some of this code with the code above.
- if (BaseExpr->getType()->isObjCObjectPointerType()) {
- const ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
- // lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
- clsDeclared);
- assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
-
- // Synthesize an explicit cast to gain access to the ivar.
- std::string RecName = clsDeclared->getIdentifier()->getName();
- RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- II);
- assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
- QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
- CK_BitCast,
- IV->getBase());
- // Don't forget the parens to enforce the proper binding.
- ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
- IV->getBase()->getLocEnd(), castExpr);
- // Cannot delete IV->getBase(), since PE points to it.
- // Replace the old base with the cast. This is important when doing
- // embedded rewrites. For example, [newInv->_container addObject:0].
- IV->setBase(PE);
- }
- }
-
- ReplaceStmtWithRange(IV, Replacement, OldRange);
- return Replacement;
-}
-
/// SynthCountByEnumWithState - To print:
/// ((unsigned int (*)
/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
@@ -3405,2541 +3242,2749 @@
llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct");
}
-// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
-/// class methods.
-template<typename MethodIterator>
-void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
- MethodIterator MethodEnd,
- bool IsInstanceMethod,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result) {
- if (MethodBegin == MethodEnd) return;
+//===----------------------------------------------------------------------===//
+// Meta Data Emission
+//===----------------------------------------------------------------------===//
- if (!objc_impl_method) {
- /* struct _objc_method {
- SEL _cmd;
- char *method_types;
- void *_imp;
- }
- */
- Result += "\nstruct _objc_method {\n";
- Result += "\tSEL _cmd;\n";
- Result += "\tchar *method_types;\n";
- Result += "\tvoid *_imp;\n";
- Result += "};\n";
- objc_impl_method = true;
- }
+/// RewriteImplementations - This routine rewrites all method implementations
+/// and emits meta-data.
- // Build _objc_method_list for class's methods if needed
+void RewriteObjC::RewriteImplementations() {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
- /* struct {
- struct _objc_method_list *next_method;
- int method_count;
- struct _objc_method method_list[];
- }
- */
- unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
- Result += "\nstatic struct {\n";
- Result += "\tstruct _objc_method_list *next_method;\n";
- Result += "\tint method_count;\n";
- Result += "\tstruct _objc_method method_list[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_";
- Result += prefix;
- Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
- Result += "_METHODS_";
- Result += ClassName;
- Result += " __attribute__ ((used, section (\"__OBJC, __";
- Result += IsInstanceMethod ? "inst" : "cls";
- Result += "_meth\")))= ";
- Result += "{\n\t0, " + utostr(NumMethods) + "\n";
+ // Rewrite implemented methods
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteImplementationDecl(ClassImplementation[i]);
- Result += "\t,{{(SEL)\"";
- Result += (*MethodBegin)->getSelector().getAsString().c_str();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\", (void *)";
- Result += MethodInternalNames[*MethodBegin];
- Result += "}\n";
- for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
- Result += "\t ,{(SEL)\"";
- Result += (*MethodBegin)->getSelector().getAsString().c_str();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\", (void *)";
- Result += MethodInternalNames[*MethodBegin];
- Result += "}\n";
- }
- Result += "\t }\n};\n";
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteImplementationDecl(CategoryImplementation[i]);
}
-/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
-void RewriteObjC::
-RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, StringRef prefix,
- StringRef ClassName, std::string &Result) {
- static bool objc_protocol_methods = false;
+void RewriteObjC::RewriteByRefString(std::string &ResultStr,
+ const std::string &Name,
+ ValueDecl *VD, bool def) {
+ assert(BlockByRefDeclNo.count(VD) &&
+ "RewriteByRefString: ByRef decl missing");
+ if (def)
+ ResultStr += "struct ";
+ ResultStr += "__Block_byref_" + Name +
+ "_" + utostr(BlockByRefDeclNo[VD]) ;
+}
- // Output struct protocol_methods holder of method selector and type.
- if (!objc_protocol_methods && !PDecl->isForwardDecl()) {
- /* struct protocol_methods {
- SEL _cmd;
- char *method_types;
- }
- */
- Result += "\nstruct _protocol_methods {\n";
- Result += "\tstruct objc_selector *_cmd;\n";
- Result += "\tchar *method_types;\n";
- Result += "};\n";
+static bool HasLocalVariableExternalStorage(ValueDecl *VD) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage());
+ return false;
+}
- objc_protocol_methods = true;
- }
- // Do not synthesize the protocol more than once.
- if (ObjCSynthesizedProtocols.count(PDecl))
- return;
+std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
+ StringRef funcName,
+ std::string Tag) {
+ const FunctionType *AFT = CE->getFunctionType();
+ QualType RT = AFT->getResultType();
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
+ funcName.str() + "_" + "block_func_" + utostr(i);
- if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
- unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
- PDecl->instmeth_end());
- /* struct _objc_protocol_method_list {
- int protocol_method_count;
- struct protocol_methods protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tint protocol_method_count;\n";
- Result += "\tstruct _protocol_methods protocol_methods[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
- "{\n\t" + utostr(NumMethods) + "\n";
+ BlockDecl *BD = CE->getBlockDecl();
- // Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I) {
- if (I == PDecl->instmeth_begin())
- Result += "\t ,{{(struct objc_selector *)\"";
+ if (isa<FunctionNoProtoType>(AFT)) {
+ // No user-supplied arguments. Still need to pass in a pointer to the
+ // block (to reference imported block decl refs).
+ S += "(" + StructRef + " *__cself)";
+ } else if (BD->param_empty()) {
+ S += "(" + StructRef + " *__cself)";
+ } else {
+ const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
+ assert(FT && "SynthesizeBlockFunc: No function proto");
+ S += '(';
+ // first add the implicit argument.
+ S += StructRef + " *__cself, ";
+ std::string ParamStr;
+ for (BlockDecl::param_iterator AI = BD->param_begin(),
+ E = BD->param_end(); AI != E; ++AI) {
+ if (AI != BD->param_begin()) S += ", ";
+ ParamStr = (*AI)->getNameAsString();
+ QualType QT = (*AI)->getType();
+ if (convertBlockPointerToFunctionPointer(QT))
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
else
- Result += "\t ,{(struct objc_selector *)\"";
- Result += (*I)->getSelector().getAsString();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\"}\n";
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
+ S += ParamStr;
}
- Result += "\t }\n};\n";
+ if (FT->isVariadic()) {
+ if (!BD->param_empty()) S += ", ";
+ S += "...";
+ }
+ S += ')';
}
+ S += " {\n";
- // Output class methods declared in this protocol.
- unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
- PDecl->classmeth_end());
- if (NumMethods > 0) {
- /* struct _objc_protocol_method_list {
- int protocol_method_count;
- struct protocol_methods protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tint protocol_method_count;\n";
- Result += "\tstruct _protocol_methods protocol_methods[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
- "{\n\t";
- Result += utostr(NumMethods);
- Result += "\n";
-
- // Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I) {
- if (I == PDecl->classmeth_begin())
- Result += "\t ,{{(struct objc_selector *)\"";
- else
- Result += "\t ,{(struct objc_selector *)\"";
- Result += (*I)->getSelector().getAsString();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\"}\n";
+ // Create local declarations to avoid rewriting all closure decl ref exprs.
+ // First, emit a declaration for all "by ref" decls.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ std::string TypeString;
+ RewriteByRefString(TypeString, Name, (*I));
+ TypeString += " *";
+ Name = TypeString + Name;
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedClosure)(void);
+ // myImportedClosure = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherClosure)(void);
+ // anotherClosure = ^(void) {
+ // myImportedClosure(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ RewriteBlockPointerTypeVariable(S, (*I));
+ S += " = (";
+ RewriteBlockPointerType(S, (*I)->getType());
+ S += ")";
+ S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
+ }
+ else {
+ std::string Name = (*I)->getNameAsString();
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
+ S += Name + " = __cself->" +
+ (*I)->getNameAsString() + "; // bound by copy\n";
}
- Result += "\t }\n};\n";
}
+ std::string RewrittenStr = RewrittenBlockExprs[CE];
+ const char *cstr = RewrittenStr.c_str();
+ while (*cstr++ != '{') ;
+ S += cstr;
+ S += "\n";
+ return S;
+}
- // Output:
- /* struct _objc_protocol {
- // Objective-C 1.0 extensions
- struct _objc_protocol_extension *isa;
- char *protocol_name;
- struct _objc_protocol **protocol_list;
- struct _objc_protocol_method_list *instance_methods;
- struct _objc_protocol_method_list *class_methods;
- };
- */
- static bool objc_protocol = false;
- if (!objc_protocol) {
- Result += "\nstruct _objc_protocol {\n";
- Result += "\tstruct _objc_protocol_extension *isa;\n";
- Result += "\tchar *protocol_name;\n";
- Result += "\tstruct _objc_protocol **protocol_list;\n";
- Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
- Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
- Result += "};\n";
-
- objc_protocol = true;
- }
+std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ StringRef funcName,
+ std::string Tag) {
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static void __";
- Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
- "{\n\t0, \"";
- Result += PDecl->getNameAsString();
- Result += "\", 0, ";
- if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
- Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
- Result += PDecl->getNameAsString();
- Result += ", ";
+ S += funcName;
+ S += "_block_copy_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*dst, " + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
+ S += "_Block_object_assign((void*)&dst->";
+ S += (*I)->getNameAsString();
+ S += ", (void*)src->";
+ S += (*I)->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
- else
- Result += "0, ";
- if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {
- Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
- Result += PDecl->getNameAsString();
- Result += "\n";
+ S += "}\n";
+
+ S += "\nstatic void __";
+ S += funcName;
+ S += "_block_dispose_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
+ S += "_Block_object_dispose((void*)src->";
+ S += (*I)->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
- else
- Result += "0\n";
- Result += "};\n";
-
- // Mark this protocol as having been generated.
- if (!ObjCSynthesizedProtocols.insert(PDecl))
- llvm_unreachable("protocol already synthesized");
-
+ S += "}\n";
+ return S;
}
-void RewriteObjC::
-RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
- StringRef prefix, StringRef ClassName,
- std::string &Result) {
- if (Protocols.empty()) return;
+std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ std::string Desc) {
+ std::string S = "\nstruct " + Tag;
+ std::string Constructor = " " + Tag;
- for (unsigned i = 0; i != Protocols.size(); i++)
- RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);
+ S += " {\n struct __block_impl impl;\n";
+ S += " struct " + Desc;
+ S += "* Desc;\n";
- // Output the top lovel protocol meta-data for the class.
- /* struct _objc_protocol_list {
- struct _objc_protocol_list *next;
- int protocol_count;
- struct _objc_protocol *class_protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tstruct _objc_protocol_list *next;\n";
- Result += "\tint protocol_count;\n";
- Result += "\tstruct _objc_protocol *class_protocols[";
- Result += utostr(Protocols.size());
- Result += "];\n} _OBJC_";
- Result += prefix;
- Result += "_PROTOCOLS_";
- Result += ClassName;
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
- "{\n\t0, ";
- Result += utostr(Protocols.size());
- Result += "\n";
+ Constructor += "(void *fp, "; // Invoke function pointer.
+ Constructor += "struct " + Desc; // Descriptor pointer.
+ Constructor += " *desc";
- Result += "\t,{&_OBJC_PROTOCOL_";
- Result += Protocols[0]->getNameAsString();
- Result += " \n";
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(FieldName, Context->getPrintingPolicy());
+ QT.getAsStringInternal(ArgName, Context->getPrintingPolicy());
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ {
+ std::string TypeString;
+ RewriteByRefString(TypeString, FieldName, (*I));
+ TypeString += " *";
+ FieldName = TypeString + FieldName;
+ ArgName = TypeString + ArgName;
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ Constructor += ", int flags=0)";
+ // Initialize all "by copy" arguments.
+ bool firsTime = true;
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ if (firsTime) {
+ Constructor += " : ";
+ firsTime = false;
+ }
+ else
+ Constructor += ", ";
+ if (isTopLevelBlockPointerType((*I)->getType()))
+ Constructor += Name + "((struct __block_impl *)_" + Name + ")";
+ else
+ Constructor += Name + "(_" + Name + ")";
+ }
+ // Initialize all "by ref" arguments.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ if (firsTime) {
+ Constructor += " : ";
+ firsTime = false;
+ }
+ else
+ Constructor += ", ";
+ Constructor += Name + "(_" + Name + "->__forwarding)";
+ }
+
+ Constructor += " {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
- for (unsigned i = 1; i != Protocols.size(); i++) {
- Result += "\t ,&_OBJC_PROTOCOL_";
- Result += Protocols[i]->getNameAsString();
- Result += "\n";
+ Constructor += " Desc = desc;\n";
+ } else {
+ // Finish writing the constructor.
+ Constructor += ", int flags=0) {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ Constructor += " Desc = desc;\n";
}
- Result += "\t }\n};\n";
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
}
+std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
+ std::string ImplTag, int i,
+ StringRef FunName,
+ unsigned hasCopy) {
+ std::string S = "\nstatic struct " + DescTag;
+
+ S += " {\n unsigned long reserved;\n";
+ S += " unsigned long Block_size;\n";
+ if (hasCopy) {
+ S += " void (*copy)(struct ";
+ S += ImplTag; S += "*, struct ";
+ S += ImplTag; S += "*);\n";
+
+ S += " void (*dispose)(struct ";
+ S += ImplTag; S += "*);\n";
+ }
+ S += "} ";
-/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
-/// implementation.
-void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
- std::string &Result) {
- ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
- // Find category declaration for this implementation.
- ObjCCategoryDecl *CDecl;
- for (CDecl = ClassDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->getIdentifier() == IDecl->getIdentifier())
- break;
-
- std::string FullCategoryName = ClassDecl->getNameAsString();
- FullCategoryName += '_';
- FullCategoryName += IDecl->getNameAsString();
-
- // Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+ S += DescTag + "_DATA = { 0, sizeof(struct ";
+ S += ImplTag + ")";
+ if (hasCopy) {
+ S += ", __" + FunName.str() + "_block_copy_" + utostr(i);
+ S += ", __" + FunName.str() + "_block_dispose_" + utostr(i);
+ }
+ S += "};\n";
+ return S;
+}
- // If any of our property implementations have associated getters or
- // setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
- if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- if (!(*Prop)->getPropertyIvarDecl())
- continue;
- ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
- if (!PD)
- continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- InstanceMethods.push_back(Getter);
- if (PD->isReadOnly())
- continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
- InstanceMethods.push_back(Setter);
+void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ StringRef FunName) {
+ // Insert declaration for the function in which block literal is used.
+ if (CurFunctionDeclToDeclareForBlock && !Blocks.empty())
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
+ bool RewriteSC = (GlobalVarDecl &&
+ !Blocks.empty() &&
+ GlobalVarDecl->getStorageClass() == SC_Static &&
+ GlobalVarDecl->getType().getCVRQualifiers());
+ if (RewriteSC) {
+ std::string SC(" void __");
+ SC += GlobalVarDecl->getNameAsString();
+ SC += "() {}";
+ InsertText(FunLocStart, SC);
}
- RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
- true, "CATEGORY_", FullCategoryName.c_str(),
- Result);
+
+ // Insert closures that were part of the function.
+ for (unsigned i = 0, count=0; i < Blocks.size(); i++) {
+ CollectBlockDeclRefInfo(Blocks[i]);
+ // Need to copy-in the inner copied-in variables not actually used in this
+ // block.
+ for (int j = 0; j < InnerDeclRefsCount[i]; j++) {
+ BlockDeclRefExpr *Exp = InnerDeclRefs[count++];
+ ValueDecl *VD = Exp->getDecl();
+ BlockDeclRefs.push_back(Exp);
+ if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) {
+ BlockByCopyDeclsPtrSet.insert(VD);
+ BlockByCopyDecls.push_back(VD);
+ }
+ if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) {
+ BlockByRefDeclsPtrSet.insert(VD);
+ BlockByRefDecls.push_back(VD);
+ }
+ // imported objects in the inner blocks not used in the outer
+ // blocks must be copied/disposed in the outer block as well.
+ if (Exp->isByRef() ||
+ VD->getType()->isObjCObjectPointerType() ||
+ VD->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(VD);
+ }
- // Build _objc_method_list for class's class methods if needed
- RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
- false, "CATEGORY_", FullCategoryName.c_str(),
- Result);
+ std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i);
+ std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i);
- // Protocols referenced in class declaration?
- // Null CDecl is case of a category implementation with no category interface
- if (CDecl)
- RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
- FullCategoryName, Result);
- /* struct _objc_category {
- char *category_name;
- char *class_name;
- struct _objc_method_list *instance_methods;
- struct _objc_method_list *class_methods;
- struct _objc_protocol_list *protocols;
- // Objective-C 1.0 extensions
- uint32_t size; // sizeof (struct _objc_category)
- struct _objc_property_list *instance_properties; // category's own
- // @property decl.
- };
- */
+ std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
- static bool objc_category = false;
- if (!objc_category) {
- Result += "\nstruct _objc_category {\n";
- Result += "\tchar *category_name;\n";
- Result += "\tchar *class_name;\n";
- Result += "\tstruct _objc_method_list *instance_methods;\n";
- Result += "\tstruct _objc_method_list *class_methods;\n";
- Result += "\tstruct _objc_protocol_list *protocols;\n";
- Result += "\tunsigned int size;\n";
- Result += "\tstruct _objc_property_list *instance_properties;\n";
- Result += "};\n";
- objc_category = true;
- }
- Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
- Result += FullCategoryName;
- Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
- Result += IDecl->getNameAsString();
- Result += "\"\n\t, \"";
- Result += ClassDecl->getNameAsString();
- Result += "\"\n";
+ InsertText(FunLocStart, CI);
- if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
- Result += "\t, (struct _objc_method_list *)"
- "&_OBJC_CATEGORY_INSTANCE_METHODS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
- if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
- Result += "\t, (struct _objc_method_list *)"
- "&_OBJC_CATEGORY_CLASS_METHODS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
- if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
- Result += "\t, sizeof(struct _objc_category), 0\n};\n";
-}
+ InsertText(FunLocStart, CF);
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
-/// ivar offset.
-void RewriteObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
- std::string &Result) {
- if (ivar->isBitField()) {
- // FIXME: The hack below doesn't work for bitfields. For now, we simply
- // place all bitfields at offset 0.
- Result += "0";
- } else {
- Result += "__OFFSETOFIVAR__(struct ";
- Result += ivar->getContainingInterface()->getNameAsString();
- if (LangOpts.MicrosoftExt)
- Result += "_IMPL";
- Result += ", ";
- Result += ivar->getNameAsString();
- Result += ")";
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
+ InsertText(FunLocStart, HF);
+ }
+ std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
+ ImportedBlockDecls.size() > 0);
+ InsertText(FunLocStart, BD);
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
+ BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
+ ImportedBlockDecls.clear();
+ }
+ if (RewriteSC) {
+ // Must insert any 'const/volatile/static here. Since it has been
+ // removed as result of rewriting of block literals.
+ std::string SC;
+ if (GlobalVarDecl->getStorageClass() == SC_Static)
+ SC = "static ";
+ if (GlobalVarDecl->getType().isConstQualified())
+ SC += "const ";
+ if (GlobalVarDecl->getType().isVolatileQualified())
+ SC += "volatile ";
+ if (GlobalVarDecl->getType().isRestrictQualified())
+ SC += "restrict ";
+ InsertText(FunLocStart, SC);
}
+
+ Blocks.clear();
+ InnerDeclRefsCount.clear();
+ InnerDeclRefs.clear();
+ RewrittenBlockExprs.clear();
}
-//===----------------------------------------------------------------------===//
-// Meta Data Emission
-//===----------------------------------------------------------------------===//
+void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ StringRef FuncName = FD->getName();
-void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
- std::string &Result) {
- ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
- // Explicitly declared @interface's are already synthesized.
- if (CDecl->isImplicitInterfaceDecl()) {
- // FIXME: Implementation of a class with no @interface (legacy) doese not
- // produce correct synthesis as yet.
- RewriteObjCInternalStruct(CDecl, Result);
- }
+static void BuildUniqueMethodName(std::string &Name,
+ ObjCMethodDecl *MD) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ Name = IFace->getName();
+ Name += "__" + MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = Name.find(":", loc)) != std::string::npos)
+ Name.replace(loc, 1, "_");
+}
- // Build _objc_ivar_list metadata for classes ivars if needed
- unsigned NumIvars = !IDecl->ivar_empty()
- ? IDecl->ivar_size()
- : (CDecl ? CDecl->ivar_size() : 0);
- if (NumIvars > 0) {
- static bool objc_ivar = false;
- if (!objc_ivar) {
- /* struct _objc_ivar {
- char *ivar_name;
- char *ivar_type;
- int ivar_offset;
- };
- */
- Result += "\nstruct _objc_ivar {\n";
- Result += "\tchar *ivar_name;\n";
- Result += "\tchar *ivar_type;\n";
- Result += "\tint ivar_offset;\n";
- Result += "};\n";
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName;
+ BuildUniqueMethodName(FuncName, MD);
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
- objc_ivar = true;
+void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockDeclRefExprs(CBE->getBody());
+ else
+ GetBlockDeclRefExprs(*CI);
+ }
+ // Handle specific things.
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ // FIXME: Handle enums.
+ if (!isa<FunctionDecl>(CDRE->getDecl()))
+ BlockDeclRefs.push_back(CDRE);
+ }
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
+ if (HasLocalVariableExternalStorage(DRE->getDecl())) {
+ BlockDeclRefExpr *BDRE =
+ new (Context)BlockDeclRefExpr(cast<VarDecl>(DRE->getDecl()),
+ DRE->getType(),
+ VK_LValue, DRE->getLocation(), false);
+ BlockDeclRefs.push_back(BDRE);
}
+
+ return;
+}
- /* struct {
- int ivar_count;
- struct _objc_ivar ivar_list[nIvars];
- };
- */
- Result += "\nstatic struct {\n";
- Result += "\tint ivar_count;\n";
- Result += "\tstruct _objc_ivar ivar_list[";
- Result += utostr(NumIvars);
- Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
- Result += IDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
- "{\n\t";
- Result += utostr(NumIvars);
- Result += "\n";
+void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
+ llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
+ InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl()));
+ GetInnerBlockDeclRefExprs(CBE->getBody(),
+ InnerBlockDeclRefs,
+ InnerContexts);
+ }
+ else
+ GetInnerBlockDeclRefExprs(*CI,
+ InnerBlockDeclRefs,
+ InnerContexts);
- ObjCInterfaceDecl::ivar_iterator IVI, IVE;
- SmallVector<ObjCIvarDecl *, 8> IVars;
- if (!IDecl->ivar_empty()) {
- for (ObjCInterfaceDecl::ivar_iterator
- IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
- IV != IVEnd; ++IV)
- IVars.push_back(*IV);
- IVI = IDecl->ivar_begin();
- IVE = IDecl->ivar_end();
- } else {
- IVI = CDecl->ivar_begin();
- IVE = CDecl->ivar_end();
- }
- Result += "\t,{{\"";
- Result += (*IVI)->getNameAsString();
- Result += "\", \"";
- std::string TmpString, StrEncoding;
- Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
- QuoteDoublequotes(TmpString, StrEncoding);
- Result += StrEncoding;
- Result += "\", ";
- RewriteIvarOffsetComputation(*IVI, Result);
- Result += "}\n";
- for (++IVI; IVI != IVE; ++IVI) {
- Result += "\t ,{\"";
- Result += (*IVI)->getNameAsString();
- Result += "\", \"";
- std::string TmpString, StrEncoding;
- Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
- QuoteDoublequotes(TmpString, StrEncoding);
- Result += StrEncoding;
- Result += "\", ";
- RewriteIvarOffsetComputation((*IVI), Result);
- Result += "}\n";
}
+ // Handle specific things.
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (!isa<FunctionDecl>(CDRE->getDecl()) &&
+ !InnerContexts.count(CDRE->getDecl()->getDeclContext()))
+ InnerBlockDeclRefs.push_back(CDRE);
+ }
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (Var->isFunctionOrMethodVarDecl())
+ ImportedLocalExternalDecls.insert(Var);
+ }
+
+ return;
+}
- Result += "\t }\n};\n";
+/// convertFunctionTypeOfBlocks - This routine converts a function type
+/// whose result type may be a block pointer or whose argument type(s)
+/// might be block pointers to an equivalent function type replacing
+/// all block pointers to function pointers.
+QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+ // Generate a funky cast.
+ SmallVector<QualType, 8> ArgTypes;
+ QualType Res = FT->getResultType();
+ bool HasBlockType = convertBlockPointerToFunctionPointer(Res);
+
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (convertBlockPointerToFunctionPointer(t))
+ HasBlockType = true;
+ ArgTypes.push_back(t);
+ }
}
+ QualType FuncType;
+ // FIXME. Does this work if block takes no argument but has a return type
+ // which is of block type?
+ if (HasBlockType)
+ FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ else FuncType = QualType(FT, 0);
+ return FuncType;
+}
- // Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
+ // Navigate to relevant type information.
+ const BlockPointerType *CPT = 0;
- // If any of our property implementations have associated getters or
- // setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
- if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- if (!(*Prop)->getPropertyIvarDecl())
- continue;
- ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
- if (!PD)
- continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- if (!Getter->isDefined())
- InstanceMethods.push_back(Getter);
- if (PD->isReadOnly())
- continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
- if (!Setter->isDefined())
- InstanceMethods.push_back(Setter);
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
+ CPT = DRE->getType()->getAs<BlockPointerType>();
+ } else if (const BlockDeclRefExpr *CDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockExp)) {
+ CPT = CDRE->getType()->getAs<BlockPointerType>();
+ } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {
+ CPT = MExpr->getType()->getAs<BlockPointerType>();
+ }
+ else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) {
+ return SynthesizeBlockCall(Exp, PRE->getSubExpr());
}
- RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
- true, "", IDecl->getName(), Result);
+ else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp))
+ CPT = IEXPR->getType()->getAs<BlockPointerType>();
+ else if (const ConditionalOperator *CEXPR =
+ dyn_cast<ConditionalOperator>(BlockExp)) {
+ Expr *LHSExp = CEXPR->getLHS();
+ Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp);
+ Expr *RHSExp = CEXPR->getRHS();
+ Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
+ Expr *CONDExp = CEXPR->getCond();
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(CONDExp,
+ SourceLocation(), cast<Expr>(LHSStmt),
+ SourceLocation(), cast<Expr>(RHSStmt),
+ Exp->getType(), VK_RValue, OK_Ordinary);
+ return CondExpr;
+ } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
+ CPT = IRE->getType()->getAs<BlockPointerType>();
+ } else if (const PseudoObjectExpr *POE
+ = dyn_cast<PseudoObjectExpr>(BlockExp)) {
+ CPT = POE->getType()->castAs<BlockPointerType>();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
- // Build _objc_method_list for class's class methods if needed
- RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
- false, "", IDecl->getName(), Result);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__block_impl"));
+ QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
- // Protocols referenced in class declaration?
- RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),
- "CLASS", CDecl->getName(), Result);
+ // Generate a funky cast.
+ SmallVector<QualType, 8> ArgTypes;
- // Declaration of class/meta-class metadata
- /* struct _objc_class {
- struct _objc_class *isa; // or const char *root_class_name when metadata
- const char *super_class_name;
- char *name;
- long version;
- long info;
- long instance_size;
- struct _objc_ivar_list *ivars;
- struct _objc_method_list *methods;
- struct objc_cache *cache;
- struct objc_protocol_list *protocols;
- const char *ivar_layout;
- struct _objc_class_ext *ext;
- };
- */
- static bool objc_class = false;
- if (!objc_class) {
- Result += "\nstruct _objc_class {\n";
- Result += "\tstruct _objc_class *isa;\n";
- Result += "\tconst char *super_class_name;\n";
- Result += "\tchar *name;\n";
- Result += "\tlong version;\n";
- Result += "\tlong info;\n";
- Result += "\tlong instance_size;\n";
- Result += "\tstruct _objc_ivar_list *ivars;\n";
- Result += "\tstruct _objc_method_list *methods;\n";
- Result += "\tstruct objc_cache *cache;\n";
- Result += "\tstruct _objc_protocol_list *protocols;\n";
- Result += "\tconst char *ivar_layout;\n";
- Result += "\tstruct _objc_class_ext *ext;\n";
- Result += "};\n";
- objc_class = true;
+ // Push the block argument type.
+ ArgTypes.push_back(PtrBlock);
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (!convertBlockPointerToFunctionPointer(t))
+ convertToUnqualifiedObjCType(t);
+ ArgTypes.push_back(t);
+ }
}
+ // Now do the pointer to function cast.
+ QualType PtrToFuncCastType
+ = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
- // Meta-class metadata generation.
- ObjCInterfaceDecl *RootClass = 0;
- ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
- while (SuperClass) {
- RootClass = SuperClass;
- SuperClass = SuperClass->getSuperClass();
- }
- SuperClass = CDecl->getSuperClass();
+ PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
- Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
- Result += CDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
- "{\n\t(struct _objc_class *)\"";
- Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
- Result += "\"";
+ CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,
+ CK_BitCast,
+ const_cast<Expr*>(BlockExp));
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ BlkCast);
+ //PE->dump();
- if (SuperClass) {
- Result += ", \"";
- Result += SuperClass->getNameAsString();
- Result += "\", \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- else {
- Result += ", 0, \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
- // 'info' field is initialized to CLS_META(2) for metaclass
- Result += ", 0,2, sizeof(struct _objc_class), 0";
- if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
- Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
- Result += IDecl->getNameAsString();
- Result += "\n";
- }
- else
- Result += ", 0\n";
- if (CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
- Result += CDecl->getNameAsString();
- Result += ",0,0\n";
- }
- else
- Result += "\t,0,0,0,0\n";
- Result += "};\n";
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("FuncPtr"),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
- // class metadata generation.
- Result += "\nstatic struct _objc_class _OBJC_CLASS_";
- Result += CDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
- "{\n\t&_OBJC_METACLASS_";
- Result += CDecl->getNameAsString();
- if (SuperClass) {
- Result += ", \"";
- Result += SuperClass->getNameAsString();
- Result += "\", \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- else {
- Result += ", 0, \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- // 'info' field is initialized to CLS_CLASS(1) for class
- Result += ", 0,1";
- if (!ObjCSynthesizedStructs.count(CDecl))
- Result += ",0";
- else {
- // class has size. Must synthesize its size.
- Result += ",sizeof(struct ";
- Result += CDecl->getNameAsString();
- if (LangOpts.MicrosoftExt)
- Result += "_IMPL";
- Result += ")";
- }
- if (NumIvars > 0) {
- Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
- Result += CDecl->getNameAsString();
- Result += "\n\t";
- }
- else
- Result += ",0";
- if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
- Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
- Result += CDecl->getNameAsString();
- Result += ", 0\n\t";
- }
- else
- Result += ",0,0";
- if (CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
- Result += CDecl->getNameAsString();
- Result += ", 0,0\n";
+
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CK_BitCast, ME);
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+
+ SmallVector<Expr*, 8> BlkExprs;
+ // Add the implicit argument.
+ BlkExprs.push_back(BlkCast);
+ // Add the user arguments.
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ BlkExprs.push_back(*I);
}
- else
- Result += ",0,0,0\n";
- Result += "};\n";
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
+ BlkExprs.size(),
+ Exp->getType(), VK_RValue,
+ SourceLocation());
+ return CE;
}
-/// RewriteImplementations - This routine rewrites all method implementations
-/// and emits meta-data.
-
-void RewriteObjC::RewriteImplementations() {
- int ClsDefCount = ClassImplementation.size();
- int CatDefCount = CategoryImplementation.size();
-
- // Rewrite implemented methods
- for (int i = 0; i < ClsDefCount; i++)
- RewriteImplementationDecl(ClassImplementation[i]);
-
- for (int i = 0; i < CatDefCount; i++)
- RewriteImplementationDecl(CategoryImplementation[i]);
-}
+// We need to return the rewritten expression to handle cases where the
+// BlockDeclRefExpr is embedded in another expression being rewritten.
+// For example:
+//
+// int main() {
+// __block Foo *f;
+// __block int i;
+//
+// void (^myblock)() = ^() {
+// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten).
+// i = 77;
+// };
+//}
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
+ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
+ // for each DeclRefExp where BYREFVAR is name of the variable.
+ ValueDecl *VD;
+ bool isArrow = true;
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
+ VD = BDRE->getDecl();
+ else {
+ VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
+ isArrow = false;
+ }
+
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("__forwarding"),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
+ FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
-void RewriteObjC::RewriteMetaDataIntoBuffer(std::string &Result) {
- int ClsDefCount = ClassImplementation.size();
- int CatDefCount = CategoryImplementation.size();
+ StringRef Name = VD->getName();
+ FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ &Context->Idents.get(Name),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
+ DeclRefExp->getType(), VK_LValue, OK_Ordinary);
- // For each implemented class, write out all its meta data.
- for (int i = 0; i < ClsDefCount; i++)
- RewriteObjCClassMetaData(ClassImplementation[i], Result);
+
+
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
+ ME);
+ ReplaceStmt(DeclRefExp, PE);
+ return PE;
+}
- // For each implemented category, write out all its meta data.
- for (int i = 0; i < CatDefCount; i++)
- RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
+// Rewrites the imported local variable V with external storage
+// (static, extern, etc.) as *V
+//
+Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ if (!ImportedLocalExternalDecls.count(Var))
+ return DRE;
+ Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
+ VK_LValue, OK_Ordinary,
+ DRE->getLocation());
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ Exp);
+ ReplaceStmt(DRE, PE);
+ return PE;
+}
- // Write objc_symtab metadata
- /*
- struct _objc_symtab
- {
- long sel_ref_cnt;
- SEL *refs;
- short cls_def_cnt;
- short cat_def_cnt;
- void *defs[cls_def_cnt + cat_def_cnt];
- };
- */
+void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
+ SourceLocation LocStart = CE->getLParenLoc();
+ SourceLocation LocEnd = CE->getRParenLoc();
- Result += "\nstruct _objc_symtab {\n";
- Result += "\tlong sel_ref_cnt;\n";
- Result += "\tSEL *refs;\n";
- Result += "\tshort cls_def_cnt;\n";
- Result += "\tshort cat_def_cnt;\n";
- Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
- Result += "};\n\n";
+ // Need to avoid trying to rewrite synthesized casts.
+ if (LocStart.isInvalid())
+ return;
+ // Need to avoid trying to rewrite casts contained in macros.
+ if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
+ return;
- Result += "static struct _objc_symtab "
- "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";
- Result += "\t0, 0, " + utostr(ClsDefCount)
- + ", " + utostr(CatDefCount) + "\n";
- for (int i = 0; i < ClsDefCount; i++) {
- Result += "\t,&_OBJC_CLASS_";
- Result += ClassImplementation[i]->getNameAsString();
- Result += "\n";
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ QualType QT = CE->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ std::string TypeAsString = "(";
+ RewriteBlockPointerType(TypeAsString, QT);
+ TypeAsString += ")";
+ ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);
+ return;
}
+ // advance the location to startArgList.
+ const char *argPtr = startBuf;
- for (int i = 0; i < CatDefCount; i++) {
- Result += "\t,&_OBJC_CATEGORY_";
- Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();
- Result += "_";
- Result += CategoryImplementation[i]->getNameAsString();
- Result += "\n";
+ while (*argPtr++ && (argPtr < endBuf)) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*");
+ break;
+ }
}
+ return;
+}
- Result += "};\n\n";
+void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
+ SourceLocation DeclLoc = FD->getLocation();
+ unsigned parenCount = 0;
- // Write objc_module metadata
+ // We have 1 or more arguments that have closure pointers.
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *startArgList = strchr(startBuf, '(');
- /*
- struct _objc_module {
- long version;
- long size;
- const char *name;
- struct _objc_symtab *symtab;
- }
- */
+ assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
- Result += "\nstruct _objc_module {\n";
- Result += "\tlong version;\n";
- Result += "\tlong size;\n";
- Result += "\tconst char *name;\n";
- Result += "\tstruct _objc_symtab *symtab;\n";
- Result += "};\n\n";
- Result += "static struct _objc_module "
- "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
- Result += "\t" + utostr(OBJC_ABI_VERSION) +
- ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
- Result += "};\n\n";
+ parenCount++;
+ // advance the location to startArgList.
+ DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf);
+ assert((DeclLoc.isValid()) && "Invalid DeclLoc");
- if (LangOpts.MicrosoftExt) {
- if (ProtocolExprDecls.size()) {
- Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
- Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I) {
- Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
- Result += " = &_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
- Result += ";\n";
- }
- Result += "#pragma data_seg(pop)\n\n";
+ const char *argPtr = startArgList;
+
+ while (*argPtr++ && parenCount) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*");
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
}
- Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";
- Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";
- Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";
- Result += "&_OBJC_MODULES;\n";
- Result += "#pragma data_seg(pop)\n\n";
}
+ return;
}
-void RewriteObjC::RewriteByRefString(std::string &ResultStr,
- const std::string &Name,
- ValueDecl *VD, bool def) {
- assert(BlockByRefDeclNo.count(VD) &&
- "RewriteByRefString: ByRef decl missing");
- if (def)
- ResultStr += "struct ";
- ResultStr += "__Block_byref_" + Name +
- "_" + utostr(BlockByRefDeclNo[VD]) ;
-}
-
-static bool HasLocalVariableExternalStorage(ValueDecl *VD) {
- if (VarDecl *Var = dyn_cast<VarDecl>(VD))
- return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage());
+bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAs<PointerType>();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
+ } else {
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isTopLevelBlockPointerType(*I))
+ return true;
+ }
return false;
}
-std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
- StringRef funcName,
- std::string Tag) {
- const FunctionType *AFT = CE->getFunctionType();
- QualType RT = AFT->getResultType();
- std::string StructRef = "struct " + Tag;
- std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
- funcName.str() + "_" + "block_func_" + utostr(i);
-
- BlockDecl *BD = CE->getBlockDecl();
-
- if (isa<FunctionNoProtoType>(AFT)) {
- // No user-supplied arguments. Still need to pass in a pointer to the
- // block (to reference imported block decl refs).
- S += "(" + StructRef + " *__cself)";
- } else if (BD->param_empty()) {
- S += "(" + StructRef + " *__cself)";
+bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAs<PointerType>();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
} else {
- const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
- assert(FT && "SynthesizeBlockFunc: No function proto");
- S += '(';
- // first add the implicit argument.
- S += StructRef + " *__cself, ";
- std::string ParamStr;
- for (BlockDecl::param_iterator AI = BD->param_begin(),
- E = BD->param_end(); AI != E; ++AI) {
- if (AI != BD->param_begin()) S += ", ";
- ParamStr = (*AI)->getNameAsString();
- QualType QT = (*AI)->getType();
- if (convertBlockPointerToFunctionPointer(QT))
- QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
- else
- QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
- S += ParamStr;
- }
- if (FT->isVariadic()) {
- if (!BD->param_empty()) S += ", ";
- S += "...";
- }
- S += ')';
- }
- S += " {\n";
-
- // Create local declarations to avoid rewriting all closure decl ref exprs.
- // First, emit a declaration for all "by ref" decls.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- S += " ";
- std::string Name = (*I)->getNameAsString();
- std::string TypeString;
- RewriteByRefString(TypeString, Name, (*I));
- TypeString += " *";
- Name = TypeString + Name;
- S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
- // Next, emit a declaration for all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- S += " ";
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedClosure)(void);
- // myImportedClosure = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherClosure)(void);
- // anotherClosure = ^(void) {
- // myImportedClosure(); // import and invoke the closure
- // };
- //
- if (isTopLevelBlockPointerType((*I)->getType())) {
- RewriteBlockPointerTypeVariable(S, (*I));
- S += " = (";
- RewriteBlockPointerType(S, (*I)->getType());
- S += ")";
- S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
- }
- else {
- std::string Name = (*I)->getNameAsString();
- QualType QT = (*I)->getType();
- if (HasLocalVariableExternalStorage(*I))
- QT = Context->getPointerType(QT);
- QT.getAsStringInternal(Name, Context->getPrintingPolicy());
- S += Name + " = __cself->" +
- (*I)->getNameAsString() + "; // bound by copy\n";
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I) {
+ if ((*I)->isObjCQualifiedIdType())
+ return true;
+ if ((*I)->isObjCObjectPointerType() &&
+ (*I)->getPointeeType()->isObjCQualifiedInterfaceType())
+ return true;
}
+
}
- std::string RewrittenStr = RewrittenBlockExprs[CE];
- const char *cstr = RewrittenStr.c_str();
- while (*cstr++ != '{') ;
- S += cstr;
- S += "\n";
- return S;
+ return false;
}
-std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
- StringRef funcName,
- std::string Tag) {
- std::string StructRef = "struct " + Tag;
- std::string S = "static void __";
+void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen,
+ const char *&RParen) {
+ const char *argPtr = strchr(Name, '(');
+ assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
- S += funcName;
- S += "_block_copy_" + utostr(i);
- S += "(" + StructRef;
- S += "*dst, " + StructRef;
- S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
- S += "_Block_object_assign((void*)&dst->";
- S += (*I)->getNameAsString();
- S += ", (void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
- S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
- else if (VD->getType()->isBlockPointerType())
- S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
- else
- S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
- }
- S += "}\n";
-
- S += "\nstatic void __";
- S += funcName;
- S += "_block_dispose_" + utostr(i);
- S += "(" + StructRef;
- S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
- S += "_Block_object_dispose((void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
- S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
- else if (VD->getType()->isBlockPointerType())
- S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
- else
- S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
+ LParen = argPtr; // output the start.
+ argPtr++; // skip past the left paren.
+ unsigned parenCount = 1;
+
+ while (*argPtr && parenCount) {
+ switch (*argPtr) {
+ case '(': parenCount++; break;
+ case ')': parenCount--; break;
+ default: break;
+ }
+ if (parenCount) argPtr++;
}
- S += "}\n";
- return S;
+ assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
+ RParen = argPtr; // output the end
}
-std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
- std::string Desc) {
- std::string S = "\nstruct " + Tag;
- std::string Constructor = " " + Tag;
-
- S += " {\n struct __block_impl impl;\n";
- S += " struct " + Desc;
- S += "* Desc;\n";
-
- Constructor += "(void *fp, "; // Invoke function pointer.
- Constructor += "struct " + Desc; // Descriptor pointer.
- Constructor += " *desc";
-
- if (BlockDeclRefs.size()) {
- // Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- S += " ";
- std::string FieldName = (*I)->getNameAsString();
- std::string ArgName = "_" + FieldName;
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedBlock)(void);
- // myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherBlock)(void);
- // anotherBlock = ^(void) {
- // myImportedBlock(); // import and invoke the closure
- // };
- //
- if (isTopLevelBlockPointerType((*I)->getType())) {
- S += "struct __block_impl *";
- Constructor += ", void *" + ArgName;
- } else {
- QualType QT = (*I)->getType();
- if (HasLocalVariableExternalStorage(*I))
- QT = Context->getPointerType(QT);
- QT.getAsStringInternal(FieldName, Context->getPrintingPolicy());
- QT.getAsStringInternal(ArgName, Context->getPrintingPolicy());
- Constructor += ", " + ArgName;
- }
- S += FieldName + ";\n";
- }
- // Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- S += " ";
- std::string FieldName = (*I)->getNameAsString();
- std::string ArgName = "_" + FieldName;
- {
- std::string TypeString;
- RewriteByRefString(TypeString, FieldName, (*I));
- TypeString += " *";
- FieldName = TypeString + FieldName;
- ArgName = TypeString + ArgName;
- Constructor += ", " + ArgName;
- }
- S += FieldName + "; // by ref\n";
- }
- // Finish writing the constructor.
- Constructor += ", int flags=0)";
- // Initialize all "by copy" arguments.
- bool firsTime = true;
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- std::string Name = (*I)->getNameAsString();
- if (firsTime) {
- Constructor += " : ";
- firsTime = false;
+void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ RewriteBlockPointerFunctionArgs(FD);
+ return;
+ }
+ // Handle Variables and Typedefs.
+ SourceLocation DeclLoc = ND->getLocation();
+ QualType DeclT;
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ DeclT = VD->getType();
+ else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND))
+ DeclT = TDD->getUnderlyingType();
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ DeclT = FD->getType();
+ else
+ llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled");
+
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *endBuf = startBuf;
+ // scan backward (from the decl location) for the end of the previous decl.
+ while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
+ startBuf--;
+ SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf);
+ std::string buf;
+ unsigned OrigLength=0;
+ // *startBuf != '^' if we are dealing with a pointer to function that
+ // may take block argument types (which will be handled below).
+ if (*startBuf == '^') {
+ // Replace the '^' with '*', computing a negative offset.
+ buf = '*';
+ startBuf++;
+ OrigLength++;
+ }
+ while (*startBuf != ')') {
+ buf += *startBuf;
+ startBuf++;
+ OrigLength++;
+ }
+ buf += ')';
+ OrigLength++;
+
+ if (PointerTypeTakesAnyBlockArguments(DeclT) ||
+ PointerTypeTakesAnyObjCQualifiedType(DeclT)) {
+ // Replace the '^' with '*' for arguments.
+ // Replace id<P> with id/*<>*/
+ DeclLoc = ND->getLocation();
+ startBuf = SM->getCharacterData(DeclLoc);
+ const char *argListBegin, *argListEnd;
+ GetExtentOfArgList(startBuf, argListBegin, argListEnd);
+ while (argListBegin < argListEnd) {
+ if (*argListBegin == '^')
+ buf += '*';
+ else if (*argListBegin == '<') {
+ buf += "/*";
+ buf += *argListBegin++;
+ OrigLength++;;
+ while (*argListBegin != '>') {
+ buf += *argListBegin++;
+ OrigLength++;
}
- else
- Constructor += ", ";
- if (isTopLevelBlockPointerType((*I)->getType()))
- Constructor += Name + "((struct __block_impl *)_" + Name + ")";
- else
- Constructor += Name + "(_" + Name + ")";
- }
- // Initialize all "by ref" arguments.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- std::string Name = (*I)->getNameAsString();
- if (firsTime) {
- Constructor += " : ";
- firsTime = false;
+ buf += *argListBegin;
+ buf += "*/";
}
else
- Constructor += ", ";
- Constructor += Name + "(_" + Name + "->__forwarding)";
+ buf += *argListBegin;
+ argListBegin++;
+ OrigLength++;
}
-
- Constructor += " {\n";
- if (GlobalVarDecl)
- Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
- else
- Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
- Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
-
- Constructor += " Desc = desc;\n";
- } else {
- // Finish writing the constructor.
- Constructor += ", int flags=0) {\n";
- if (GlobalVarDecl)
- Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
- else
- Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
- Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
- Constructor += " Desc = desc;\n";
+ buf += ')';
+ OrigLength++;
}
- Constructor += " ";
- Constructor += "}\n";
- S += Constructor;
- S += "};\n";
- return S;
+ ReplaceText(Start, OrigLength, buf);
+
+ return;
}
-std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
- std::string ImplTag, int i,
- StringRef FunName,
- unsigned hasCopy) {
- std::string S = "\nstatic struct " + DescTag;
-
- S += " {\n unsigned long reserved;\n";
- S += " unsigned long Block_size;\n";
- if (hasCopy) {
- S += " void (*copy)(struct ";
- S += ImplTag; S += "*, struct ";
- S += ImplTag; S += "*);\n";
-
- S += " void (*dispose)(struct ";
- S += ImplTag; S += "*);\n";
- }
- S += "} ";
- S += DescTag + "_DATA = { 0, sizeof(struct ";
- S += ImplTag + ")";
- if (hasCopy) {
- S += ", __" + FunName.str() + "_block_copy_" + utostr(i);
- S += ", __" + FunName.str() + "_block_dispose_" + utostr(i);
- }
- S += "};\n";
+/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:
+/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,
+/// struct Block_byref_id_object *src) {
+/// _Block_object_assign (&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_assign(&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+/// And:
+/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+
+std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
+ int flag) {
+ std::string S;
+ if (CopyDestroyCache.count(flag))
+ return S;
+ CopyDestroyCache.insert(flag);
+ S = "static void __Block_byref_id_object_copy_";
+ S += utostr(flag);
+ S += "(void *dst, void *src) {\n";
+
+ // offset into the object pointer is computed as:
+ // void * + void* + int + int + void* + void *
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ unsigned VoidPtrSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
+
+ unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth();
+ S += " _Block_object_assign((char*)dst + ";
+ S += utostr(offset);
+ S += ", *(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+
+ S += "static void __Block_byref_id_object_dispose_";
+ S += utostr(flag);
+ S += "(void *src) {\n";
+ S += " _Block_object_dispose(*(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
return S;
}
-void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
- StringRef FunName) {
- // Insert declaration for the function in which block literal is used.
- if (CurFunctionDeclToDeclareForBlock && !Blocks.empty())
- RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
- bool RewriteSC = (GlobalVarDecl &&
- !Blocks.empty() &&
- GlobalVarDecl->getStorageClass() == SC_Static &&
- GlobalVarDecl->getType().getCVRQualifiers());
- if (RewriteSC) {
- std::string SC(" void __");
- SC += GlobalVarDecl->getNameAsString();
- SC += "() {}";
- InsertText(FunLocStart, SC);
- }
+/// RewriteByRefVar - For each __block typex ND variable this routine transforms
+/// the declaration into:
+/// struct __Block_byref_ND {
+/// void *__isa; // NULL for everything except __weak pointers
+/// struct __Block_byref_ND *__forwarding;
+/// int32_t __flags;
+/// int32_t __size;
+/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object
+/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object
+/// typex ND;
+/// };
+///
+/// It then replaces declaration of ND variable with:
+/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag,
+/// __size=sizeof(struct __Block_byref_ND),
+/// ND=initializer-if-any};
+///
+///
+void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
+ // Insert declaration for the function in which block literal is
+ // used.
+ if (CurFunctionDeclToDeclareForBlock)
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
+ int flag = 0;
+ int isa = 0;
+ SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
+ if (DeclLoc.isInvalid())
+ // If type location is missing, it is because of missing type (a warning).
+ // Use variable's location which is good for this case.
+ DeclLoc = ND->getLocation();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getExpansionLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ std::string Name(ND->getNameAsString());
+ std::string ByrefType;
+ RewriteByRefString(ByrefType, Name, ND, true);
+ ByrefType += " {\n";
+ ByrefType += " void *__isa;\n";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += " *__forwarding;\n";
+ ByrefType += " int __flags;\n";
+ ByrefType += " int __size;\n";
+ // Add void *__Block_byref_id_object_copy;
+ // void *__Block_byref_id_object_dispose; if needed.
+ QualType Ty = ND->getType();
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
+ ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
+ }
+
+ QualType T = Ty;
+ (void)convertBlockPointerToFunctionPointer(T);
+ T.getAsStringInternal(Name, Context->getPrintingPolicy());
+
+ ByrefType += " " + Name + ";\n";
+ ByrefType += "};\n";
+ // Insert this type in global scope. It is needed by helper function.
+ SourceLocation FunLocStart;
+ if (CurFunctionDef)
+ FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
+ else {
+ assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
+ FunLocStart = CurMethodDef->getLocStart();
+ }
+ InsertText(FunLocStart, ByrefType);
+ if (Ty.isObjCGCWeak()) {
+ flag |= BLOCK_FIELD_IS_WEAK;
+ isa = 1;
+ }
- // Insert closures that were part of the function.
- for (unsigned i = 0, count=0; i < Blocks.size(); i++) {
- CollectBlockDeclRefInfo(Blocks[i]);
- // Need to copy-in the inner copied-in variables not actually used in this
- // block.
- for (int j = 0; j < InnerDeclRefsCount[i]; j++) {
- BlockDeclRefExpr *Exp = InnerDeclRefs[count++];
+ if (HasCopyAndDispose) {
+ flag = BLOCK_BYREF_CALLER;
+ QualType Ty = ND->getType();
+ // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.
+ if (Ty->isBlockPointerType())
+ flag |= BLOCK_FIELD_IS_BLOCK;
+ else
+ flag |= BLOCK_FIELD_IS_OBJECT;
+ std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
+ if (!HF.empty())
+ InsertText(FunLocStart, HF);
+ }
+
+ // struct __Block_byref_ND ND =
+ // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
+ // initializer-if-any};
+ bool hasInit = (ND->getInit() != 0);
+ unsigned flags = 0;
+ if (HasCopyAndDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+ Name = ND->getNameAsString();
+ ByrefType.clear();
+ RewriteByRefString(ByrefType, Name, ND);
+ std::string ForwardingCastType("(");
+ ForwardingCastType += ByrefType + " *)";
+ if (!hasInit) {
+ ByrefType += " " + Name + " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += ")";
+ if (HasCopyAndDispose) {
+ ByrefType += ", __Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ }
+ ByrefType += "};\n";
+ unsigned nameSize = Name.size();
+ // for block or function pointer declaration. Name is aleady
+ // part of the declaration.
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
+ nameSize = 1;
+ ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType);
+ }
+ else {
+ SourceLocation startLoc;
+ Expr *E = ND->getInit();
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
+ startLoc = SM->getExpansionLoc(startLoc);
+ endBuf = SM->getCharacterData(startLoc);
+ ByrefType += " " + Name;
+ ByrefType += " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += "), ";
+ if (HasCopyAndDispose) {
+ ByrefType += "__Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
+ }
+ ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);
+
+ // Complete the newly synthesized compound expression by inserting a right
+ // curly brace before the end of the declaration.
+ // FIXME: This approach avoids rewriting the initializer expression. It
+ // also assumes there is only one declarator. For example, the following
+ // isn't currently supported by this routine (in general):
+ //
+ // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37;
+ //
+ const char *startInitializerBuf = SM->getCharacterData(startLoc);
+ const char *semiBuf = strchr(startInitializerBuf, ';');
+ assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");
+ SourceLocation semiLoc =
+ startLoc.getLocWithOffset(semiBuf-startInitializerBuf);
+
+ InsertText(semiLoc, "}");
+ }
+ return;
+}
+
+void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+ // Add initializers for any closure decl refs.
+ GetBlockDeclRefExprs(Exp->getBody());
+ if (BlockDeclRefs.size()) {
+ // Unique all "by copy" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (!BlockDeclRefs[i]->isByRef()) {
+ if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef() ||
+ BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
+ BlockDeclRefs[i]->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+}
+
+FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
+ IdentifierInfo *ID = &Context->Idents.get(name);
+ QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
+ return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), ID, FType, 0, SC_Extern,
+ SC_None, false, false);
+}
+
+Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
+ const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) {
+ const BlockDecl *block = Exp->getBlockDecl();
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+
+ // Add inner imported variables now used in current block.
+ int countOfInnerDecls = 0;
+ if (!InnerBlockDeclRefs.empty()) {
+ for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {
+ BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i];
ValueDecl *VD = Exp->getDecl();
- BlockDeclRefs.push_back(Exp);
if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) {
+ // We need to save the copied-in variables in nested
+ // blocks because it is needed at the end for some of the API generations.
+ // See SynthesizeBlockLiterals routine.
+ InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
+ BlockDeclRefs.push_back(Exp);
BlockByCopyDeclsPtrSet.insert(VD);
BlockByCopyDecls.push_back(VD);
}
if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) {
+ InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
+ BlockDeclRefs.push_back(Exp);
BlockByRefDeclsPtrSet.insert(VD);
BlockByRefDecls.push_back(VD);
}
- // imported objects in the inner blocks not used in the outer
- // blocks must be copied/disposed in the outer block as well.
- if (Exp->isByRef() ||
- VD->getType()->isObjCObjectPointerType() ||
- VD->getType()->isBlockPointerType())
- ImportedBlockDecls.insert(VD);
}
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++)
+ if (InnerBlockDeclRefs[i]->isByRef() ||
+ InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
+ InnerBlockDeclRefs[i]->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl());
+ }
+ InnerDeclRefsCount.push_back(countOfInnerDecls);
+
+ std::string FuncName;
- std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i);
- std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i);
+ if (CurFunctionDef)
+ FuncName = CurFunctionDef->getNameAsString();
+ else if (CurMethodDef)
+ BuildUniqueMethodName(FuncName, CurMethodDef);
+ else if (GlobalVarDecl)
+ FuncName = std::string(GlobalVarDecl->getNameAsString());
- std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
+ std::string BlockNumber = utostr(Blocks.size()-1);
- InsertText(FunLocStart, CI);
+ std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
- std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
+ // Get a pointer to the function type so we can cast appropriately.
+ QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());
+ QualType FType = Context->getPointerType(BFT);
- InsertText(FunLocStart, CF);
+ FunctionDecl *FD;
+ Expr *NewRep;
- if (ImportedBlockDecls.size()) {
- std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
- InsertText(FunLocStart, HF);
- }
- std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
- ImportedBlockDecls.size() > 0);
- InsertText(FunLocStart, BD);
+ // Simulate a contructor call...
+ FD = SynthBlockInitFunctionDecl(Tag);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, VK_RValue,
+ SourceLocation());
- BlockDeclRefs.clear();
- BlockByRefDecls.clear();
- BlockByRefDeclsPtrSet.clear();
- BlockByCopyDecls.clear();
- BlockByCopyDeclsPtrSet.clear();
- ImportedBlockDecls.clear();
+ SmallVector<Expr*, 4> InitExprs;
+
+ // Initialize the block function.
+ FD = SynthBlockInitFunctionDecl(Func);
+ DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CK_BitCast, Arg);
+ InitExprs.push_back(castExpr);
+
+ // Initialize the block descriptor.
+ std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get(DescData.c_str()),
+ Context->VoidPtrTy, 0,
+ SC_Static, SC_None);
+ UnaryOperator *DescRefExpr =
+ new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD,
+ Context->VoidPtrTy,
+ VK_LValue,
+ SourceLocation()),
+ UO_AddrOf,
+ Context->getPointerType(Context->VoidPtrTy),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ InitExprs.push_back(DescRefExpr);
+
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ Expr *Exp;
+ // Output all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ if (isObjCType((*I)->getType())) {
+ // FIXME: Conform to ABI ([[obj retain] autorelease]).
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
+ OK_Ordinary, SourceLocation());
+ }
+ } else if (isTopLevelBlockPointerType((*I)->getType())) {
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CK_BitCast, Arg);
+ } else {
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
+ OK_Ordinary, SourceLocation());
+ }
+
+ }
+ InitExprs.push_back(Exp);
+ }
+ // Output all "by ref" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ ValueDecl *ND = (*I);
+ std::string Name(ND->getNameAsString());
+ std::string RecName;
+ RewriteByRefString(RecName, Name, ND, true);
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ + sizeof("struct"));
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ SourceLocation());
+ bool isNestedCapturedVar = false;
+ if (block)
+ for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
+ ce = block->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ if (variable == ND && ci->isNested()) {
+ assert (ci->isByRef() &&
+ "SynthBlockInitExpr - captured block variable is not byref");
+ isNestedCapturedVar = true;
+ break;
+ }
+ }
+ // captured nested byref variable has its address passed. Do not take
+ // its address again.
+ if (!isNestedCapturedVar)
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
+ Context->getPointerType(Exp->getType()),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
+ InitExprs.push_back(Exp);
+ }
}
- if (RewriteSC) {
- // Must insert any 'const/volatile/static here. Since it has been
- // removed as result of rewriting of block literals.
- std::string SC;
- if (GlobalVarDecl->getStorageClass() == SC_Static)
- SC = "static ";
- if (GlobalVarDecl->getType().isConstQualified())
- SC += "const ";
- if (GlobalVarDecl->getType().isVolatileQualified())
- SC += "volatile ";
- if (GlobalVarDecl->getType().isRestrictQualified())
- SC += "restrict ";
- InsertText(FunLocStart, SC);
+ if (ImportedBlockDecls.size()) {
+ // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
+ int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
+ Context->IntTy, SourceLocation());
+ InitExprs.push_back(FlagExp);
}
-
- Blocks.clear();
- InnerDeclRefsCount.clear();
- InnerDeclRefs.clear();
- RewrittenBlockExprs.clear();
+ NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ FType, VK_LValue, SourceLocation());
+ NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
+ Context->getPointerType(NewRep->getType()),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
+ NewRep);
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
+ BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
+ ImportedBlockDecls.clear();
+ return NewRep;
}
-void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
- SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
- StringRef FuncName = FD->getName();
-
- SynthesizeBlockLiterals(FunLocStart, FuncName);
+bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
+ if (const ObjCForCollectionStmt * CS =
+ dyn_cast<ObjCForCollectionStmt>(Stmts.back()))
+ return CS->getElement() == DS;
+ return false;
}
-static void BuildUniqueMethodName(std::string &Name,
- ObjCMethodDecl *MD) {
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- Name = IFace->getName();
- Name += "__" + MD->getSelector().getAsString();
- // Convert colons to underscores.
- std::string::size_type loc = 0;
- while ((loc = Name.find(":", loc)) != std::string::npos)
- Name.replace(loc, 1, "_");
-}
+//===----------------------------------------------------------------------===//
+// Function Body / Expression rewriting
+//===----------------------------------------------------------------------===//
-void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
- //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
- //SourceLocation FunLocStart = MD->getLocStart();
- SourceLocation FunLocStart = MD->getLocStart();
- std::string FuncName;
- BuildUniqueMethodName(FuncName, MD);
- SynthesizeBlockLiterals(FunLocStart, FuncName);
-}
+Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S))
+ Stmts.push_back(S);
+ else if (isa<ObjCForCollectionStmt>(S)) {
+ Stmts.push_back(S);
+ ObjCBcLabelNo.push_back(++BcLabelCount);
+ }
-void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
- for (Stmt::child_range CI = S->children(); CI; ++CI)
- if (*CI) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
- GetBlockDeclRefExprs(CBE->getBody());
- else
- GetBlockDeclRefExprs(*CI);
+ // Pseudo-object operations and ivar references need special
+ // treatment because we're going to recursively rewrite them.
+ if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {
+ if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {
+ return RewritePropertyOrImplicitSetter(PseudoOp);
+ } else {
+ return RewritePropertyOrImplicitGetter(PseudoOp);
}
- // Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- // FIXME: Handle enums.
- if (!isa<FunctionDecl>(CDRE->getDecl()))
- BlockDeclRefs.push_back(CDRE);
+ } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ return RewriteObjCIvarRefExpr(IvarRefExpr);
}
- else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
- if (HasLocalVariableExternalStorage(DRE->getDecl())) {
- BlockDeclRefExpr *BDRE =
- new (Context)BlockDeclRefExpr(cast<VarDecl>(DRE->getDecl()),
- DRE->getType(),
- VK_LValue, DRE->getLocation(), false);
- BlockDeclRefs.push_back(BDRE);
- }
-
- return;
-}
-void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
- llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
+ SourceRange OrigStmtRange = S->getSourceRange();
+
+ // Perform a bottom up rewrite of all children.
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
- if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
- InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl()));
- GetInnerBlockDeclRefExprs(CBE->getBody(),
- InnerBlockDeclRefs,
- InnerContexts);
- }
- else
- GetInnerBlockDeclRefExprs(*CI,
- InnerBlockDeclRefs,
- InnerContexts);
-
+ Stmt *childStmt = (*CI);
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);
+ if (newStmt) {
+ *CI = newStmt;
+ }
}
- // Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- if (!isa<FunctionDecl>(CDRE->getDecl()) &&
- !InnerContexts.count(CDRE->getDecl()->getDeclContext()))
- InnerBlockDeclRefs.push_back(CDRE);
- }
- else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
- if (Var->isFunctionOrMethodVarDecl())
- ImportedLocalExternalDecls.insert(Var);
- }
-
- return;
-}
-/// convertFunctionTypeOfBlocks - This routine converts a function type
-/// whose result type may be a block pointer or whose argument type(s)
-/// might be block pointers to an equivalent function type replacing
-/// all block pointers to function pointers.
-QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
- const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
- // FTP will be null for closures that don't take arguments.
- // Generate a funky cast.
- SmallVector<QualType, 8> ArgTypes;
- QualType Res = FT->getResultType();
- bool HasBlockType = convertBlockPointerToFunctionPointer(Res);
-
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
- // Make sure we convert "t (^)(...)" to "t (*)(...)".
- if (convertBlockPointerToFunctionPointer(t))
- HasBlockType = true;
- ArgTypes.push_back(t);
- }
+ if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+ SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
+ llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
+ InnerContexts.insert(BE->getBlockDecl());
+ ImportedLocalExternalDecls.clear();
+ GetInnerBlockDeclRefExprs(BE->getBody(),
+ InnerBlockDeclRefs, InnerContexts);
+ // Rewrite the block body in place.
+ Stmt *SaveCurrentBody = CurrentBody;
+ CurrentBody = BE->getBody();
+ PropParentMap = 0;
+ // block literal on rhs of a property-dot-sytax assignment
+ // must be replaced by its synthesize ast so getRewrittenText
+ // works as expected. In this case, what actually ends up on RHS
+ // is the blockTranscribed which is the helper function for the
+ // block literal; as in: self.c = ^() {[ace ARR];};
+ bool saveDisableReplaceStmt = DisableReplaceStmt;
+ DisableReplaceStmt = false;
+ RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
+ DisableReplaceStmt = saveDisableReplaceStmt;
+ CurrentBody = SaveCurrentBody;
+ PropParentMap = 0;
+ ImportedLocalExternalDecls.clear();
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
+ RewrittenBlockExprs[BE] = Str;
+
+ Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);
+
+ //blockTranscribed->dump();
+ ReplaceStmt(S, blockTranscribed);
+ return blockTranscribed;
}
- QualType FuncType;
- // FIXME. Does this work if block takes no argument but has a return type
- // which is of block type?
- if (HasBlockType)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
- else FuncType = QualType(FT, 0);
- return FuncType;
-}
+ // Handle specific things.
+ if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
+ return RewriteAtEncode(AtEncode);
-Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
- // Navigate to relevant type information.
- const BlockPointerType *CPT = 0;
+ if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
+ return RewriteAtSelector(AtSelector);
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
- CPT = DRE->getType()->getAs<BlockPointerType>();
- } else if (const BlockDeclRefExpr *CDRE =
- dyn_cast<BlockDeclRefExpr>(BlockExp)) {
- CPT = CDRE->getType()->getAs<BlockPointerType>();
- } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {
- CPT = MExpr->getType()->getAs<BlockPointerType>();
- }
- else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) {
- return SynthesizeBlockCall(Exp, PRE->getSubExpr());
- }
- else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp))
- CPT = IEXPR->getType()->getAs<BlockPointerType>();
- else if (const ConditionalOperator *CEXPR =
- dyn_cast<ConditionalOperator>(BlockExp)) {
- Expr *LHSExp = CEXPR->getLHS();
- Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp);
- Expr *RHSExp = CEXPR->getRHS();
- Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
- Expr *CONDExp = CEXPR->getCond();
- ConditionalOperator *CondExpr =
- new (Context) ConditionalOperator(CONDExp,
- SourceLocation(), cast<Expr>(LHSStmt),
- SourceLocation(), cast<Expr>(RHSStmt),
- Exp->getType(), VK_RValue, OK_Ordinary);
- return CondExpr;
- } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
- CPT = IRE->getType()->getAs<BlockPointerType>();
- } else if (const PseudoObjectExpr *POE
- = dyn_cast<PseudoObjectExpr>(BlockExp)) {
- CPT = POE->getType()->castAs<BlockPointerType>();
- } else {
- assert(1 && "RewriteBlockClass: Bad type");
- }
- assert(CPT && "RewriteBlockClass: Bad type");
- const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
- assert(FT && "RewriteBlockClass: Bad type");
- const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
- // FTP will be null for closures that don't take arguments.
+ if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
+ return RewriteObjCStringLiteral(AtString);
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__block_impl"));
- QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
+ if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
+#if 0
+ // Before we rewrite it, put the original message expression in a comment.
+ SourceLocation startLoc = MessExpr->getLocStart();
+ SourceLocation endLoc = MessExpr->getLocEnd();
- // Generate a funky cast.
- SmallVector<QualType, 8> ArgTypes;
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *endBuf = SM->getCharacterData(endLoc);
- // Push the block argument type.
- ArgTypes.push_back(PtrBlock);
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
- // Make sure we convert "t (^)(...)" to "t (*)(...)".
- if (!convertBlockPointerToFunctionPointer(t))
- convertToUnqualifiedObjCType(t);
- ArgTypes.push_back(t);
- }
+ std::string messString;
+ messString += "// ";
+ messString.append(startBuf, endBuf-startBuf+1);
+ messString += "\n";
+
+ // FIXME: Missing definition of
+ // InsertText(clang::SourceLocation, char const*, unsigned int).
+ // InsertText(startLoc, messString.c_str(), messString.size());
+ // Tried this, but it didn't work either...
+ // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
+#endif
+ return RewriteMessageExpr(MessExpr);
}
- // Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
- PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
+ if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
+ return RewriteObjCTryStmt(StmtTry);
- CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,
- CK_BitCast,
- const_cast<Expr*>(BlockExp));
- // Don't forget the parens to enforce the proper binding.
- ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
- BlkCast);
- //PE->dump();
+ if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
+ return RewriteObjCSynchronizedStmt(StmtTry);
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(),
- &Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- /*HasInit=*/false);
- MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
+ if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
+ return RewriteObjCThrowStmt(StmtThrow);
-
- CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
- CK_BitCast, ME);
- PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+ if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
+ return RewriteObjCProtocolExpr(ProtocolExp);
- SmallVector<Expr*, 8> BlkExprs;
- // Add the implicit argument.
- BlkExprs.push_back(BlkCast);
- // Add the user arguments.
- for (CallExpr::arg_iterator I = Exp->arg_begin(),
- E = Exp->arg_end(); I != E; ++I) {
- BlkExprs.push_back(*I);
- }
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
- BlkExprs.size(),
- Exp->getType(), VK_RValue,
- SourceLocation());
- return CE;
-}
+ if (ObjCForCollectionStmt *StmtForCollection =
+ dyn_cast<ObjCForCollectionStmt>(S))
+ return RewriteObjCForCollectionStmt(StmtForCollection,
+ OrigStmtRange.getEnd());
+ if (BreakStmt *StmtBreakStmt =
+ dyn_cast<BreakStmt>(S))
+ return RewriteBreakStmt(StmtBreakStmt);
+ if (ContinueStmt *StmtContinueStmt =
+ dyn_cast<ContinueStmt>(S))
+ return RewriteContinueStmt(StmtContinueStmt);
-// We need to return the rewritten expression to handle cases where the
-// BlockDeclRefExpr is embedded in another expression being rewritten.
-// For example:
-//
-// int main() {
-// __block Foo *f;
-// __block int i;
-//
-// void (^myblock)() = ^() {
-// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten).
-// i = 77;
-// };
-//}
-Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
- // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
- // for each DeclRefExp where BYREFVAR is name of the variable.
- ValueDecl *VD;
- bool isArrow = true;
- if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
- VD = BDRE->getDecl();
- else {
- VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
- isArrow = false;
- }
-
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(),
- &Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- /*HasInit=*/false);
- MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
- FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
-
- StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
- &Context->Idents.get(Name),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- /*HasInit=*/false);
- ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
- DeclRefExp->getType(), VK_LValue, OK_Ordinary);
-
-
-
- // Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
- DeclRefExp->getExprLoc(),
- ME);
- ReplaceStmt(DeclRefExp, PE);
- return PE;
-}
-
-// Rewrites the imported local variable V with external storage
-// (static, extern, etc.) as *V
-//
-Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
- ValueDecl *VD = DRE->getDecl();
- if (VarDecl *Var = dyn_cast<VarDecl>(VD))
- if (!ImportedLocalExternalDecls.count(Var))
- return DRE;
- Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
- VK_LValue, OK_Ordinary,
- DRE->getLocation());
- // Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
- Exp);
- ReplaceStmt(DRE, PE);
- return PE;
-}
-
-void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
- SourceLocation LocStart = CE->getLParenLoc();
- SourceLocation LocEnd = CE->getRParenLoc();
-
- // Need to avoid trying to rewrite synthesized casts.
- if (LocStart.isInvalid())
- return;
- // Need to avoid trying to rewrite casts contained in macros.
- if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
- return;
-
- const char *startBuf = SM->getCharacterData(LocStart);
- const char *endBuf = SM->getCharacterData(LocEnd);
- QualType QT = CE->getType();
- const Type* TypePtr = QT->getAs<Type>();
- if (isa<TypeOfExprType>(TypePtr)) {
- const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
- QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
- std::string TypeAsString = "(";
- RewriteBlockPointerType(TypeAsString, QT);
- TypeAsString += ")";
- ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);
- return;
- }
- // advance the location to startArgList.
- const char *argPtr = startBuf;
+ // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
+ // and cast exprs.
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ // FIXME: What we're doing here is modifying the type-specifier that
+ // precedes the first Decl. In the future the DeclGroup should have
+ // a separate type-specifier that we can rewrite.
+ // NOTE: We need to avoid rewriting the DeclStmt if it is within
+ // the context of an ObjCForCollectionStmt. For example:
+ // NSArray *someArray;
+ // for (id <FooProtocol> index in someArray) ;
+ // This is because RewriteObjCForCollectionStmt() does textual rewriting
+ // and it depends on the original text locations/positions.
+ if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS))
+ RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
- while (*argPtr++ && (argPtr < endBuf)) {
- switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- LocStart = LocStart.getLocWithOffset(argPtr-startBuf);
- ReplaceText(LocStart, 1, "*");
- break;
+ // Blocks rewrite rules.
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+ Decl *SD = *DI;
+ if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
+ if (isTopLevelBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {
+ if (VD->hasAttr<BlocksAttr>()) {
+ static unsigned uniqueByrefDeclCount = 0;
+ assert(!BlockByRefDeclNo.count(ND) &&
+ "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");
+ BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
+ RewriteByRefVar(VD);
+ }
+ else
+ RewriteTypeOfDecl(VD);
+ }
+ }
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
}
}
- return;
-}
-
-void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
- SourceLocation DeclLoc = FD->getLocation();
- unsigned parenCount = 0;
-
- // We have 1 or more arguments that have closure pointers.
- const char *startBuf = SM->getCharacterData(DeclLoc);
- const char *startArgList = strchr(startBuf, '(');
-
- assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
-
- parenCount++;
- // advance the location to startArgList.
- DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf);
- assert((DeclLoc.isValid()) && "Invalid DeclLoc");
- const char *argPtr = startArgList;
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
+ RewriteObjCQualifiedInterfaceTypes(CE);
- while (*argPtr++ && parenCount) {
- switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList);
- ReplaceText(DeclLoc, 1, "*");
- break;
- case '(':
- parenCount++;
- break;
- case ')':
- parenCount--;
- break;
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S)) {
+ assert(!Stmts.empty() && "Statement stack is empty");
+ assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
+ isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
+ && "Statement stack mismatch");
+ Stmts.pop_back();
+ }
+ // Handle blocks rewriting.
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (BDRE->isByRef())
+ return RewriteBlockDeclRefExpr(BDRE);
+ }
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<BlocksAttr>())
+ return RewriteBlockDeclRefExpr(DRE);
+ if (HasLocalVariableExternalStorage(VD))
+ return RewriteLocalVariableExternalStorage(DRE);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
+ ReplaceStmt(S, BlockCall);
+ return BlockCall;
}
}
- return;
-}
-
-bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
- const FunctionProtoType *FTP;
- const PointerType *PT = QT->getAs<PointerType>();
- if (PT) {
- FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
- } else {
- const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
- assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
- FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) {
+ RewriteCastExpr(CE);
}
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I)
- if (isTopLevelBlockPointerType(*I))
- return true;
+#if 0
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
+ CastExpr *Replacement = new (Context) CastExpr(ICE->getType(),
+ ICE->getSubExpr(),
+ SourceLocation());
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream Buf(SStr);
+ Replacement->printPretty(Buf, *Context);
+ const std::string &Str = Buf.str();
+
+ printf("CAST = %s\n", &Str[0]);
+ InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
+ delete S;
+ return Replacement;
}
- return false;
+#endif
+ // Return this stmt unmodified.
+ return S;
}
-bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {
- const FunctionProtoType *FTP;
- const PointerType *PT = QT->getAs<PointerType>();
- if (PT) {
- FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
- } else {
- const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
- assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
- FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
- }
- if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I) {
- if ((*I)->isObjCQualifiedIdType())
- return true;
- if ((*I)->isObjCObjectPointerType() &&
- (*I)->getPointeeType()->isObjCQualifiedInterfaceType())
- return true;
- }
-
+void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ if (FD->getType()->isObjCQualifiedIdType() ||
+ FD->getType()->isObjCQualifiedInterfaceType())
+ RewriteObjCQualifiedInterfaceTypes(FD);
}
- return false;
}
-void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen,
- const char *&RParen) {
- const char *argPtr = strchr(Name, '(');
- assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
+/// HandleDeclInMainFile - This is called for each top-level decl defined in the
+/// main file of the input.
+void RewriteObjC::HandleDeclInMainFile(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (FD->isOverloadedOperator())
+ return;
- LParen = argPtr; // output the start.
- argPtr++; // skip past the left paren.
- unsigned parenCount = 1;
+ // Since function prototypes don't have ParmDecl's, we check the function
+ // prototype. This enables us to rewrite function declarations and
+ // definitions using the same code.
+ RewriteBlocksInFunctionProtoType(FD->getType(), FD);
- while (*argPtr && parenCount) {
- switch (*argPtr) {
- case '(': parenCount++; break;
- case ')': parenCount--; break;
- default: break;
+ // FIXME: If this should support Obj-C++, support CXXTryStmt
+ if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
+ CurFunctionDef = FD;
+ CurFunctionDeclToDeclareForBlock = FD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ FD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
+ }
+ break;
}
- if (parenCount) argPtr++;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
+ if (CompoundStmt *Body = MD->getCompoundBody()) {
+ CurMethodDef = MD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ MD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
+ }
+ break;
+ }
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D);
+ ClassImplementation.push_back(CI);
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D);
+ CategoryImplementation.push_back(CI);
+ break;
+ }
+ case Decl::Var: {
+ VarDecl *VD = cast<VarDecl>(D);
+ RewriteObjCQualifiedInterfaceTypes(VD);
+ if (isTopLevelBlockPointerType(VD->getType()))
+ RewriteBlockPointerDecl(VD);
+ else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isRecordType()) {
+ RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ }
+ if (VD->getInit()) {
+ GlobalVarDecl = VD;
+ CurrentBody = VD->getInit();
+ RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
+ GlobalVarDecl = 0;
+
+ // This is needed for blocks.
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ break;
+ }
+ case Decl::TypeAlias:
+ case Decl::Typedef: {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ break;
+ }
+ case Decl::CXXRecord:
+ case Decl::Record: {
+ RecordDecl *RD = cast<RecordDecl>(D);
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ break;
+ }
+ case Decl::ObjCClass: {
+ llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl");
+ break;
+ }
+ default:
+ break;
}
- assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
- RParen = argPtr; // output the end
+ // Nothing yet.
}
-void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
- RewriteBlockPointerFunctionArgs(FD);
+void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
+ if (Diags.hasErrorOccurred())
return;
- }
- // Handle Variables and Typedefs.
- SourceLocation DeclLoc = ND->getLocation();
- QualType DeclT;
- if (VarDecl *VD = dyn_cast<VarDecl>(ND))
- DeclT = VD->getType();
- else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND))
- DeclT = TDD->getUnderlyingType();
- else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
- DeclT = FD->getType();
- else
- llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled");
- const char *startBuf = SM->getCharacterData(DeclLoc);
- const char *endBuf = startBuf;
- // scan backward (from the decl location) for the end of the previous decl.
- while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
- startBuf--;
- SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf);
- std::string buf;
- unsigned OrigLength=0;
- // *startBuf != '^' if we are dealing with a pointer to function that
- // may take block argument types (which will be handled below).
- if (*startBuf == '^') {
- // Replace the '^' with '*', computing a negative offset.
- buf = '*';
- startBuf++;
- OrigLength++;
- }
- while (*startBuf != ')') {
- buf += *startBuf;
- startBuf++;
- OrigLength++;
+ RewriteInclude();
+
+ // Here's a great place to add any extra declarations that may be needed.
+ // Write out meta data for each @protocol(<expr>).
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I)
+ RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+
+ InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
+ if (ClassImplementation.size() || CategoryImplementation.size())
+ RewriteImplementations();
+
+ // Get the buffer corresponding to MainFileID. If we haven't changed it, then
+ // we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ //printf("Changed:\n");
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ llvm::errs() << "No changes\n";
}
- buf += ')';
- OrigLength++;
-
- if (PointerTypeTakesAnyBlockArguments(DeclT) ||
- PointerTypeTakesAnyObjCQualifiedType(DeclT)) {
- // Replace the '^' with '*' for arguments.
- // Replace id<P> with id/*<>*/
- DeclLoc = ND->getLocation();
- startBuf = SM->getCharacterData(DeclLoc);
- const char *argListBegin, *argListEnd;
- GetExtentOfArgList(startBuf, argListBegin, argListEnd);
- while (argListBegin < argListEnd) {
- if (*argListBegin == '^')
- buf += '*';
- else if (*argListBegin == '<') {
- buf += "/*";
- buf += *argListBegin++;
- OrigLength++;;
- while (*argListBegin != '>') {
- buf += *argListBegin++;
- OrigLength++;
- }
- buf += *argListBegin;
- buf += "*/";
- }
- else
- buf += *argListBegin;
- argListBegin++;
- OrigLength++;
- }
- buf += ')';
- OrigLength++;
+
+ if (ClassImplementation.size() || CategoryImplementation.size() ||
+ ProtocolExprDecls.size()) {
+ // Rewrite Objective-c meta data*
+ std::string ResultStr;
+ RewriteMetaDataIntoBuffer(ResultStr);
+ // Emit metadata.
+ *OutFile << ResultStr;
}
- ReplaceText(Start, OrigLength, buf);
-
- return;
+ OutFile->flush();
}
-
-/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:
-/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,
-/// struct Block_byref_id_object *src) {
-/// _Block_object_assign (&_dest->object, _src->object,
-/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
-/// [|BLOCK_FIELD_IS_WEAK]) // object
-/// _Block_object_assign(&_dest->object, _src->object,
-/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
-/// [|BLOCK_FIELD_IS_WEAK]) // block
-/// }
-/// And:
-/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {
-/// _Block_object_dispose(_src->object,
-/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
-/// [|BLOCK_FIELD_IS_WEAK]) // object
-/// _Block_object_dispose(_src->object,
-/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
-/// [|BLOCK_FIELD_IS_WEAK]) // block
-/// }
-
-std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
- int flag) {
- std::string S;
- if (CopyDestroyCache.count(flag))
- return S;
- CopyDestroyCache.insert(flag);
- S = "static void __Block_byref_id_object_copy_";
- S += utostr(flag);
- S += "(void *dst, void *src) {\n";
+void RewriteObjCFragileABI::Initialize(ASTContext &context) {
+ InitializeCommon(context);
- // offset into the object pointer is computed as:
- // void * + void* + int + int + void* + void *
- unsigned IntSize =
- static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
- unsigned VoidPtrSize =
- static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
-
- unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth();
- S += " _Block_object_assign((char*)dst + ";
- S += utostr(offset);
- S += ", *(void * *) ((char*)src + ";
- S += utostr(offset);
- S += "), ";
- S += utostr(flag);
- S += ");\n}\n";
-
- S += "static void __Block_byref_id_object_dispose_";
- S += utostr(flag);
- S += "(void *src) {\n";
- S += " _Block_object_dispose(*(void * *) ((char*)src + ";
- S += utostr(offset);
- S += "), ";
- S += utostr(flag);
- S += ");\n}\n";
- return S;
-}
-
-/// RewriteByRefVar - For each __block typex ND variable this routine transforms
-/// the declaration into:
-/// struct __Block_byref_ND {
-/// void *__isa; // NULL for everything except __weak pointers
-/// struct __Block_byref_ND *__forwarding;
-/// int32_t __flags;
-/// int32_t __size;
-/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object
-/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object
-/// typex ND;
-/// };
-///
-/// It then replaces declaration of ND variable with:
-/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag,
-/// __size=sizeof(struct __Block_byref_ND),
-/// ND=initializer-if-any};
-///
-///
-void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
- // Insert declaration for the function in which block literal is
- // used.
- if (CurFunctionDeclToDeclareForBlock)
- RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
- int flag = 0;
- int isa = 0;
- SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
- if (DeclLoc.isInvalid())
- // If type location is missing, it is because of missing type (a warning).
- // Use variable's location which is good for this case.
- DeclLoc = ND->getLocation();
- const char *startBuf = SM->getCharacterData(DeclLoc);
- SourceLocation X = ND->getLocEnd();
- X = SM->getExpansionLoc(X);
- const char *endBuf = SM->getCharacterData(X);
- std::string Name(ND->getNameAsString());
- std::string ByrefType;
- RewriteByRefString(ByrefType, Name, ND, true);
- ByrefType += " {\n";
- ByrefType += " void *__isa;\n";
- RewriteByRefString(ByrefType, Name, ND);
- ByrefType += " *__forwarding;\n";
- ByrefType += " int __flags;\n";
- ByrefType += " int __size;\n";
- // Add void *__Block_byref_id_object_copy;
- // void *__Block_byref_id_object_dispose; if needed.
- QualType Ty = ND->getType();
- bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
- if (HasCopyAndDispose) {
- ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
- ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
+ // declaring objc_selector outside the parameter list removes a silly
+ // scope related warning...
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ Preamble += "struct objc_selector; struct objc_class;\n";
+ Preamble += "struct __rw_objc_super { struct objc_object *object; ";
+ Preamble += "struct objc_object *superClass; ";
+ if (LangOpts.MicrosoftExt) {
+ // Add a constructor for creating temporary objects.
+ Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
+ ": ";
+ Preamble += "object(o), superClass(s) {} ";
+ }
+ Preamble += "};\n";
+ Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
+ Preamble += "typedef struct objc_object Protocol;\n";
+ Preamble += "#define _REWRITER_typedef_Protocol\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
+ Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
+ } else
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
+ Preamble += "(struct objc_class *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
+ Preamble += "(struct objc_class *, struct objc_object *);\n";
+ // @synchronized hooks.
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+ Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
+ Preamble += "struct __objcFastEnumerationState {\n\t";
+ Preamble += "unsigned long state;\n\t";
+ Preamble += "void **itemsPtr;\n\t";
+ Preamble += "unsigned long *mutationsPtr;\n\t";
+ Preamble += "unsigned long extra[5];\n};\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
+ Preamble += "#define __FASTENUMERATIONSTATE\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "struct __NSConstantStringImpl {\n";
+ Preamble += " int *isa;\n";
+ Preamble += " int flags;\n";
+ Preamble += " char *str;\n";
+ Preamble += " long length;\n";
+ Preamble += "};\n";
+ Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
+ Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "#endif\n";
+ // Blocks preamble.
+ Preamble += "#ifndef BLOCK_IMPL\n";
+ Preamble += "#define BLOCK_IMPL\n";
+ Preamble += "struct __block_impl {\n";
+ Preamble += " void *isa;\n";
+ Preamble += " int Flags;\n";
+ Preamble += " int Reserved;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
+ Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
+ Preamble += "extern \"C\" __declspec(dllexport) "
+ "void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
+ Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
+ Preamble += "#define __attribute__(X)\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __weak\n";
}
-
- QualType T = Ty;
- (void)convertBlockPointerToFunctionPointer(T);
- T.getAsStringInternal(Name, Context->getPrintingPolicy());
-
- ByrefType += " " + Name + ";\n";
- ByrefType += "};\n";
- // Insert this type in global scope. It is needed by helper function.
- SourceLocation FunLocStart;
- if (CurFunctionDef)
- FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
else {
- assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
- FunLocStart = CurMethodDef->getLocStart();
+ Preamble += "#define __block\n";
+ Preamble += "#define __weak\n";
}
- InsertText(FunLocStart, ByrefType);
- if (Ty.isObjCGCWeak()) {
- flag |= BLOCK_FIELD_IS_WEAK;
- isa = 1;
+ // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
+ // as this avoids warning in any 64bit/32bit compilation model.
+ Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+}
+
+/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// ivar offset.
+void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) {
+ if (ivar->isBitField()) {
+ // FIXME: The hack below doesn't work for bitfields. For now, we simply
+ // place all bitfields at offset 0.
+ Result += "0";
+ } else {
+ Result += "__OFFSETOFIVAR__(struct ";
+ Result += ivar->getContainingInterface()->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ", ";
+ Result += ivar->getNameAsString();
+ Result += ")";
}
+}
+
+/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
+void RewriteObjCFragileABI::RewriteObjCProtocolMetaData(
+ ObjCProtocolDecl *PDecl, StringRef prefix,
+ StringRef ClassName, std::string &Result) {
+ static bool objc_protocol_methods = false;
- if (HasCopyAndDispose) {
- flag = BLOCK_BYREF_CALLER;
- QualType Ty = ND->getType();
- // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.
- if (Ty->isBlockPointerType())
- flag |= BLOCK_FIELD_IS_BLOCK;
- else
- flag |= BLOCK_FIELD_IS_OBJECT;
- std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
- if (!HF.empty())
- InsertText(FunLocStart, HF);
+ // Output struct protocol_methods holder of method selector and type.
+ if (!objc_protocol_methods && !PDecl->isForwardDecl()) {
+ /* struct protocol_methods {
+ SEL _cmd;
+ char *method_types;
+ }
+ */
+ Result += "\nstruct _protocol_methods {\n";
+ Result += "\tstruct objc_selector *_cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "};\n";
+
+ objc_protocol_methods = true;
}
+ // Do not synthesize the protocol more than once.
+ if (ObjCSynthesizedProtocols.count(PDecl))
+ return;
- // struct __Block_byref_ND ND =
- // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
- // initializer-if-any};
- bool hasInit = (ND->getInit() != 0);
- unsigned flags = 0;
- if (HasCopyAndDispose)
- flags |= BLOCK_HAS_COPY_DISPOSE;
- Name = ND->getNameAsString();
- ByrefType.clear();
- RewriteByRefString(ByrefType, Name, ND);
- std::string ForwardingCastType("(");
- ForwardingCastType += ByrefType + " *)";
- if (!hasInit) {
- ByrefType += " " + Name + " = {(void*)";
- ByrefType += utostr(isa);
- ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
- ByrefType += utostr(flags);
- ByrefType += ", ";
- ByrefType += "sizeof(";
- RewriteByRefString(ByrefType, Name, ND);
- ByrefType += ")";
- if (HasCopyAndDispose) {
- ByrefType += ", __Block_byref_id_object_copy_";
- ByrefType += utostr(flag);
- ByrefType += ", __Block_byref_id_object_dispose_";
- ByrefType += utostr(flag);
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
+ PDecl->instmeth_end());
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
+ "{\n\t" + utostr(NumMethods) + "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ I != E; ++I) {
+ if (I == PDecl->instmeth_begin())
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
}
- ByrefType += "};\n";
- unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
- // part of the declaration.
- if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
- nameSize = 1;
- ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType);
+ Result += "\t }\n};\n";
}
- else {
- SourceLocation startLoc;
- Expr *E = ND->getInit();
- if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
- startLoc = ECE->getLParenLoc();
- else
- startLoc = E->getLocStart();
- startLoc = SM->getExpansionLoc(startLoc);
- endBuf = SM->getCharacterData(startLoc);
- ByrefType += " " + Name;
- ByrefType += " = {(void*)";
- ByrefType += utostr(isa);
- ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
- ByrefType += utostr(flags);
- ByrefType += ", ";
- ByrefType += "sizeof(";
- RewriteByRefString(ByrefType, Name, ND);
- ByrefType += "), ";
- if (HasCopyAndDispose) {
- ByrefType += "__Block_byref_id_object_copy_";
- ByrefType += utostr(flag);
- ByrefType += ", __Block_byref_id_object_dispose_";
- ByrefType += utostr(flag);
- ByrefType += ", ";
+
+ // Output class methods declared in this protocol.
+ unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
+ PDecl->classmeth_end());
+ if (NumMethods > 0) {
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t";
+ Result += utostr(NumMethods);
+ Result += "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
+ I != E; ++I) {
+ if (I == PDecl->classmeth_begin())
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
}
- ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);
+ Result += "\t }\n};\n";
+ }
+
+ // Output:
+ /* struct _objc_protocol {
+ // Objective-C 1.0 extensions
+ struct _objc_protocol_extension *isa;
+ char *protocol_name;
+ struct _objc_protocol **protocol_list;
+ struct _objc_protocol_method_list *instance_methods;
+ struct _objc_protocol_method_list *class_methods;
+ };
+ */
+ static bool objc_protocol = false;
+ if (!objc_protocol) {
+ Result += "\nstruct _objc_protocol {\n";
+ Result += "\tstruct _objc_protocol_extension *isa;\n";
+ Result += "\tchar *protocol_name;\n";
+ Result += "\tstruct _objc_protocol **protocol_list;\n";
+ Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
+ Result += "};\n";
- // Complete the newly synthesized compound expression by inserting a right
- // curly brace before the end of the declaration.
- // FIXME: This approach avoids rewriting the initializer expression. It
- // also assumes there is only one declarator. For example, the following
- // isn't currently supported by this routine (in general):
- //
- // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37;
- //
- const char *startInitializerBuf = SM->getCharacterData(startLoc);
- const char *semiBuf = strchr(startInitializerBuf, ';');
- assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");
- SourceLocation semiLoc =
- startLoc.getLocWithOffset(semiBuf-startInitializerBuf);
-
- InsertText(semiLoc, "}");
+ objc_protocol = true;
}
- return;
-}
-
-void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
- // Add initializers for any closure decl refs.
- GetBlockDeclRefExprs(Exp->getBody());
- if (BlockDeclRefs.size()) {
- // Unique all "by copy" declarations.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (!BlockDeclRefs[i]->isByRef()) {
- if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
- BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
- BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
- }
- }
- // Unique all "by ref" declarations.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->isByRef()) {
- if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
- BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
- BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
- }
- }
- // Find any imported blocks...they will need special attention.
- for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->isByRef() ||
- BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
- BlockDeclRefs[i]->getType()->isBlockPointerType())
- ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+
+ Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
+ "{\n\t0, \"";
+ Result += PDecl->getNameAsString();
+ Result += "\", 0, ";
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += ", ";
}
+ else
+ Result += "0, ";
+ if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += "0\n";
+ Result += "};\n";
+
+ // Mark this protocol as having been generated.
+ if (!ObjCSynthesizedProtocols.insert(PDecl))
+ llvm_unreachable("protocol already synthesized");
+
}
-FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
- IdentifierInfo *ID = &Context->Idents.get(name);
- QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
- return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, FType, 0, SC_Extern,
- SC_None, false, false);
+void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Protocols,
+ StringRef prefix, StringRef ClassName,
+ std::string &Result) {
+ if (Protocols.empty()) return;
+
+ for (unsigned i = 0; i != Protocols.size(); i++)
+ RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);
+
+ // Output the top lovel protocol meta-data for the class.
+ /* struct _objc_protocol_list {
+ struct _objc_protocol_list *next;
+ int protocol_count;
+ struct _objc_protocol *class_protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_protocol_list *next;\n";
+ Result += "\tint protocol_count;\n";
+ Result += "\tstruct _objc_protocol *class_protocols[";
+ Result += utostr(Protocols.size());
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += "_PROTOCOLS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t0, ";
+ Result += utostr(Protocols.size());
+ Result += "\n";
+
+ Result += "\t,{&_OBJC_PROTOCOL_";
+ Result += Protocols[0]->getNameAsString();
+ Result += " \n";
+
+ for (unsigned i = 1; i != Protocols.size(); i++) {
+ Result += "\t ,&_OBJC_PROTOCOL_";
+ Result += Protocols[i]->getNameAsString();
+ Result += "\n";
+ }
+ Result += "\t }\n};\n";
}
-Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) {
- const BlockDecl *block = Exp->getBlockDecl();
- Blocks.push_back(Exp);
-
- CollectBlockDeclRefInfo(Exp);
+void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
- // Add inner imported variables now used in current block.
- int countOfInnerDecls = 0;
- if (!InnerBlockDeclRefs.empty()) {
- for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {
- BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i];
- ValueDecl *VD = Exp->getDecl();
- if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) {
- // We need to save the copied-in variables in nested
- // blocks because it is needed at the end for some of the API generations.
- // See SynthesizeBlockLiterals routine.
- InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
- BlockDeclRefs.push_back(Exp);
- BlockByCopyDeclsPtrSet.insert(VD);
- BlockByCopyDecls.push_back(VD);
- }
- if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) {
- InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
- BlockDeclRefs.push_back(Exp);
- BlockByRefDeclsPtrSet.insert(VD);
- BlockByRefDecls.push_back(VD);
- }
- }
- // Find any imported blocks...they will need special attention.
- for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++)
- if (InnerBlockDeclRefs[i]->isByRef() ||
- InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
- InnerBlockDeclRefs[i]->getType()->isBlockPointerType())
- ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl());
+ // Explicitly declared @interface's are already synthesized.
+ if (CDecl->isImplicitInterfaceDecl()) {
+ // FIXME: Implementation of a class with no @interface (legacy) doese not
+ // produce correct synthesis as yet.
+ RewriteObjCInternalStruct(CDecl, Result);
}
- InnerDeclRefsCount.push_back(countOfInnerDecls);
-
- std::string FuncName;
-
- if (CurFunctionDef)
- FuncName = CurFunctionDef->getNameAsString();
- else if (CurMethodDef)
- BuildUniqueMethodName(FuncName, CurMethodDef);
- else if (GlobalVarDecl)
- FuncName = std::string(GlobalVarDecl->getNameAsString());
-
- std::string BlockNumber = utostr(Blocks.size()-1);
-
- std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
- std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
-
- // Get a pointer to the function type so we can cast appropriately.
- QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());
- QualType FType = Context->getPointerType(BFT);
-
- FunctionDecl *FD;
- Expr *NewRep;
-
- // Simulate a contructor call...
- FD = SynthBlockInitFunctionDecl(Tag);
- DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, VK_RValue,
- SourceLocation());
-
- SmallVector<Expr*, 4> InitExprs;
-
- // Initialize the block function.
- FD = SynthBlockInitFunctionDecl(Func);
- DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
- CK_BitCast, Arg);
- InitExprs.push_back(castExpr);
-
- // Initialize the block descriptor.
- std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";
-
- VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
- SourceLocation(), SourceLocation(),
- &Context->Idents.get(DescData.c_str()),
- Context->VoidPtrTy, 0,
- SC_Static, SC_None);
- UnaryOperator *DescRefExpr =
- new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD,
- Context->VoidPtrTy,
- VK_LValue,
- SourceLocation()),
- UO_AddrOf,
- Context->getPointerType(Context->VoidPtrTy),
- VK_RValue, OK_Ordinary,
- SourceLocation());
- InitExprs.push_back(DescRefExpr);
- // Add initializers for any closure decl refs.
- if (BlockDeclRefs.size()) {
- Expr *Exp;
- // Output all "by copy" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
- E = BlockByCopyDecls.end(); I != E; ++I) {
- if (isObjCType((*I)->getType())) {
- // FIXME: Conform to ABI ([[obj retain] autorelease]).
- FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
- if (HasLocalVariableExternalStorage(*I)) {
- QualType QT = (*I)->getType();
- QT = Context->getPointerType(QT);
- Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
- OK_Ordinary, SourceLocation());
- }
- } else if (isTopLevelBlockPointerType((*I)->getType())) {
- FD = SynthBlockInitFunctionDecl((*I)->getName());
- Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
- Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
- CK_BitCast, Arg);
- } else {
- FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
- if (HasLocalVariableExternalStorage(*I)) {
- QualType QT = (*I)->getType();
- QT = Context->getPointerType(QT);
- Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
- OK_Ordinary, SourceLocation());
- }
-
- }
- InitExprs.push_back(Exp);
- }
- // Output all "by ref" declarations.
- for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
- E = BlockByRefDecls.end(); I != E; ++I) {
- ValueDecl *ND = (*I);
- std::string Name(ND->getNameAsString());
- std::string RecName;
- RewriteByRefString(RecName, Name, ND, true);
- IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
- + sizeof("struct"));
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- II);
- assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
- QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ // Build _objc_ivar_list metadata for classes ivars if needed
+ unsigned NumIvars = !IDecl->ivar_empty()
+ ? IDecl->ivar_size()
+ : (CDecl ? CDecl->ivar_size() : 0);
+ if (NumIvars > 0) {
+ static bool objc_ivar = false;
+ if (!objc_ivar) {
+ /* struct _objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ };
+ */
+ Result += "\nstruct _objc_ivar {\n";
+ Result += "\tchar *ivar_name;\n";
+ Result += "\tchar *ivar_type;\n";
+ Result += "\tint ivar_offset;\n";
+ Result += "};\n";
- FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
- bool isNestedCapturedVar = false;
- if (block)
- for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
- ce = block->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
- if (variable == ND && ci->isNested()) {
- assert (ci->isByRef() &&
- "SynthBlockInitExpr - captured block variable is not byref");
- isNestedCapturedVar = true;
- break;
- }
- }
- // captured nested byref variable has its address passed. Do not take
- // its address again.
- if (!isNestedCapturedVar)
- Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
- Context->getPointerType(Exp->getType()),
- VK_RValue, OK_Ordinary, SourceLocation());
- Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
- InitExprs.push_back(Exp);
+ objc_ivar = true;
+ }
+
+ /* struct {
+ int ivar_count;
+ struct _objc_ivar ivar_list[nIvars];
+ };
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint ivar_count;\n";
+ Result += "\tstruct _objc_ivar ivar_list[";
+ Result += utostr(NumIvars);
+ Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
+ Result += IDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
+ "{\n\t";
+ Result += utostr(NumIvars);
+ Result += "\n";
+
+ ObjCInterfaceDecl::ivar_iterator IVI, IVE;
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+ if (!IDecl->ivar_empty()) {
+ for (ObjCInterfaceDecl::ivar_iterator
+ IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
+ IV != IVEnd; ++IV)
+ IVars.push_back(*IV);
+ IVI = IDecl->ivar_begin();
+ IVE = IDecl->ivar_end();
+ } else {
+ IVI = CDecl->ivar_begin();
+ IVE = CDecl->ivar_end();
}
+ Result += "\t,{{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ RewriteIvarOffsetComputation(*IVI, Result);
+ Result += "}\n";
+ for (++IVI; IVI != IVE; ++IVI) {
+ Result += "\t ,{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ RewriteIvarOffsetComputation((*IVI), Result);
+ Result += "}\n";
+ }
+
+ Result += "\t }\n};\n";
}
- if (ImportedBlockDecls.size()) {
- // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
- int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
- unsigned IntSize =
- static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
- Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
- Context->IntTy, SourceLocation());
- InitExprs.push_back(FlagExp);
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (!Getter->isDefined())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (!Setter->isDefined())
+ InstanceMethods.push_back(Setter);
+ }
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "", IDecl->getName(), Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "", IDecl->getName(), Result);
+
+ // Protocols referenced in class declaration?
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),
+ "CLASS", CDecl->getName(), Result);
+
+ // Declaration of class/meta-class metadata
+ /* struct _objc_class {
+ struct _objc_class *isa; // or const char *root_class_name when metadata
+ const char *super_class_name;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct _objc_ivar_list *ivars;
+ struct _objc_method_list *methods;
+ struct objc_cache *cache;
+ struct objc_protocol_list *protocols;
+ const char *ivar_layout;
+ struct _objc_class_ext *ext;
+ };
+ */
+ static bool objc_class = false;
+ if (!objc_class) {
+ Result += "\nstruct _objc_class {\n";
+ Result += "\tstruct _objc_class *isa;\n";
+ Result += "\tconst char *super_class_name;\n";
+ Result += "\tchar *name;\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong info;\n";
+ Result += "\tlong instance_size;\n";
+ Result += "\tstruct _objc_ivar_list *ivars;\n";
+ Result += "\tstruct _objc_method_list *methods;\n";
+ Result += "\tstruct objc_cache *cache;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tconst char *ivar_layout;\n";
+ Result += "\tstruct _objc_class_ext *ext;\n";
+ Result += "};\n";
+ objc_class = true;
+ }
+
+ // Meta-class metadata generation.
+ ObjCInterfaceDecl *RootClass = 0;
+ ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
+ while (SuperClass) {
+ RootClass = SuperClass;
+ SuperClass = SuperClass->getSuperClass();
+ }
+ SuperClass = CDecl->getSuperClass();
+
+ Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
+ "{\n\t(struct _objc_class *)\"";
+ Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
+ Result += "\"";
+
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
+ // 'info' field is initialized to CLS_META(2) for metaclass
+ Result += ", 0,2, sizeof(struct _objc_class), 0";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
+ Result += IDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += ", 0\n";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ",0,0\n";
+ }
+ else
+ Result += "\t,0,0,0,0\n";
+ Result += "};\n";
+
+ // class metadata generation.
+ Result += "\nstatic struct _objc_class _OBJC_CLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
+ "{\n\t&_OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
}
- NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
- FType, VK_LValue, SourceLocation());
- NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
- Context->getPointerType(NewRep->getType()),
- VK_RValue, OK_Ordinary, SourceLocation());
- NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
- NewRep);
- BlockDeclRefs.clear();
- BlockByRefDecls.clear();
- BlockByRefDeclsPtrSet.clear();
- BlockByCopyDecls.clear();
- BlockByCopyDeclsPtrSet.clear();
- ImportedBlockDecls.clear();
- return NewRep;
-}
-
-bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
- if (const ObjCForCollectionStmt * CS =
- dyn_cast<ObjCForCollectionStmt>(Stmts.back()))
- return CS->getElement() == DS;
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// Function Body / Expression rewriting
-//===----------------------------------------------------------------------===//
-
-Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
- if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
- isa<DoStmt>(S) || isa<ForStmt>(S))
- Stmts.push_back(S);
- else if (isa<ObjCForCollectionStmt>(S)) {
- Stmts.push_back(S);
- ObjCBcLabelNo.push_back(++BcLabelCount);
+ // 'info' field is initialized to CLS_CLASS(1) for class
+ Result += ", 0,1";
+ if (!ObjCSynthesizedStructs.count(CDecl))
+ Result += ",0";
+ else {
+ // class has size. Must synthesize its size.
+ Result += ",sizeof(struct ";
+ Result += CDecl->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ")";
}
-
- // Pseudo-object operations and ivar references need special
- // treatment because we're going to recursively rewrite them.
- if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {
- if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {
- return RewritePropertyOrImplicitSetter(PseudoOp);
- } else {
- return RewritePropertyOrImplicitGetter(PseudoOp);
- }
- } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
- return RewriteObjCIvarRefExpr(IvarRefExpr);
+ if (NumIvars > 0) {
+ Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
+ Result += CDecl->getNameAsString();
+ Result += "\n\t";
}
-
- SourceRange OrigStmtRange = S->getSourceRange();
-
- // Perform a bottom up rewrite of all children.
- for (Stmt::child_range CI = S->children(); CI; ++CI)
- if (*CI) {
- Stmt *childStmt = (*CI);
- Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);
- if (newStmt) {
- *CI = newStmt;
- }
- }
-
- if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
- llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
- InnerContexts.insert(BE->getBlockDecl());
- ImportedLocalExternalDecls.clear();
- GetInnerBlockDeclRefExprs(BE->getBody(),
- InnerBlockDeclRefs, InnerContexts);
- // Rewrite the block body in place.
- Stmt *SaveCurrentBody = CurrentBody;
- CurrentBody = BE->getBody();
- PropParentMap = 0;
- // block literal on rhs of a property-dot-sytax assignment
- // must be replaced by its synthesize ast so getRewrittenText
- // works as expected. In this case, what actually ends up on RHS
- // is the blockTranscribed which is the helper function for the
- // block literal; as in: self.c = ^() {[ace ARR];};
- bool saveDisableReplaceStmt = DisableReplaceStmt;
- DisableReplaceStmt = false;
- RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
- DisableReplaceStmt = saveDisableReplaceStmt;
- CurrentBody = SaveCurrentBody;
- PropParentMap = 0;
- ImportedLocalExternalDecls.clear();
- // Now we snarf the rewritten text and stash it away for later use.
- std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
- RewrittenBlockExprs[BE] = Str;
-
- Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);
-
- //blockTranscribed->dump();
- ReplaceStmt(S, blockTranscribed);
- return blockTranscribed;
+ else
+ Result += ",0";
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0\n\t";
}
- // Handle specific things.
- if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
- return RewriteAtEncode(AtEncode);
-
- if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
- return RewriteAtSelector(AtSelector);
-
- if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
- return RewriteObjCStringLiteral(AtString);
-
- if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
-#if 0
- // Before we rewrite it, put the original message expression in a comment.
- SourceLocation startLoc = MessExpr->getLocStart();
- SourceLocation endLoc = MessExpr->getLocEnd();
-
- const char *startBuf = SM->getCharacterData(startLoc);
- const char *endBuf = SM->getCharacterData(endLoc);
-
- std::string messString;
- messString += "// ";
- messString.append(startBuf, endBuf-startBuf+1);
- messString += "\n";
-
- // FIXME: Missing definition of
- // InsertText(clang::SourceLocation, char const*, unsigned int).
- // InsertText(startLoc, messString.c_str(), messString.size());
- // Tried this, but it didn't work either...
- // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
-#endif
- return RewriteMessageExpr(MessExpr);
+ else
+ Result += ",0,0";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0,0\n";
}
+ else
+ Result += ",0,0,0\n";
+ Result += "};\n";
+}
- if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
- return RewriteObjCTryStmt(StmtTry);
-
- if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
- return RewriteObjCSynchronizedStmt(StmtTry);
-
- if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
- return RewriteObjCThrowStmt(StmtThrow);
-
- if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
- return RewriteObjCProtocolExpr(ProtocolExp);
-
- if (ObjCForCollectionStmt *StmtForCollection =
- dyn_cast<ObjCForCollectionStmt>(S))
- return RewriteObjCForCollectionStmt(StmtForCollection,
- OrigStmtRange.getEnd());
- if (BreakStmt *StmtBreakStmt =
- dyn_cast<BreakStmt>(S))
- return RewriteBreakStmt(StmtBreakStmt);
- if (ContinueStmt *StmtContinueStmt =
- dyn_cast<ContinueStmt>(S))
- return RewriteContinueStmt(StmtContinueStmt);
-
- // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
- // and cast exprs.
- if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
- // FIXME: What we're doing here is modifying the type-specifier that
- // precedes the first Decl. In the future the DeclGroup should have
- // a separate type-specifier that we can rewrite.
- // NOTE: We need to avoid rewriting the DeclStmt if it is within
- // the context of an ObjCForCollectionStmt. For example:
- // NSArray *someArray;
- // for (id <FooProtocol> index in someArray) ;
- // This is because RewriteObjCForCollectionStmt() does textual rewriting
- // and it depends on the original text locations/positions.
- if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS))
- RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
-
- // Blocks rewrite rules.
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
- Decl *SD = *DI;
- if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
- if (isTopLevelBlockPointerType(ND->getType()))
- RewriteBlockPointerDecl(ND);
- else if (ND->getType()->isFunctionPointerType())
- CheckFunctionPointerDecl(ND->getType(), ND);
- if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {
- if (VD->hasAttr<BlocksAttr>()) {
- static unsigned uniqueByrefDeclCount = 0;
- assert(!BlockByRefDeclNo.count(ND) &&
- "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");
- BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
- RewriteByRefVar(VD);
- }
- else
- RewriteTypeOfDecl(VD);
- }
- }
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
- if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
- RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
- CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // For each implemented class, write out all its meta data.
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteObjCClassMetaData(ClassImplementation[i], Result);
+
+ // For each implemented category, write out all its meta data.
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
+
+ // Write objc_symtab metadata
+ /*
+ struct _objc_symtab
+ {
+ long sel_ref_cnt;
+ SEL *refs;
+ short cls_def_cnt;
+ short cat_def_cnt;
+ void *defs[cls_def_cnt + cat_def_cnt];
+ };
+ */
+
+ Result += "\nstruct _objc_symtab {\n";
+ Result += "\tlong sel_ref_cnt;\n";
+ Result += "\tSEL *refs;\n";
+ Result += "\tshort cls_def_cnt;\n";
+ Result += "\tshort cat_def_cnt;\n";
+ Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
+ Result += "};\n\n";
+
+ Result += "static struct _objc_symtab "
+ "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";
+ Result += "\t0, 0, " + utostr(ClsDefCount)
+ + ", " + utostr(CatDefCount) + "\n";
+ for (int i = 0; i < ClsDefCount; i++) {
+ Result += "\t,&_OBJC_CLASS_";
+ Result += ClassImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ for (int i = 0; i < CatDefCount; i++) {
+ Result += "\t,&_OBJC_CATEGORY_";
+ Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();
+ Result += "_";
+ Result += CategoryImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ Result += "};\n\n";
+
+ // Write objc_module metadata
+
+ /*
+ struct _objc_module {
+ long version;
+ long size;
+ const char *name;
+ struct _objc_symtab *symtab;
+ }
+ */
+
+ Result += "\nstruct _objc_module {\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong size;\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tstruct _objc_symtab *symtab;\n";
+ Result += "};\n\n";
+ Result += "static struct _objc_module "
+ "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
+ Result += "\t" + utostr(OBJC_ABI_VERSION) +
+ ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
+ Result += "};\n\n";
+
+ if (LangOpts.MicrosoftExt) {
+ if (ProtocolExprDecls.size()) {
+ Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I) {
+ Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += " = &_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += ";\n";
}
+ Result += "#pragma data_seg(pop)\n\n";
}
+ Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";
+ Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";
+ Result += "&_OBJC_MODULES;\n";
+ Result += "#pragma data_seg(pop)\n\n";
}
+}
- if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
- RewriteObjCQualifiedInterfaceTypes(CE);
-
- if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
- isa<DoStmt>(S) || isa<ForStmt>(S)) {
- assert(!Stmts.empty() && "Statement stack is empty");
- assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
- isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
- && "Statement stack mismatch");
- Stmts.pop_back();
- }
- // Handle blocks rewriting.
- if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- if (BDRE->isByRef())
- return RewriteBlockDeclRefExpr(BDRE);
+/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
+/// implementation.
+void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
+ // Find category declaration for this implementation.
+ ObjCCategoryDecl *CDecl;
+ for (CDecl = ClassDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->getIdentifier() == IDecl->getIdentifier())
+ break;
+
+ std::string FullCategoryName = ClassDecl->getNameAsString();
+ FullCategoryName += '_';
+ FullCategoryName += IDecl->getNameAsString();
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ InstanceMethods.push_back(Setter);
}
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- ValueDecl *VD = DRE->getDecl();
- if (VD->hasAttr<BlocksAttr>())
- return RewriteBlockDeclRefExpr(DRE);
- if (HasLocalVariableExternalStorage(VD))
- return RewriteLocalVariableExternalStorage(DRE);
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Protocols referenced in class declaration?
+ // Null CDecl is case of a category implementation with no category interface
+ if (CDecl)
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
+ FullCategoryName, Result);
+ /* struct _objc_category {
+ char *category_name;
+ char *class_name;
+ struct _objc_method_list *instance_methods;
+ struct _objc_method_list *class_methods;
+ struct _objc_protocol_list *protocols;
+ // Objective-C 1.0 extensions
+ uint32_t size; // sizeof (struct _objc_category)
+ struct _objc_property_list *instance_properties; // category's own
+ // @property decl.
+ };
+ */
+
+ static bool objc_category = false;
+ if (!objc_category) {
+ Result += "\nstruct _objc_category {\n";
+ Result += "\tchar *category_name;\n";
+ Result += "\tchar *class_name;\n";
+ Result += "\tstruct _objc_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_method_list *class_methods;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tunsigned int size;\n";
+ Result += "\tstruct _objc_property_list *instance_properties;\n";
+ Result += "};\n";
+ objc_category = true;
}
+ Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
+ Result += FullCategoryName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
+ Result += IDecl->getNameAsString();
+ Result += "\"\n\t, \"";
+ Result += ClassDecl->getNameAsString();
+ Result += "\"\n";
- if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
- if (CE->getCallee()->getType()->isBlockPointerType()) {
- Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
- ReplaceStmt(S, BlockCall);
- return BlockCall;
- }
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_INSTANCE_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
}
- if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) {
- RewriteCastExpr(CE);
+ else
+ Result += "\t, 0\n";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_CLASS_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
}
-#if 0
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
- CastExpr *Replacement = new (Context) CastExpr(ICE->getType(),
- ICE->getSubExpr(),
- SourceLocation());
- // Get the new text.
- std::string SStr;
- llvm::raw_string_ostream Buf(SStr);
- Replacement->printPretty(Buf, *Context);
- const std::string &Str = Buf.str();
+ else
+ Result += "\t, 0\n";
+
+ if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ Result += "\t, sizeof(struct _objc_category), 0\n};\n";
+}
- printf("CAST = %s\n", &Str[0]);
- InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
- delete S;
- return Replacement;
+// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
+/// class methods.
+template<typename MethodIterator>
+void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) {
+ if (MethodBegin == MethodEnd) return;
+
+ if (!objc_impl_method) {
+ /* struct _objc_method {
+ SEL _cmd;
+ char *method_types;
+ void *_imp;
+ }
+ */
+ Result += "\nstruct _objc_method {\n";
+ Result += "\tSEL _cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "\tvoid *_imp;\n";
+ Result += "};\n";
+
+ objc_impl_method = true;
+ }
+
+ // Build _objc_method_list for class's methods if needed
+
+ /* struct {
+ struct _objc_method_list *next_method;
+ int method_count;
+ struct _objc_method method_list[];
+ }
+ */
+ unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_method_list *next_method;\n";
+ Result += "\tint method_count;\n";
+ Result += "\tstruct _objc_method method_list[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
+ Result += "_METHODS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __";
+ Result += IsInstanceMethod ? "inst" : "cls";
+ Result += "_meth\")))= ";
+ Result += "{\n\t0, " + utostr(NumMethods) + "\n";
+
+ Result += "\t,{{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
+ Result += "\t ,{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
}
-#endif
- // Return this stmt unmodified.
- return S;
+ Result += "\t }\n};\n";
}
-void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
- if (isTopLevelBlockPointerType(FD->getType()))
- RewriteBlockPointerDecl(FD);
- if (FD->getType()->isObjCQualifiedIdType() ||
- FD->getType()->isObjCQualifiedInterfaceType())
- RewriteObjCQualifiedInterfaceTypes(FD);
+Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
+ SourceRange OldRange = IV->getSourceRange();
+ Expr *BaseExpr = IV->getBase();
+
+ // Rewrite the base, but without actually doing replaces.
+ {
+ DisableReplaceStmtScope S(*this);
+ BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));
+ IV->setBase(BaseExpr);
}
-}
-
-/// HandleDeclInMainFile - This is called for each top-level decl defined in the
-/// main file of the input.
-void RewriteObjC::HandleDeclInMainFile(Decl *D) {
- switch (D->getKind()) {
- case Decl::Function: {
- FunctionDecl *FD = cast<FunctionDecl>(D);
- if (FD->isOverloadedOperator())
- return;
-
- // Since function prototypes don't have ParmDecl's, we check the function
- // prototype. This enables us to rewrite function declarations and
- // definitions using the same code.
- RewriteBlocksInFunctionProtoType(FD->getType(), FD);
-
- // FIXME: If this should support Obj-C++, support CXXTryStmt
- if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
- CurFunctionDef = FD;
- CurFunctionDeclToDeclareForBlock = FD;
- CurrentBody = Body;
- Body =
- cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
- FD->setBody(Body);
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
- }
- // This synthesizes and inserts the block "impl" struct, invoke function,
- // and any copy/dispose helper functions.
- InsertBlockLiteralsWithinFunction(FD);
- CurFunctionDef = 0;
- CurFunctionDeclToDeclareForBlock = 0;
- }
- break;
- }
- case Decl::ObjCMethod: {
- ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
- if (CompoundStmt *Body = MD->getCompoundBody()) {
- CurMethodDef = MD;
- CurrentBody = Body;
- Body =
- cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
- MD->setBody(Body);
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
- }
- InsertBlockLiteralsWithinMethod(MD);
- CurMethodDef = 0;
- }
- break;
- }
- case Decl::ObjCImplementation: {
- ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D);
- ClassImplementation.push_back(CI);
- break;
- }
- case Decl::ObjCCategoryImpl: {
- ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D);
- CategoryImplementation.push_back(CI);
- break;
- }
- case Decl::Var: {
- VarDecl *VD = cast<VarDecl>(D);
- RewriteObjCQualifiedInterfaceTypes(VD);
- if (isTopLevelBlockPointerType(VD->getType()))
- RewriteBlockPointerDecl(VD);
- else if (VD->getType()->isFunctionPointerType()) {
- CheckFunctionPointerDecl(VD->getType(), VD);
- if (VD->getInit()) {
- if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
- }
- }
- } else if (VD->getType()->isRecordType()) {
- RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
- if (RD->isCompleteDefinition())
- RewriteRecordBody(RD);
- }
- if (VD->getInit()) {
- GlobalVarDecl = VD;
- CurrentBody = VD->getInit();
- RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
- }
- SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
- GlobalVarDecl = 0;
-
- // This is needed for blocks.
- if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
- }
- }
- break;
- }
- case Decl::TypeAlias:
- case Decl::Typedef: {
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
- RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
- CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+
+ ObjCIvarDecl *D = IV->getDecl();
+
+ Expr *Replacement = IV;
+ if (CurMethodDef) {
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ const ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CK_BitCast,
+ IV->getBase());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),
+ OldRange.getEnd(),
+ castExpr);
+ if (IV->isFreeIvar() &&
+ CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
+ IV->getLocation(),
+ D->getType(),
+ VK_LValue, OK_Ordinary);
+ Replacement = ME;
+ } else {
+ IV->setBase(PE);
}
- break;
- }
- case Decl::CXXRecord:
- case Decl::Record: {
- RecordDecl *RD = cast<RecordDecl>(D);
- if (RD->isCompleteDefinition())
- RewriteRecordBody(RD);
- break;
}
- case Decl::ObjCClass: {
- llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl");
- break;
+ } else { // we are outside a method.
+ assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
+
+ // Explicit ivar refs need to have a cast inserted.
+ // FIXME: consider sharing some of this code with the code above.
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ const ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CK_BitCast,
+ IV->getBase());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(), castExpr);
+ // Cannot delete IV->getBase(), since PE points to it.
+ // Replace the old base with the cast. This is important when doing
+ // embedded rewrites. For example, [newInv->_container addObject:0].
+ IV->setBase(PE);
}
- default:
- break;
}
- // Nothing yet.
+
+ ReplaceStmtWithRange(IV, Replacement, OldRange);
+ return Replacement;
}
-void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
- if (Diags.hasErrorOccurred())
- return;
-
- RewriteInclude();
-
- // Here's a great place to add any extra declarations that may be needed.
- // Write out meta data for each @protocol(<expr>).
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I)
- RewriteObjCProtocolMetaData(*I, "", "", Preamble);
-
- InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
- if (ClassImplementation.size() || CategoryImplementation.size())
- RewriteImplementations();
-
- // Get the buffer corresponding to MainFileID. If we haven't changed it, then
- // we are done.
- if (const RewriteBuffer *RewriteBuf =
- Rewrite.getRewriteBufferFor(MainFileID)) {
- //printf("Changed:\n");
- *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
- } else {
- llvm::errs() << "No changes\n";
- }
-
- if (ClassImplementation.size() || CategoryImplementation.size() ||
- ProtocolExprDecls.size()) {
- // Rewrite Objective-c meta data*
- std::string ResultStr;
- RewriteMetaDataIntoBuffer(ResultStr);
- // Emit metadata.
- *OutFile << ResultStr;
- }
- OutFile->flush();
-}
More information about the cfe-commits
mailing list