blob: b7cdb48aab038787669ffdb28a04ed365fc56ef3 [file] [log] [blame]
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001//===--- RewriteBlocks.cpp ----------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the closure rewriter.
11//
12//===----------------------------------------------------------------------===//
13
Eli Friedman39d7c4d2009-05-18 22:50:54 +000014#include "clang/Frontend/ASTConsumers.h"
Steve Naroff1c9f81b2008-09-17 00:13:27 +000015#include "clang/Rewrite/Rewriter.h"
16#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
18#include "clang/Basic/SourceManager.h"
19#include "clang/Basic/IdentifierTable.h"
20#include "clang/Basic/Diagnostic.h"
21#include "clang/Basic/LangOptions.h"
22#include "llvm/Support/MemoryBuffer.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/SmallPtrSet.h"
25#include <sstream>
26
27using namespace clang;
28using llvm::utostr;
29
30namespace {
31
32class RewriteBlocks : public ASTConsumer {
33 Rewriter Rewrite;
34 Diagnostic &Diags;
35 const LangOptions &LangOpts;
36 unsigned RewriteFailedDiag;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000037
38 ASTContext *Context;
39 SourceManager *SM;
Chris Lattner2b2453a2009-01-17 06:22:33 +000040 FileID MainFileID;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000041 const char *MainFileStart, *MainFileEnd;
42
43 // Block expressions.
44 llvm::SmallVector<BlockExpr *, 32> Blocks;
45 llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
46 llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
47
48 // Block related declarations.
49 llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
50 llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
Steve Naroff4e13b762008-10-03 20:28:15 +000051 llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
Steve Naroff70f95502008-10-04 17:06:23 +000052
53 llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000054
55 // The function/method we are rewriting.
56 FunctionDecl *CurFunctionDef;
57 ObjCMethodDecl *CurMethodDef;
58
59 bool IsHeader;
Steve Naroffa0b75cf2008-10-02 23:30:43 +000060
61 std::string Preamble;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000062public:
Eli Friedman66d6f042009-05-18 22:20:00 +000063 RewriteBlocks(std::string inFile, Diagnostic &D,
Steve Naroff13188952008-09-18 14:10:13 +000064 const LangOptions &LOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000065 ~RewriteBlocks() {
66 // Get the buffer corresponding to MainFileID.
67 // If we haven't changed it, then we are done.
68 if (const RewriteBuffer *RewriteBuf =
69 Rewrite.getRewriteBufferFor(MainFileID)) {
70 std::string S(RewriteBuf->begin(), RewriteBuf->end());
71 printf("%s\n", S.c_str());
72 } else {
73 printf("No changes\n");
74 }
75 }
76
77 void Initialize(ASTContext &context);
78
79 void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
80 void ReplaceText(SourceLocation Start, unsigned OrigLength,
81 const char *NewStr, unsigned NewLength);
82
83 // Top Level Driver code.
Chris Lattner682bf922009-03-29 16:50:03 +000084 virtual void HandleTopLevelDecl(DeclGroupRef D) {
85 for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
86 HandleTopLevelSingleDecl(*I);
87 }
88 void HandleTopLevelSingleDecl(Decl *D);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000089 void HandleDeclInMainFile(Decl *D);
90
91 // Top level
92 Stmt *RewriteFunctionBody(Stmt *S);
93 void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
94 void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
95
96 // Block specific rewrite rules.
Steve Naroff70f95502008-10-04 17:06:23 +000097 std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000098
99 void RewriteBlockCall(CallExpr *Exp);
100 void RewriteBlockPointerDecl(NamedDecl *VD);
Steve Naroff5e52b172008-10-04 18:52:47 +0000101 void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000102 void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
103
Steve Naroff4e13b762008-10-03 20:28:15 +0000104 std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
105 const char *funcName, std::string Tag);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000106 std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
107 const char *funcName, std::string Tag);
Steve Naroffacba0f22008-10-04 23:47:37 +0000108 std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
109 bool hasCopyDisposeHelpers);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000110 std::string SynthesizeBlockCall(CallExpr *Exp);
111 void SynthesizeBlockLiterals(SourceLocation FunLocStart,
112 const char *FunName);
113
Steve Naroffd3f77902008-10-05 00:06:12 +0000114 void CollectBlockDeclRefInfo(BlockExpr *Exp);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000115 void GetBlockCallExprs(Stmt *S);
Steve Naroffacba0f22008-10-04 23:47:37 +0000116 void GetBlockDeclRefExprs(Stmt *S);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000117
118 // We avoid calling Type::isBlockPointerType(), since it operates on the
119 // canonical type. We only care if the top-level type is a closure pointer.
120 bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
121
122 // FIXME: This predicate seems like it would be useful to add to ASTContext.
123 bool isObjCType(QualType T) {
124 if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
125 return false;
126
127 QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
128
129 if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
130 OCT == Context->getCanonicalType(Context->getObjCClassType()))
131 return true;
132
Ted Kremenek6217b802009-07-29 21:53:49 +0000133 if (const PointerType *PT = OCT->getAs<PointerType>()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000134 if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
Steve Naroffd1b3c2d2009-06-17 22:40:22 +0000135 PT->getPointeeType()->isObjCQualifiedIdType())
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000136 return true;
137 }
138 return false;
139 }
140 // ObjC rewrite methods.
141 void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
142 void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
143 void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
144 void RewriteMethodDecl(ObjCMethodDecl *MDecl);
Steve Naroffca743602008-10-15 18:38:58 +0000145
Douglas Gregor72564e72009-02-26 23:50:07 +0000146 void RewriteFunctionProtoType(QualType funcType, NamedDecl *D);
Steve Naroffca743602008-10-15 18:38:58 +0000147 void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
148 void RewriteCastExpr(CastExpr *CE);
Steve Naroffeab5f632008-09-23 19:24:41 +0000149
Steve Naroffca743602008-10-15 18:38:58 +0000150 bool PointerTypeTakesAnyBlockArguments(QualType QT);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000151 void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000152};
153
154}
155
156static bool IsHeaderFile(const std::string &Filename) {
157 std::string::size_type DotPos = Filename.rfind('.');
158
159 if (DotPos == std::string::npos) {
160 // no file extension
161 return false;
162 }
163
164 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
165 // C header: .h
166 // C++ header: .hh or .H;
167 return Ext == "h" || Ext == "hh" || Ext == "H";
168}
169
Eli Friedman66d6f042009-05-18 22:20:00 +0000170RewriteBlocks::RewriteBlocks(std::string inFile,
Steve Naroff13188952008-09-18 14:10:13 +0000171 Diagnostic &D, const LangOptions &LOpts) :
172 Diags(D), LangOpts(LOpts) {
173 IsHeader = IsHeaderFile(inFile);
Steve Naroff13188952008-09-18 14:10:13 +0000174 CurFunctionDef = 0;
175 CurMethodDef = 0;
176 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
177 "rewriting failed");
Steve Naroff13188952008-09-18 14:10:13 +0000178}
179
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000180ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
181 Diagnostic &Diags,
182 const LangOptions &LangOpts) {
Eli Friedman66d6f042009-05-18 22:20:00 +0000183 return new RewriteBlocks(InFile, Diags, LangOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000184}
185
186void RewriteBlocks::Initialize(ASTContext &context) {
187 Context = &context;
188 SM = &Context->getSourceManager();
189
190 // Get the ID and start/end of the main file.
191 MainFileID = SM->getMainFileID();
192 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
193 MainFileStart = MainBuf->getBufferStart();
194 MainFileEnd = MainBuf->getBufferEnd();
195
Chris Lattner2c78b872009-04-14 23:22:57 +0000196 Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000197
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000198 if (IsHeader)
199 Preamble = "#pragma once\n";
200 Preamble += "#ifndef BLOCK_IMPL\n";
201 Preamble += "#define BLOCK_IMPL\n";
202 Preamble += "struct __block_impl {\n";
203 Preamble += " void *isa;\n";
204 Preamble += " int Flags;\n";
205 Preamble += " int Size;\n";
206 Preamble += " void *FuncPtr;\n";
207 Preamble += "};\n";
208 Preamble += "enum {\n";
209 Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
210 Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
211 Preamble += "};\n";
212 if (LangOpts.Microsoft)
213 Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
214 else
215 Preamble += "#define __OBJC_RW_EXTERN extern\n";
216 Preamble += "// Runtime copy/destroy helper functions\n";
217 Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
218 Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
219 Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
220 Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000221 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
222 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000223 Preamble += "#endif\n";
224
Chris Lattner2b2453a2009-01-17 06:22:33 +0000225 InsertText(SM->getLocForStartOfFile(MainFileID),
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000226 Preamble.c_str(), Preamble.size());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000227}
228
229void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
230 unsigned StrLen)
231{
232 if (!Rewrite.InsertText(Loc, StrData, StrLen))
233 return;
234 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
235}
236
237void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
238 const char *NewStr, unsigned NewLength) {
Daniel Dunbard7407dc2009-08-19 19:10:30 +0000239 if (!Rewrite.ReplaceText(Start, OrigLength,
240 llvm::StringRef(NewStr, NewLength)))
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000241 return;
242 Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
243}
244
245void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
246 bool haveBlockPtrs = false;
247 for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
248 E = Method->param_end(); I != E; ++I)
249 if (isBlockPointerType((*I)->getType()))
250 haveBlockPtrs = true;
251
252 if (!haveBlockPtrs)
253 return;
254
255 // Do a fuzzy rewrite.
256 // We have 1 or more arguments that have closure pointers.
257 SourceLocation Loc = Method->getLocStart();
258 SourceLocation LocEnd = Method->getLocEnd();
259 const char *startBuf = SM->getCharacterData(Loc);
260 const char *endBuf = SM->getCharacterData(LocEnd);
261
262 const char *methodPtr = startBuf;
Steve Naroff8af6a452008-10-02 17:12:56 +0000263 std::string Tag = "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000264
265 while (*methodPtr++ && (methodPtr != endBuf)) {
266 switch (*methodPtr) {
267 case ':':
268 methodPtr++;
269 if (*methodPtr == '(') {
270 const char *scanType = ++methodPtr;
271 bool foundBlockPointer = false;
272 unsigned parenCount = 1;
273
274 while (parenCount) {
275 switch (*scanType) {
276 case '(':
277 parenCount++;
278 break;
279 case ')':
280 parenCount--;
281 break;
282 case '^':
283 foundBlockPointer = true;
284 break;
285 }
286 scanType++;
287 }
288 if (foundBlockPointer) {
289 // advance the location to startArgList.
290 Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
291 assert((Loc.isValid()) && "Invalid Loc");
292 ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
293
294 // Advance startBuf. Since the underlying buffer has changed,
295 // it's very important to advance startBuf (so we can correctly
296 // compute a relative Loc the next time around).
297 startBuf = methodPtr;
298 }
299 // Advance the method ptr to the end of the type.
300 methodPtr = scanType;
301 }
302 break;
303 }
304 }
305 return;
306}
307
308void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
Douglas Gregor6ab35242009-04-09 21:40:53 +0000309 for (ObjCInterfaceDecl::instmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000310 I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000311 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000312 RewriteMethodDecl(*I);
Douglas Gregor6ab35242009-04-09 21:40:53 +0000313 for (ObjCInterfaceDecl::classmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000314 I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000315 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000316 RewriteMethodDecl(*I);
317}
318
319void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
Douglas Gregor6ab35242009-04-09 21:40:53 +0000320 for (ObjCCategoryDecl::instmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000321 I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000322 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000323 RewriteMethodDecl(*I);
Douglas Gregor6ab35242009-04-09 21:40:53 +0000324 for (ObjCCategoryDecl::classmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000325 I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000326 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000327 RewriteMethodDecl(*I);
328}
329
330void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
Douglas Gregor6ab35242009-04-09 21:40:53 +0000331 for (ObjCProtocolDecl::instmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000332 I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000333 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000334 RewriteMethodDecl(*I);
Douglas Gregor6ab35242009-04-09 21:40:53 +0000335 for (ObjCProtocolDecl::classmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000336 I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000337 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000338 RewriteMethodDecl(*I);
339}
340
341//===----------------------------------------------------------------------===//
342// Top Level Driver Code
343//===----------------------------------------------------------------------===//
344
Chris Lattner682bf922009-03-29 16:50:03 +0000345void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000346 // Two cases: either the decl could be in the main file, or it could be in a
347 // #included file. If the former, rewrite it now. If the later, check to see
348 // if we rewrote the #include/#import.
349 SourceLocation Loc = D->getLocation();
Chris Lattnerf7cf85b2009-01-16 07:36:28 +0000350 Loc = SM->getInstantiationLoc(Loc);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000351
352 // If this is for a builtin, ignore it.
353 if (Loc.isInvalid()) return;
354
355 if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
356 RewriteInterfaceDecl(MD);
357 else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
358 RewriteCategoryDecl(CD);
359 else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
360 RewriteProtocolDecl(PD);
361
362 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner23f2c582009-01-25 22:02:19 +0000363 if (SM->isFromMainFile(Loc))
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000364 HandleDeclInMainFile(D);
365 return;
366}
367
368std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
369 const char *funcName,
370 std::string Tag) {
371 const FunctionType *AFT = CE->getFunctionType();
372 QualType RT = AFT->getResultType();
Steve Naroff48a8c612008-10-03 12:09:49 +0000373 std::string StructRef = "struct " + Tag;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000374 std::string S = "static " + RT.getAsString() + " __" +
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000375 funcName + "_" + "block_func_" + utostr(i);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000376
Steve Naroff56ee6892008-10-08 17:01:13 +0000377 BlockDecl *BD = CE->getBlockDecl();
378
Douglas Gregor72564e72009-02-26 23:50:07 +0000379 if (isa<FunctionNoProtoType>(AFT)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000380 S += "()";
Steve Naroff56ee6892008-10-08 17:01:13 +0000381 } else if (BD->param_empty()) {
Steve Naroff48a8c612008-10-03 12:09:49 +0000382 S += "(" + StructRef + " *__cself)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000383 } else {
Douglas Gregor72564e72009-02-26 23:50:07 +0000384 const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000385 assert(FT && "SynthesizeBlockFunc: No function proto");
386 S += '(';
387 // first add the implicit argument.
Steve Naroff48a8c612008-10-03 12:09:49 +0000388 S += StructRef + " *__cself, ";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000389 std::string ParamStr;
Steve Naroff56ee6892008-10-08 17:01:13 +0000390 for (BlockDecl::param_iterator AI = BD->param_begin(),
391 E = BD->param_end(); AI != E; ++AI) {
392 if (AI != BD->param_begin()) S += ", ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000393 ParamStr = (*AI)->getNameAsString();
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000394 (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000395 S += ParamStr;
396 }
397 if (FT->isVariadic()) {
Steve Naroff56ee6892008-10-08 17:01:13 +0000398 if (!BD->param_empty()) S += ", ";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000399 S += "...";
400 }
401 S += ')';
402 }
403 S += " {\n";
404
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000405 // Create local declarations to avoid rewriting all closure decl ref exprs.
406 // First, emit a declaration for all "by ref" decls.
407 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
408 E = BlockByRefDecls.end(); I != E; ++I) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000409 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000410 std::string Name = (*I)->getNameAsString();
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000411 Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
412 Context->PrintingPolicy);
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000413 S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000414 }
415 // Next, emit a declaration for all "by copy" declarations.
416 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
417 E = BlockByCopyDecls.end(); I != E; ++I) {
418 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000419 std::string Name = (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000420 // Handle nested closure invocation. For example:
421 //
422 // void (^myImportedClosure)(void);
423 // myImportedClosure = ^(void) { setGlobalInt(x + y); };
424 //
425 // void (^anotherClosure)(void);
426 // anotherClosure = ^(void) {
427 // myImportedClosure(); // import and invoke the closure
428 // };
429 //
430 if (isBlockPointerType((*I)->getType()))
Steve Naroff8af6a452008-10-02 17:12:56 +0000431 S += "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000432 else
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000433 (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000434 S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000435 }
Steve Naroff70f95502008-10-04 17:06:23 +0000436 std::string RewrittenStr = RewrittenBlockExprs[CE];
437 const char *cstr = RewrittenStr.c_str();
438 while (*cstr++ != '{') ;
439 S += cstr;
440 S += "\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000441 return S;
442}
443
Steve Naroff4e13b762008-10-03 20:28:15 +0000444std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
445 const char *funcName,
446 std::string Tag) {
447 std::string StructRef = "struct " + Tag;
448 std::string S = "static void __";
449
450 S += funcName;
451 S += "_block_copy_" + utostr(i);
452 S += "(" + StructRef;
453 S += "*dst, " + StructRef;
454 S += "*src) {";
455 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
456 E = ImportedBlockDecls.end(); I != E; ++I) {
457 S += "_Block_copy_assign(&dst->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000458 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000459 S += ", src->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000460 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000461 S += ");}";
462 }
463 S += "\nstatic void __";
464 S += funcName;
465 S += "_block_dispose_" + utostr(i);
466 S += "(" + StructRef;
467 S += "*src) {";
468 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
469 E = ImportedBlockDecls.end(); I != E; ++I) {
470 S += "_Block_destroy(src->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000471 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000472 S += ");";
473 }
474 S += "}\n";
475 return S;
476}
477
Steve Naroffacba0f22008-10-04 23:47:37 +0000478std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
479 bool hasCopyDisposeHelpers) {
Steve Naroff48a8c612008-10-03 12:09:49 +0000480 std::string S = "struct " + Tag;
481 std::string Constructor = " " + Tag;
482
483 S += " {\n struct __block_impl impl;\n";
Steve Naroffacba0f22008-10-04 23:47:37 +0000484
485 if (hasCopyDisposeHelpers)
486 S += " void *copy;\n void *dispose;\n";
487
Steve Naroff48a8c612008-10-03 12:09:49 +0000488 Constructor += "(void *fp";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000489
Steve Naroffacba0f22008-10-04 23:47:37 +0000490 if (hasCopyDisposeHelpers)
491 Constructor += ", void *copyHelp, void *disposeHelp";
492
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000493 if (BlockDeclRefs.size()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000494 // Output all "by copy" declarations.
495 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
496 E = BlockByCopyDecls.end(); I != E; ++I) {
497 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000498 std::string FieldName = (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000499 std::string ArgName = "_" + FieldName;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000500 // Handle nested closure invocation. For example:
501 //
502 // void (^myImportedBlock)(void);
503 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
504 //
505 // void (^anotherBlock)(void);
506 // anotherBlock = ^(void) {
507 // myImportedBlock(); // import and invoke the closure
508 // };
509 //
Steve Naroff4e13b762008-10-03 20:28:15 +0000510 if (isBlockPointerType((*I)->getType())) {
Steve Naroff8af6a452008-10-02 17:12:56 +0000511 S += "struct __block_impl *";
Steve Naroff4e13b762008-10-03 20:28:15 +0000512 Constructor += ", void *" + ArgName;
513 } else {
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000514 (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
515 (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
Steve Naroff4e13b762008-10-03 20:28:15 +0000516 Constructor += ", " + ArgName;
Steve Naroff48a8c612008-10-03 12:09:49 +0000517 }
Steve Naroff4e13b762008-10-03 20:28:15 +0000518 S += FieldName + ";\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000519 }
520 // Output all "by ref" declarations.
521 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
522 E = BlockByRefDecls.end(); I != E; ++I) {
523 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000524 std::string FieldName = (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000525 std::string ArgName = "_" + FieldName;
526 // Handle nested closure invocation. For example:
527 //
528 // void (^myImportedBlock)(void);
529 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
530 //
531 // void (^anotherBlock)(void);
532 // anotherBlock = ^(void) {
533 // myImportedBlock(); // import and invoke the closure
534 // };
535 //
536 if (isBlockPointerType((*I)->getType())) {
Steve Naroff8af6a452008-10-02 17:12:56 +0000537 S += "struct __block_impl *";
Steve Naroff4e13b762008-10-03 20:28:15 +0000538 Constructor += ", void *" + ArgName;
539 } else {
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000540 Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
541 Context->PrintingPolicy);
542 Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
543 Context->PrintingPolicy);
Steve Naroff4e13b762008-10-03 20:28:15 +0000544 Constructor += ", " + ArgName;
Steve Naroff48a8c612008-10-03 12:09:49 +0000545 }
Steve Naroff4e13b762008-10-03 20:28:15 +0000546 S += FieldName + "; // by ref\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000547 }
548 // Finish writing the constructor.
549 // FIXME: handle NSConcreteGlobalBlock.
550 Constructor += ", int flags=0) {\n";
Steve Naroff83ba14e2008-10-03 15:04:50 +0000551 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
Steve Naroff48a8c612008-10-03 12:09:49 +0000552 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
553
Steve Naroffacba0f22008-10-04 23:47:37 +0000554 if (hasCopyDisposeHelpers)
555 Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
556
Steve Naroff48a8c612008-10-03 12:09:49 +0000557 // Initialize all "by copy" arguments.
558 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
559 E = BlockByCopyDecls.end(); I != E; ++I) {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000560 std::string Name = (*I)->getNameAsString();
Steve Naroff48a8c612008-10-03 12:09:49 +0000561 Constructor += " ";
Steve Naroff4e13b762008-10-03 20:28:15 +0000562 if (isBlockPointerType((*I)->getType()))
563 Constructor += Name + " = (struct __block_impl *)_";
564 else
565 Constructor += Name + " = _";
Steve Naroff48a8c612008-10-03 12:09:49 +0000566 Constructor += Name + ";\n";
567 }
568 // Initialize all "by ref" arguments.
569 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
570 E = BlockByRefDecls.end(); I != E; ++I) {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000571 std::string Name = (*I)->getNameAsString();
Steve Naroff48a8c612008-10-03 12:09:49 +0000572 Constructor += " ";
Steve Naroff4e13b762008-10-03 20:28:15 +0000573 if (isBlockPointerType((*I)->getType()))
574 Constructor += Name + " = (struct __block_impl *)_";
575 else
576 Constructor += Name + " = _";
Steve Naroff48a8c612008-10-03 12:09:49 +0000577 Constructor += Name + ";\n";
578 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000579 } else {
580 // Finish writing the constructor.
581 // FIXME: handle NSConcreteGlobalBlock.
582 Constructor += ", int flags=0) {\n";
583 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
584 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
Steve Naroffacba0f22008-10-04 23:47:37 +0000585 if (hasCopyDisposeHelpers)
586 Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000587 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000588 Constructor += " ";
589 Constructor += "}\n";
590 S += Constructor;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000591 S += "};\n";
592 return S;
593}
594
595void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
596 const char *FunName) {
597 // Insert closures that were part of the function.
598 for (unsigned i = 0; i < Blocks.size(); i++) {
Steve Naroffacba0f22008-10-04 23:47:37 +0000599
Steve Naroffd3f77902008-10-05 00:06:12 +0000600 CollectBlockDeclRefInfo(Blocks[i]);
601
Steve Naroff48a8c612008-10-03 12:09:49 +0000602 std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000603
Steve Naroffacba0f22008-10-04 23:47:37 +0000604 std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
605 ImportedBlockDecls.size() > 0);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000606
607 InsertText(FunLocStart, CI.c_str(), CI.size());
Steve Naroff4e13b762008-10-03 20:28:15 +0000608
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000609 std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
610
611 InsertText(FunLocStart, CF.c_str(), CF.size());
612
Steve Naroff4e13b762008-10-03 20:28:15 +0000613 if (ImportedBlockDecls.size()) {
614 std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
615 InsertText(FunLocStart, HF.c_str(), HF.size());
616 }
617
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000618 BlockDeclRefs.clear();
619 BlockByRefDecls.clear();
620 BlockByCopyDecls.clear();
621 BlockCallExprs.clear();
Steve Naroff4e13b762008-10-03 20:28:15 +0000622 ImportedBlockDecls.clear();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000623 }
624 Blocks.clear();
Steve Naroff8e9216d2008-10-04 17:10:02 +0000625 RewrittenBlockExprs.clear();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000626}
627
628void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
Steve Naroff3ad29e22008-10-03 00:12:09 +0000629 SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
Chris Lattner8ec03f52008-11-24 03:54:41 +0000630 const char *FuncName = FD->getNameAsCString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000631
632 SynthesizeBlockLiterals(FunLocStart, FuncName);
633}
634
635void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
636 SourceLocation FunLocStart = MD->getLocStart();
Chris Lattner077bf5e2008-11-24 03:33:13 +0000637 std::string FuncName = MD->getSelector().getAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000638 // Convert colons to underscores.
639 std::string::size_type loc = 0;
640 while ((loc = FuncName.find(":", loc)) != std::string::npos)
641 FuncName.replace(loc, 1, "_");
642
643 SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
644}
645
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000646void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
647 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
648 CI != E; ++CI)
Steve Naroff84a969f2008-10-08 17:31:13 +0000649 if (*CI) {
650 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
651 GetBlockDeclRefExprs(CBE->getBody());
652 else
653 GetBlockDeclRefExprs(*CI);
654 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000655 // Handle specific things.
656 if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
657 // FIXME: Handle enums.
658 if (!isa<FunctionDecl>(CDRE->getDecl()))
659 BlockDeclRefs.push_back(CDRE);
660 return;
661}
662
663void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
664 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
665 CI != E; ++CI)
Steve Naroff84a969f2008-10-08 17:31:13 +0000666 if (*CI) {
667 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
668 GetBlockCallExprs(CBE->getBody());
669 else
670 GetBlockCallExprs(*CI);
671 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000672
673 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
Steve Naroff4e13b762008-10-03 20:28:15 +0000674 if (CE->getCallee()->getType()->isBlockPointerType()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000675 BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
Steve Naroff4e13b762008-10-03 20:28:15 +0000676 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000677 }
678 return;
679}
680
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000681std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
682 // Navigate to relevant type information.
Steve Naroffcc2ece22008-09-24 22:46:45 +0000683 const char *closureName = 0;
684 const BlockPointerType *CPT = 0;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000685
686 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000687 closureName = DRE->getDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000688 CPT = DRE->getType()->getAs<BlockPointerType>();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000689 } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000690 closureName = CDRE->getDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000691 CPT = CDRE->getType()->getAs<BlockPointerType>();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000692 } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000693 closureName = MExpr->getMemberDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000694 CPT = MExpr->getType()->getAs<BlockPointerType>();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000695 } else {
696 assert(1 && "RewriteBlockClass: Bad type");
697 }
698 assert(CPT && "RewriteBlockClass: Bad type");
699 const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
700 assert(FT && "RewriteBlockClass: Bad type");
Douglas Gregor72564e72009-02-26 23:50:07 +0000701 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000702 // FTP will be null for closures that don't take arguments.
703
704 // Build a closure call - start with a paren expr to enforce precedence.
705 std::string BlockCall = "(";
706
707 // Synthesize the cast.
708 BlockCall += "(" + Exp->getType().getAsString() + "(*)";
Steve Naroff8af6a452008-10-02 17:12:56 +0000709 BlockCall += "(struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000710 if (FTP) {
Douglas Gregor72564e72009-02-26 23:50:07 +0000711 for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000712 E = FTP->arg_type_end(); I && (I != E); ++I)
713 BlockCall += ", " + (*I).getAsString();
714 }
715 BlockCall += "))"; // close the argument list and paren expression.
716
Steve Naroff83ba14e2008-10-03 15:04:50 +0000717 // Invoke the closure. We need to cast it since the declaration type is
718 // bogus (it's a function pointer type)
719 BlockCall += "((struct __block_impl *)";
720 std::string closureExprBufStr;
721 llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
Chris Lattnere4f21422009-06-30 01:26:17 +0000722 Exp->getCallee()->printPretty(closureExprBuf, *Context, 0,
723 PrintingPolicy(LangOpts));
Steve Naroff83ba14e2008-10-03 15:04:50 +0000724 BlockCall += closureExprBuf.str();
725 BlockCall += ")->FuncPtr)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000726
727 // Add the arguments.
Steve Naroff83ba14e2008-10-03 15:04:50 +0000728 BlockCall += "((struct __block_impl *)";
Steve Naroffb65a4f12008-10-04 17:45:51 +0000729 BlockCall += closureExprBuf.str();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000730 for (CallExpr::arg_iterator I = Exp->arg_begin(),
731 E = Exp->arg_end(); I != E; ++I) {
732 std::string syncExprBufS;
733 llvm::raw_string_ostream Buf(syncExprBufS);
Chris Lattnere4f21422009-06-30 01:26:17 +0000734 (*I)->printPretty(Buf, *Context, 0, PrintingPolicy(LangOpts));
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000735 BlockCall += ", " + Buf.str();
736 }
737 return BlockCall;
738}
739
740void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
741 std::string BlockCall = SynthesizeBlockCall(Exp);
742
743 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
744 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
745
746 ReplaceText(Exp->getLocStart(), endBuf-startBuf,
747 BlockCall.c_str(), BlockCall.size());
748}
749
Steve Naroff5e52b172008-10-04 18:52:47 +0000750void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
751 // FIXME: Add more elaborate code generation required by the ABI.
752 InsertText(BDRE->getLocStart(), "*", 1);
753}
754
Steve Naroffca743602008-10-15 18:38:58 +0000755void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
756 SourceLocation LocStart = CE->getLocStart();
757 SourceLocation LocEnd = CE->getLocEnd();
758
Steve Naroff8f6ce572008-11-03 11:20:24 +0000759 if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
760 return;
761
Steve Naroffca743602008-10-15 18:38:58 +0000762 const char *startBuf = SM->getCharacterData(LocStart);
763 const char *endBuf = SM->getCharacterData(LocEnd);
764
765 // advance the location to startArgList.
766 const char *argPtr = startBuf;
767
768 while (*argPtr++ && (argPtr < endBuf)) {
769 switch (*argPtr) {
770 case '^':
771 // Replace the '^' with '*'.
772 LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
773 ReplaceText(LocStart, 1, "*", 1);
774 break;
775 }
776 }
777 return;
778}
779
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000780void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
781 SourceLocation DeclLoc = FD->getLocation();
Steve Naroffe0109a52008-10-10 15:33:34 +0000782 unsigned parenCount = 0;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000783
784 // We have 1 or more arguments that have closure pointers.
785 const char *startBuf = SM->getCharacterData(DeclLoc);
786 const char *startArgList = strchr(startBuf, '(');
787
788 assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
789
790 parenCount++;
791 // advance the location to startArgList.
Steve Naroffe0109a52008-10-10 15:33:34 +0000792 DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000793 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
794
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000795 const char *argPtr = startArgList;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000796
797 while (*argPtr++ && parenCount) {
798 switch (*argPtr) {
799 case '^':
Steve Naroffe0109a52008-10-10 15:33:34 +0000800 // Replace the '^' with '*'.
801 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
802 ReplaceText(DeclLoc, 1, "*", 1);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000803 break;
804 case '(':
805 parenCount++;
806 break;
807 case ')':
808 parenCount--;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000809 break;
810 }
811 }
812 return;
813}
814
Steve Naroffca743602008-10-15 18:38:58 +0000815bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
Douglas Gregor72564e72009-02-26 23:50:07 +0000816 const FunctionProtoType *FTP;
Ted Kremenek6217b802009-07-29 21:53:49 +0000817 const PointerType *PT = QT->getAs<PointerType>();
Steve Naroffca743602008-10-15 18:38:58 +0000818 if (PT) {
Douglas Gregor72564e72009-02-26 23:50:07 +0000819 FTP = PT->getPointeeType()->getAsFunctionProtoType();
Steve Naroffca743602008-10-15 18:38:58 +0000820 } else {
Ted Kremenek6217b802009-07-29 21:53:49 +0000821 const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
Steve Naroffca743602008-10-15 18:38:58 +0000822 assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
Douglas Gregor72564e72009-02-26 23:50:07 +0000823 FTP = BPT->getPointeeType()->getAsFunctionProtoType();
Steve Naroffca743602008-10-15 18:38:58 +0000824 }
Steve Naroffeab5f632008-09-23 19:24:41 +0000825 if (FTP) {
Douglas Gregor72564e72009-02-26 23:50:07 +0000826 for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
Steve Naroffeab5f632008-09-23 19:24:41 +0000827 E = FTP->arg_type_end(); I != E; ++I)
828 if (isBlockPointerType(*I))
829 return true;
830 }
831 return false;
832}
833
834void RewriteBlocks::GetExtentOfArgList(const char *Name,
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000835 const char *&LParen, const char *&RParen) {
836 const char *argPtr = strchr(Name, '(');
Steve Naroffeab5f632008-09-23 19:24:41 +0000837 assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
838
839 LParen = argPtr; // output the start.
840 argPtr++; // skip past the left paren.
841 unsigned parenCount = 1;
842
843 while (*argPtr && parenCount) {
844 switch (*argPtr) {
845 case '(': parenCount++; break;
846 case ')': parenCount--; break;
847 default: break;
848 }
849 if (parenCount) argPtr++;
850 }
851 assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
852 RParen = argPtr; // output the end
853}
854
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000855void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000856 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
857 RewriteBlockPointerFunctionArgs(FD);
858 return;
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000859 }
860 // Handle Variables and Typedefs.
861 SourceLocation DeclLoc = ND->getLocation();
862 QualType DeclT;
863 if (VarDecl *VD = dyn_cast<VarDecl>(ND))
864 DeclT = VD->getType();
865 else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
866 DeclT = TDD->getUnderlyingType();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000867 else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
868 DeclT = FD->getType();
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000869 else
870 assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled");
Steve Naroffeab5f632008-09-23 19:24:41 +0000871
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000872 const char *startBuf = SM->getCharacterData(DeclLoc);
873 const char *endBuf = startBuf;
874 // scan backward (from the decl location) for the end of the previous decl.
875 while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
876 startBuf--;
Steve Naroffca743602008-10-15 18:38:58 +0000877
878 // *startBuf != '^' if we are dealing with a pointer to function that
879 // may take block argument types (which will be handled below).
880 if (*startBuf == '^') {
881 // Replace the '^' with '*', computing a negative offset.
882 DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
883 ReplaceText(DeclLoc, 1, "*", 1);
884 }
885 if (PointerTypeTakesAnyBlockArguments(DeclT)) {
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000886 // Replace the '^' with '*' for arguments.
887 DeclLoc = ND->getLocation();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000888 startBuf = SM->getCharacterData(DeclLoc);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000889 const char *argListBegin, *argListEnd;
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000890 GetExtentOfArgList(startBuf, argListBegin, argListEnd);
891 while (argListBegin < argListEnd) {
892 if (*argListBegin == '^') {
893 SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
894 ReplaceText(CaretLoc, 1, "*", 1);
895 }
896 argListBegin++;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000897 }
Steve Naroffeab5f632008-09-23 19:24:41 +0000898 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000899 return;
900}
901
Steve Naroffd3f77902008-10-05 00:06:12 +0000902void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000903 // Add initializers for any closure decl refs.
Steve Naroff84a969f2008-10-08 17:31:13 +0000904 GetBlockDeclRefExprs(Exp->getBody());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000905 if (BlockDeclRefs.size()) {
906 // Unique all "by copy" declarations.
907 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
908 if (!BlockDeclRefs[i]->isByRef())
909 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
910 // Unique all "by ref" declarations.
911 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
912 if (BlockDeclRefs[i]->isByRef()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000913 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
914 }
Steve Naroffacba0f22008-10-04 23:47:37 +0000915 // Find any imported blocks...they will need special attention.
916 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
917 if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
918 GetBlockCallExprs(Blocks[i]);
919 ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
920 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000921 }
Steve Naroffd3f77902008-10-05 00:06:12 +0000922}
923
924std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
925 Blocks.push_back(Exp);
926
927 CollectBlockDeclRefInfo(Exp);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000928 std::string FuncName;
929
930 if (CurFunctionDef)
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000931 FuncName = std::string(CurFunctionDef->getNameAsString());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000932 else if (CurMethodDef) {
Chris Lattner077bf5e2008-11-24 03:33:13 +0000933 FuncName = CurMethodDef->getSelector().getAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000934 // Convert colons to underscores.
935 std::string::size_type loc = 0;
936 while ((loc = FuncName.find(":", loc)) != std::string::npos)
937 FuncName.replace(loc, 1, "_");
Steve Naroff39622b92008-10-03 15:38:09 +0000938 } else if (VD)
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000939 FuncName = std::string(VD->getNameAsString());
Steve Naroff39622b92008-10-03 15:38:09 +0000940
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000941 std::string BlockNumber = utostr(Blocks.size()-1);
942
Steve Naroff83ba14e2008-10-03 15:04:50 +0000943 std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000944 std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000945
Steve Naroff83ba14e2008-10-03 15:04:50 +0000946 std::string FunkTypeStr;
947
948 // Get a pointer to the function type so we can cast appropriately.
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000949 Context->getPointerType(QualType(Exp->getFunctionType(),0))
950 .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy);
Steve Naroff83ba14e2008-10-03 15:04:50 +0000951
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000952 // Rewrite the closure block with a compound literal. The first cast is
953 // to prevent warnings from the C compiler.
Steve Naroff83ba14e2008-10-03 15:04:50 +0000954 std::string Init = "(" + FunkTypeStr;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000955
Steve Naroff83ba14e2008-10-03 15:04:50 +0000956 Init += ")&" + Tag;
957
958 // Initialize the block function.
959 Init += "((void*)" + Func;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000960
Steve Naroffacba0f22008-10-04 23:47:37 +0000961 if (ImportedBlockDecls.size()) {
962 std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
963 Init += ",(void*)" + Buf;
964 Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
965 Init += ",(void*)" + Buf;
966 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000967 // Add initializers for any closure decl refs.
968 if (BlockDeclRefs.size()) {
969 // Output all "by copy" declarations.
970 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
971 E = BlockByCopyDecls.end(); I != E; ++I) {
972 Init += ",";
973 if (isObjCType((*I)->getType())) {
974 Init += "[[";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000975 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000976 Init += " retain] autorelease]";
Steve Naroff4e13b762008-10-03 20:28:15 +0000977 } else if (isBlockPointerType((*I)->getType())) {
978 Init += "(void *)";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000979 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000980 } else {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000981 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000982 }
983 }
984 // Output all "by ref" declarations.
985 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
986 E = BlockByRefDecls.end(); I != E; ++I) {
987 Init += ",&";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000988 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000989 }
990 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000991 Init += ")";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000992 BlockDeclRefs.clear();
993 BlockByRefDecls.clear();
994 BlockByCopyDecls.clear();
Steve Naroff4e13b762008-10-03 20:28:15 +0000995 ImportedBlockDecls.clear();
996
Steve Naroff70f95502008-10-04 17:06:23 +0000997 return Init;
998}
999
1000//===----------------------------------------------------------------------===//
1001// Function Body / Expression rewriting
1002//===----------------------------------------------------------------------===//
1003
1004Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
1005 // Start by rewriting all children.
1006 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
1007 CI != E; ++CI)
1008 if (*CI) {
1009 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
Eli Friedman687abff2009-06-08 04:24:21 +00001010 RewriteFunctionBody(CBE->getBody());
Steve Naroff70f95502008-10-04 17:06:23 +00001011
1012 // We've just rewritten the block body in place.
1013 // Now we snarf the rewritten text and stash it away for later use.
1014 std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
1015 RewrittenBlockExprs[CBE] = S;
1016 std::string Init = SynthesizeBlockInitExpr(CBE);
1017 // Do the rewrite, using S.size() which contains the rewritten size.
1018 ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
1019 } else {
Eli Friedman687abff2009-06-08 04:24:21 +00001020 RewriteFunctionBody(*CI);
Steve Naroff70f95502008-10-04 17:06:23 +00001021 }
1022 }
1023 // Handle specific things.
1024 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
1025 if (CE->getCallee()->getType()->isBlockPointerType())
1026 RewriteBlockCall(CE);
1027 }
Steve Naroffca743602008-10-15 18:38:58 +00001028 if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
1029 RewriteCastExpr(CE);
1030 }
Steve Naroff70f95502008-10-04 17:06:23 +00001031 if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001032 for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
1033 DI != DE; ++DI) {
1034
Douglas Gregor4afa39d2009-01-20 01:17:11 +00001035 Decl *SD = *DI;
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001036 if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
1037 if (isBlockPointerType(ND->getType()))
1038 RewriteBlockPointerDecl(ND);
Steve Naroffca743602008-10-15 18:38:58 +00001039 else if (ND->getType()->isFunctionPointerType())
1040 CheckFunctionPointerDecl(ND->getType(), ND);
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001041 }
1042 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
1043 if (isBlockPointerType(TD->getUnderlyingType()))
1044 RewriteBlockPointerDecl(TD);
Steve Naroffca743602008-10-15 18:38:58 +00001045 else if (TD->getUnderlyingType()->isFunctionPointerType())
1046 CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001047 }
Steve Naroff70f95502008-10-04 17:06:23 +00001048 }
1049 }
Steve Naroff5e52b172008-10-04 18:52:47 +00001050 // Handle specific things.
1051 if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
1052 if (BDRE->isByRef())
1053 RewriteBlockDeclRefExpr(BDRE);
1054 }
Steve Naroff70f95502008-10-04 17:06:23 +00001055 // Return this stmt unmodified.
1056 return S;
1057}
1058
Douglas Gregor72564e72009-02-26 23:50:07 +00001059void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
1060 if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
1061 for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
Steve Naroffca743602008-10-15 18:38:58 +00001062 E = fproto->arg_type_end(); I && (I != E); ++I)
1063 if (isBlockPointerType(*I)) {
1064 // All the args are checked/rewritten. Don't call twice!
1065 RewriteBlockPointerDecl(D);
1066 break;
1067 }
1068 }
1069}
1070
1071void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
Ted Kremenek6217b802009-07-29 21:53:49 +00001072 const PointerType *PT = funcType->getAs<PointerType>();
Steve Naroffca743602008-10-15 18:38:58 +00001073 if (PT && PointerTypeTakesAnyBlockArguments(funcType))
Douglas Gregor72564e72009-02-26 23:50:07 +00001074 RewriteFunctionProtoType(PT->getPointeeType(), ND);
Steve Naroffca743602008-10-15 18:38:58 +00001075}
1076
Steve Naroff70f95502008-10-04 17:06:23 +00001077/// HandleDeclInMainFile - This is called for each top-level decl defined in the
1078/// main file of the input.
1079void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
1080 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff70f95502008-10-04 17:06:23 +00001081 // Since function prototypes don't have ParmDecl's, we check the function
1082 // prototype. This enables us to rewrite function declarations and
1083 // definitions using the same code.
Douglas Gregor72564e72009-02-26 23:50:07 +00001084 RewriteFunctionProtoType(FD->getType(), FD);
Sebastian Redld3a413d2009-04-26 20:35:05 +00001085
1086 // FIXME: Handle CXXTryStmt
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001087 if (CompoundStmt *Body = FD->getCompoundBody()) {
Steve Naroff70f95502008-10-04 17:06:23 +00001088 CurFunctionDef = FD;
Ted Kremenekeaab2062009-03-12 18:33:24 +00001089 FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
Steve Naroff70f95502008-10-04 17:06:23 +00001090 // This synthesizes and inserts the block "impl" struct, invoke function,
1091 // and any copy/dispose helper functions.
1092 InsertBlockLiteralsWithinFunction(FD);
1093 CurFunctionDef = 0;
1094 }
1095 return;
1096 }
1097 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
1098 RewriteMethodDecl(MD);
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001099 if (Stmt *Body = MD->getBody()) {
Steve Naroff70f95502008-10-04 17:06:23 +00001100 CurMethodDef = MD;
1101 RewriteFunctionBody(Body);
1102 InsertBlockLiteralsWithinMethod(MD);
1103 CurMethodDef = 0;
1104 }
1105 }
1106 if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
1107 if (isBlockPointerType(VD->getType())) {
1108 RewriteBlockPointerDecl(VD);
1109 if (VD->getInit()) {
1110 if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001111 RewriteFunctionBody(CBE->getBody());
Steve Naroff70f95502008-10-04 17:06:23 +00001112
1113 // We've just rewritten the block body in place.
1114 // Now we snarf the rewritten text and stash it away for later use.
1115 std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
1116 RewrittenBlockExprs[CBE] = S;
1117 std::string Init = SynthesizeBlockInitExpr(CBE, VD);
1118 // Do the rewrite, using S.size() which contains the rewritten size.
1119 ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
Douglas Gregor2e1cd422008-11-17 14:58:09 +00001120 SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
Chris Lattner8ec03f52008-11-24 03:54:41 +00001121 VD->getNameAsCString());
Steve Naroffca743602008-10-15 18:38:58 +00001122 } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
1123 RewriteCastExpr(CE);
1124 }
1125 }
1126 } else if (VD->getType()->isFunctionPointerType()) {
1127 CheckFunctionPointerDecl(VD->getType(), VD);
1128 if (VD->getInit()) {
1129 if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
1130 RewriteCastExpr(CE);
Steve Naroff70f95502008-10-04 17:06:23 +00001131 }
1132 }
1133 }
1134 return;
1135 }
1136 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
1137 if (isBlockPointerType(TD->getUnderlyingType()))
1138 RewriteBlockPointerDecl(TD);
Steve Naroffca743602008-10-15 18:38:58 +00001139 else if (TD->getUnderlyingType()->isFunctionPointerType())
1140 CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
Steve Naroff70f95502008-10-04 17:06:23 +00001141 return;
1142 }
1143 if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
1144 if (RD->isDefinition()) {
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +00001145 for (RecordDecl::field_iterator i = RD->field_begin(),
1146 e = RD->field_end(); i != e; ++i) {
Steve Naroff70f95502008-10-04 17:06:23 +00001147 FieldDecl *FD = *i;
1148 if (isBlockPointerType(FD->getType()))
1149 RewriteBlockPointerDecl(FD);
1150 }
1151 }
1152 return;
1153 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001154}