[cfe-commits] r58253 - /cfe/trunk/Driver/RewriteObjC.cpp
Steve Naroff
snaroff at apple.com
Mon Oct 27 10:21:04 PDT 2008
Author: snaroff
Date: Mon Oct 27 12:20:55 2008
New Revision: 58253
URL: http://llvm.org/viewvc/llvm-project?rev=58253&view=rev
Log:
Integrate the blocks and objc rewriters.
Modified:
cfe/trunk/Driver/RewriteObjC.cpp
Modified: cfe/trunk/Driver/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/RewriteObjC.cpp?rev=58253&r1=58252&r2=58253&view=diff
==============================================================================
--- cfe/trunk/Driver/RewriteObjC.cpp (original)
+++ cfe/trunk/Driver/RewriteObjC.cpp Mon Oct 27 12:20:55 2008
@@ -80,7 +80,7 @@
int BcLabelCount;
// Needed for super.
- ObjCMethodDecl *CurMethodDecl;
+ ObjCMethodDecl *CurMethodDef;
RecordDecl *SuperStructDecl;
RecordDecl *ConstantStringDecl;
@@ -91,7 +91,21 @@
std::string OutFileName;
std::string Preamble;
-
+
+ // Block expressions.
+ llvm::SmallVector<BlockExpr *, 32> Blocks;
+ llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
+
+ // Block related declarations.
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+
+ llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
+
+ FunctionDecl *CurFunctionDef;
+
static const int OBJC_ABI_VERSION =7 ;
public:
virtual void Initialize(ASTContext &context);
@@ -231,9 +245,83 @@
ObjCIvarDecl *ivar,
std::string &Result);
void RewriteImplementations(std::string &Result);
+
+ // Block rewriting.
+ void RewriteBlocksInFunctionTypeProto(QualType funcType, NamedDecl *D);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ // Block specific rewrite rules.
+ std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
+
+ void RewriteBlockCall(CallExpr *Exp);
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
+
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers);
+ std::string SynthesizeBlockCall(CallExpr *Exp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName);
+
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockCallExprs(Stmt *S);
+ void GetBlockDeclRefExprs(Stmt *S);
+
+ // We avoid calling Type::isBlockPointerType(), since it operates on the
+ // canonical type. We only care if the top-level type is a closure pointer.
+ bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
+
+ // FIXME: This predicate seems like it would be useful to add to ASTContext.
+ bool isObjCType(QualType T) {
+ if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
+ return false;
+
+ QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
+
+ if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
+ OCT == Context->getCanonicalType(Context->getObjCClassType()))
+ return true;
+
+ if (const PointerType *PT = OCT->getAsPointerType()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ isa<ObjCQualifiedIdType>(PT->getPointeeType()))
+ return true;
+ }
+ return false;
+ }
+ bool PointerTypeTakesAnyBlockArguments(QualType QT);
+ void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
+ void RewriteCastExpr(CastExpr *CE);
};
}
+void RewriteObjC::RewriteBlocksInFunctionTypeProto(QualType funcType,
+ NamedDecl *D) {
+ if (FunctionTypeProto *fproto = dyn_cast<FunctionTypeProto>(funcType)) {
+ for (FunctionTypeProto::arg_type_iterator I = fproto->arg_type_begin(),
+ E = fproto->arg_type_end(); I && (I != E); ++I)
+ if (isBlockPointerType(*I)) {
+ // All the args are checked/rewritten. Don't call twice!
+ RewriteBlockPointerDecl(D);
+ break;
+ }
+ }
+}
+
+void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
+ const PointerType *PT = funcType->getAsPointerType();
+ if (PT && PointerTypeTakesAnyBlockArguments(funcType))
+ RewriteBlocksInFunctionTypeProto(PT->getPointeeType(), ND);
+}
+
static bool IsHeaderFile(const std::string &Filename) {
std::string::size_type DotPos = Filename.rfind('.');
@@ -281,7 +369,8 @@
GetProtocolFunctionDecl = 0;
ConstantStringClassReference = 0;
NSStringRecord = 0;
- CurMethodDecl = 0;
+ CurMethodDef = 0;
+ CurFunctionDef = 0;
SuperStructDecl = 0;
ConstantStringDecl = 0;
BcLabelCount = 0;
@@ -371,6 +460,31 @@
Preamble += "#undef __OBJC_RW_EXTERN\n";
Preamble += "#define __attribute__(X)\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 Size;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "enum {\n";
+ Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
+ Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
+ Preamble += "};\n";
+ if (LangOpts.Microsoft)
+ Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
+ else
+ Preamble += "#define __OBJC_RW_EXTERN extern\n";
+ Preamble += "// Runtime copy/destroy helper functions\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
+ Preamble += "#endif\n";
}
@@ -415,16 +529,29 @@
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
/// main file of the input.
void RewriteObjC::HandleDeclInMainFile(Decl *D) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (Stmt *Body = FD->getBody())
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // 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.
+ RewriteBlocksInFunctionTypeProto(FD->getType(), FD);
+
+ if (Stmt *Body = FD->getBody()) {
+ CurFunctionDef = FD;
FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
-
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ }
+ return;
+ }
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (Stmt *Body = MD->getBody()) {
//Body->dump();
- CurMethodDecl = MD;
+ CurMethodDef = MD;
MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
- CurMethodDecl = 0;
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
}
}
if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
@@ -438,6 +565,54 @@
if (VD->getInit())
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
}
+ // Rewrite rules for blocks.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (isBlockPointerType(VD->getType())) {
+ RewriteBlockPointerDecl(VD);
+ if (VD->getInit()) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
+ RewriteFunctionBodyOrGlobalInitializer(CBE->getBody());
+
+ // We've just rewritten the block body in place.
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
+ RewrittenBlockExprs[CBE] = S;
+ std::string Init = SynthesizeBlockInitExpr(CBE, VD);
+ // Do the rewrite, using S.size() which contains the rewritten size.
+ ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
+ } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ }
+ return;
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ return;
+ }
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ if (RD->isDefinition()) {
+ for (RecordDecl::field_const_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
// Nothing yet.
}
@@ -870,7 +1045,7 @@
Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation OrigStart) {
ObjCIvarDecl *D = IV->getDecl();
- if (CurMethodDecl) {
+ if (CurMethodDef) {
if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
// lookup which class implements the instance variable.
@@ -893,7 +1068,7 @@
IV->getBase()->getLocEnd(),
castExpr);
if (IV->isFreeIvar() &&
- CurMethodDecl->getClassInterface() == iFaceDecl->getDecl()) {
+ CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
MemberExpr *ME = new MemberExpr(PE, true, D, IV->getLocation(),
D->getType());
ReplaceStmt(IV, ME);
@@ -1032,6 +1207,25 @@
// precedes the first Decl. In the future the DeclGroup should have
// a separate type-specifier that we can rewrite.
RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
+
+ // Blocks rewrite rules.
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+
+ ScopedDecl *SD = *DI;
+ if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
+ if (isBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ }
}
if (ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(S))
@@ -1045,6 +1239,18 @@
&& "Statement stack mismatch");
Stmts.pop_back();
}
+ // Handle blocks rewriting.
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (BDRE->isByRef())
+ RewriteBlockDeclRefExpr(BDRE);
+ }
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType())
+ RewriteBlockCall(CE);
+ }
+ if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
+ RewriteCastExpr(CE);
+ }
#if 0
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
@@ -1978,7 +2184,7 @@
ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
// check if we are sending a message to 'super'
- if (!CurMethodDecl || !CurMethodDecl->isInstance()) return 0;
+ if (!CurMethodDef || !CurMethodDef->isInstance()) return 0;
if (PredefinedExpr *PDE = dyn_cast<PredefinedExpr>(recExpr))
if (PDE->getIdentType() == PredefinedExpr::ObjCSuper) {
@@ -2086,13 +2292,13 @@
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
ObjCInterfaceDecl *SuperDecl =
- CurMethodDecl->getClassInterface()->getSuperClass();
+ CurMethodDef->getClassInterface()->getSuperClass();
llvm::SmallVector<Expr*, 4> InitExprs;
// set the receiver to self, the first argument to all methods.
InitExprs.push_back(new DeclRefExpr(
- CurMethodDecl->getSelfDecl(),
+ CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()));
llvm::SmallVector<Expr*, 8> ClsExprs;
@@ -2157,7 +2363,7 @@
InitExprs.push_back(
new ExplicitCastExpr(Context->getObjCIdType(),
- new DeclRefExpr(CurMethodDecl->getSelfDecl(),
+ new DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()),
SourceLocation())); // set the 'receiver'.
@@ -3229,6 +3435,627 @@
}
}
+std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ const FunctionType *AFT = CE->getFunctionType();
+ QualType RT = AFT->getResultType();
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static " + RT.getAsString() + " __" +
+ funcName + "_" + "block_func_" + utostr(i);
+
+ BlockDecl *BD = CE->getBlockDecl();
+
+ if (isa<FunctionTypeNoProto>(AFT)) {
+ S += "()";
+ } else if (BD->param_empty()) {
+ S += "(" + StructRef + " *__cself)";
+ } else {
+ const FunctionTypeProto *FT = cast<FunctionTypeProto>(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)->getName();
+ (*AI)->getType().getAsStringInternal(ParamStr);
+ 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 (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getName();
+ Context->getPointerType((*I)->getType()).getAsStringInternal(Name);
+ S += Name + " = __cself->" + (*I)->getName() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getName();
+ // 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 (isBlockPointerType((*I)->getType()))
+ S += "struct __block_impl *";
+ else
+ (*I)->getType().getAsStringInternal(Name);
+ S += Name + " = __cself->" + (*I)->getName() + "; // bound by copy\n";
+ }
+ std::string RewrittenStr = RewrittenBlockExprs[CE];
+ const char *cstr = RewrittenStr.c_str();
+ while (*cstr++ != '{') ;
+ S += cstr;
+ S += "\n";
+ return S;
+}
+
+std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static void __";
+
+ 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) {
+ S += "_Block_copy_assign(&dst->";
+ S += (*I)->getName();
+ S += ", src->";
+ S += (*I)->getName();
+ S += ");}";
+ }
+ 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) {
+ S += "_Block_destroy(src->";
+ S += (*I)->getName();
+ S += ");";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers) {
+ std::string S = "struct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+
+ if (hasCopyDisposeHelpers)
+ S += " void *copy;\n void *dispose;\n";
+
+ Constructor += "(void *fp";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += ", void *copyHelp, void *disposeHelp";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getName();
+ 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 (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ (*I)->getType().getAsStringInternal(FieldName);
+ (*I)->getType().getAsStringInternal(ArgName);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getName();
+ 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 (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName);
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+
+ // Initialize all "by copy" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getName();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ // Initialize all "by ref" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getName();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ } else {
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName) {
+ // Insert closures that were part of the function.
+ for (unsigned i = 0; i < Blocks.size(); i++) {
+ CollectBlockDeclRefInfo(Blocks[i]);
+
+ std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+ ImportedBlockDecls.size() > 0);
+
+ InsertText(FunLocStart, CI.c_str(), CI.size());
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+
+ InsertText(FunLocStart, CF.c_str(), CF.size());
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ BlockCallExprs.clear();
+ ImportedBlockDecls.clear();
+ }
+ Blocks.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const char *FuncName = FD->getName();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName = std::string(MD->getSelector().getName());
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
+}
+
+void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++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);
+ return;
+}
+
+void RewriteObjC::GetBlockCallExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockCallExprs(CBE->getBody());
+ else
+ GetBlockCallExprs(*CI);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
+ }
+ }
+ return;
+}
+
+std::string RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
+ // Navigate to relevant type information.
+ const char *closureName = 0;
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
+ closureName = DRE->getDecl()->getName();
+ CPT = DRE->getType()->getAsBlockPointerType();
+ } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
+ closureName = CDRE->getDecl()->getName();
+ CPT = CDRE->getType()->getAsBlockPointerType();
+ } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
+ closureName = MExpr->getMemberDecl()->getName();
+ CPT = MExpr->getType()->getAsBlockPointerType();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FT);
+ // FTP will be null for closures that don't take arguments.
+
+ // Build a closure call - start with a paren expr to enforce precedence.
+ std::string BlockCall = "(";
+
+ // Synthesize the cast.
+ BlockCall += "(" + Exp->getType().getAsString() + "(*)";
+ BlockCall += "(struct __block_impl *";
+ if (FTP) {
+ for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I)
+ BlockCall += ", " + (*I).getAsString();
+ }
+ BlockCall += "))"; // close the argument list and paren expression.
+
+ // Invoke the closure. We need to cast it since the declaration type is
+ // bogus (it's a function pointer type)
+ BlockCall += "((struct __block_impl *)";
+ std::string closureExprBufStr;
+ llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
+ Exp->getCallee()->printPretty(closureExprBuf);
+ BlockCall += closureExprBuf.str();
+ BlockCall += ")->FuncPtr)";
+
+ // Add the arguments.
+ BlockCall += "((struct __block_impl *)";
+ BlockCall += closureExprBuf.str();
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ std::string syncExprBufS;
+ llvm::raw_string_ostream Buf(syncExprBufS);
+ (*I)->printPretty(Buf);
+ BlockCall += ", " + Buf.str();
+ }
+ return BlockCall;
+}
+
+void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
+ std::string BlockCall = SynthesizeBlockCall(Exp);
+
+ const char *startBuf = SM->getCharacterData(Exp->getLocStart());
+ const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
+
+ ReplaceText(Exp->getLocStart(), endBuf-startBuf,
+ BlockCall.c_str(), BlockCall.size());
+}
+
+void RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+ // FIXME: Add more elaborate code generation required by the ABI.
+ InsertText(BDRE->getLocStart(), "*", 1);
+}
+
+void RewriteObjC::RewriteCastExpr(CastExpr *CE) {
+ SourceLocation LocStart = CE->getLocStart();
+ SourceLocation LocEnd = CE->getLocEnd();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // advance the location to startArgList.
+ const char *argPtr = startBuf;
+
+ while (*argPtr++ && (argPtr < endBuf)) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*", 1);
+ break;
+ }
+ }
+ 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.getFileLocWithOffset(startArgList-startBuf);
+ assert((DeclLoc.isValid()) && "Invalid DeclLoc");
+
+ const char *argPtr = startArgList;
+
+ while (*argPtr++ && parenCount) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionTypeProto *FTP;
+ const PointerType *PT = QT->getAsPointerType();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAsFunctionTypeProto();
+ } else {
+ const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAsFunctionTypeProto();
+ }
+ if (FTP) {
+ for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isBlockPointerType(*I))
+ return true;
+ }
+ 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");
+
+ 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++;
+ }
+ assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
+ RParen = argPtr; // output the end
+}
+
+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 (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
+ DeclT = TDD->getUnderlyingType();
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ DeclT = FD->getType();
+ else
+ assert(0 && "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--;
+
+ // *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.
+ DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ }
+ if (PointerTypeTakesAnyBlockArguments(DeclT)) {
+ // Replace the '^' with '*' for arguments.
+ DeclLoc = ND->getLocation();
+ startBuf = SM->getCharacterData(DeclLoc);
+ const char *argListBegin, *argListEnd;
+ GetExtentOfArgList(startBuf, argListBegin, argListEnd);
+ while (argListBegin < argListEnd) {
+ if (*argListBegin == '^') {
+ SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
+ ReplaceText(CaretLoc, 1, "*", 1);
+ }
+ argListBegin++;
+ }
+ }
+ 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())
+ BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
+ GetBlockCallExprs(Blocks[i]);
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ }
+}
+
+std::string RewriteObjC::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = std::string(CurFunctionDef->getName());
+ else if (CurMethodDef) {
+ FuncName = std::string(CurMethodDef->getSelector().getName());
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+ } else if (VD)
+ FuncName = std::string(VD->getName());
+
+ std::string BlockNumber = utostr(Blocks.size()-1);
+
+ std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
+
+ std::string FunkTypeStr;
+
+ // Get a pointer to the function type so we can cast appropriately.
+ Context->getPointerType(QualType(Exp->getFunctionType(),0)).getAsStringInternal(FunkTypeStr);
+
+ // Rewrite the closure block with a compound literal. The first cast is
+ // to prevent warnings from the C compiler.
+ std::string Init = "(" + FunkTypeStr;
+
+ Init += ")&" + Tag;
+
+ // Initialize the block function.
+ Init += "((void*)" + Func;
+
+ if (ImportedBlockDecls.size()) {
+ std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ }
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ Init += ",";
+ if (isObjCType((*I)->getType())) {
+ Init += "[[";
+ Init += (*I)->getName();
+ Init += " retain] autorelease]";
+ } else if (isBlockPointerType((*I)->getType())) {
+ Init += "(void *)";
+ Init += (*I)->getName();
+ } else {
+ Init += (*I)->getName();
+ }
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ Init += ",&";
+ Init += (*I)->getName();
+ }
+ }
+ Init += ")";
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ ImportedBlockDecls.clear();
+
+ return Init;
+}
More information about the cfe-commits
mailing list