blob: 753f4ffa2ef7c03cb2638e90339ec93c3d36575a [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
14#include "ASTConsumers.h"
15#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;
37 unsigned NoNestedBlockCalls;
38
39 ASTContext *Context;
40 SourceManager *SM;
41 unsigned MainFileID;
42 const char *MainFileStart, *MainFileEnd;
43
44 // Block expressions.
45 llvm::SmallVector<BlockExpr *, 32> Blocks;
46 llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
47 llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
48
49 // Block related declarations.
50 llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
51 llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
52
53 // The function/method we are rewriting.
54 FunctionDecl *CurFunctionDef;
55 ObjCMethodDecl *CurMethodDef;
56
57 bool IsHeader;
58public:
59 RewriteBlocks(bool isHeader, Diagnostic &D, const LangOptions &LOpts) :
60 Diags(D), LangOpts(LOpts) {
61 IsHeader = isHeader;
62 CurFunctionDef = 0;
63 CurMethodDef = 0;
64 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
65 "rewriting failed");
66 NoNestedBlockCalls = Diags.getCustomDiagID(Diagnostic::Warning,
67 "Rewrite support for closure calls nested within closure blocks is incomplete");
68 }
69 ~RewriteBlocks() {
70 // Get the buffer corresponding to MainFileID.
71 // If we haven't changed it, then we are done.
72 if (const RewriteBuffer *RewriteBuf =
73 Rewrite.getRewriteBufferFor(MainFileID)) {
74 std::string S(RewriteBuf->begin(), RewriteBuf->end());
75 printf("%s\n", S.c_str());
76 } else {
77 printf("No changes\n");
78 }
79 }
80
81 void Initialize(ASTContext &context);
82
83 void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
84 void ReplaceText(SourceLocation Start, unsigned OrigLength,
85 const char *NewStr, unsigned NewLength);
86
87 // Top Level Driver code.
88 virtual void HandleTopLevelDecl(Decl *D);
89 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 Naroff9c3c9022008-09-17 18:37:59 +000097 void RewriteBlockExpr(BlockExpr *Exp);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000098
99 void RewriteBlockCall(CallExpr *Exp);
100 void RewriteBlockPointerDecl(NamedDecl *VD);
101 void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
102
103 std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
104 const char *funcName, std::string Tag);
105 std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag);
106 std::string SynthesizeBlockCall(CallExpr *Exp);
107 void SynthesizeBlockLiterals(SourceLocation FunLocStart,
108 const char *FunName);
109
110 void GetBlockDeclRefExprs(Stmt *S);
111 void GetBlockCallExprs(Stmt *S);
112
113 // We avoid calling Type::isBlockPointerType(), since it operates on the
114 // canonical type. We only care if the top-level type is a closure pointer.
115 bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
116
117 // FIXME: This predicate seems like it would be useful to add to ASTContext.
118 bool isObjCType(QualType T) {
119 if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
120 return false;
121
122 QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
123
124 if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
125 OCT == Context->getCanonicalType(Context->getObjCClassType()))
126 return true;
127
128 if (const PointerType *PT = OCT->getAsPointerType()) {
129 if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
130 isa<ObjCQualifiedIdType>(PT->getPointeeType()))
131 return true;
132 }
133 return false;
134 }
135 // ObjC rewrite methods.
136 void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
137 void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
138 void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
139 void RewriteMethodDecl(ObjCMethodDecl *MDecl);
140};
141
142}
143
144static bool IsHeaderFile(const std::string &Filename) {
145 std::string::size_type DotPos = Filename.rfind('.');
146
147 if (DotPos == std::string::npos) {
148 // no file extension
149 return false;
150 }
151
152 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
153 // C header: .h
154 // C++ header: .hh or .H;
155 return Ext == "h" || Ext == "hh" || Ext == "H";
156}
157
158ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
159 Diagnostic &Diags,
160 const LangOptions &LangOpts) {
161 return new RewriteBlocks(IsHeaderFile(InFile), Diags, LangOpts);
162}
163
164void RewriteBlocks::Initialize(ASTContext &context) {
165 Context = &context;
166 SM = &Context->getSourceManager();
167
168 // Get the ID and start/end of the main file.
169 MainFileID = SM->getMainFileID();
170 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
171 MainFileStart = MainBuf->getBufferStart();
172 MainFileEnd = MainBuf->getBufferEnd();
173
174 Rewrite.setSourceMgr(Context->getSourceManager());
175
176 const char *s = "#pragma once\n"
177 "#ifndef CLOSURE_IMPL\n"
178 "struct __closure_impl {\n"
179 " long Reserved;\n"
180 " int Flags;\n"
181 " int Size;\n"
182 " void *Invoke;\n"
183 "};\n"
184 "enum {\n"
185 " HAS_NONPOD = (1<<25),\n"
186 " HAS_BYREF = (1<<26)\n"
187 "};\n"
188 "#define CLOSURE_IMPL\n"
189 "#endif\n";
190 if (IsHeader) {
191 // insert the whole string when rewriting a header file
192 InsertText(SourceLocation::getFileLoc(MainFileID, 0), s, strlen(s));
193 }
194 else {
195 // Not rewriting header, exclude the #pragma once pragma
196 const char *p = s + strlen("#pragma once\n");
197 InsertText(SourceLocation::getFileLoc(MainFileID, 0), p, strlen(p));
198 }
199}
200
201void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
202 unsigned StrLen)
203{
204 if (!Rewrite.InsertText(Loc, StrData, StrLen))
205 return;
206 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
207}
208
209void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
210 const char *NewStr, unsigned NewLength) {
211 if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength))
212 return;
213 Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
214}
215
216void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
217 bool haveBlockPtrs = false;
218 for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
219 E = Method->param_end(); I != E; ++I)
220 if (isBlockPointerType((*I)->getType()))
221 haveBlockPtrs = true;
222
223 if (!haveBlockPtrs)
224 return;
225
226 // Do a fuzzy rewrite.
227 // We have 1 or more arguments that have closure pointers.
228 SourceLocation Loc = Method->getLocStart();
229 SourceLocation LocEnd = Method->getLocEnd();
230 const char *startBuf = SM->getCharacterData(Loc);
231 const char *endBuf = SM->getCharacterData(LocEnd);
232
233 const char *methodPtr = startBuf;
234 std::string Tag = "struct __closure_impl *";
235
236 while (*methodPtr++ && (methodPtr != endBuf)) {
237 switch (*methodPtr) {
238 case ':':
239 methodPtr++;
240 if (*methodPtr == '(') {
241 const char *scanType = ++methodPtr;
242 bool foundBlockPointer = false;
243 unsigned parenCount = 1;
244
245 while (parenCount) {
246 switch (*scanType) {
247 case '(':
248 parenCount++;
249 break;
250 case ')':
251 parenCount--;
252 break;
253 case '^':
254 foundBlockPointer = true;
255 break;
256 }
257 scanType++;
258 }
259 if (foundBlockPointer) {
260 // advance the location to startArgList.
261 Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
262 assert((Loc.isValid()) && "Invalid Loc");
263 ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
264
265 // Advance startBuf. Since the underlying buffer has changed,
266 // it's very important to advance startBuf (so we can correctly
267 // compute a relative Loc the next time around).
268 startBuf = methodPtr;
269 }
270 // Advance the method ptr to the end of the type.
271 methodPtr = scanType;
272 }
273 break;
274 }
275 }
276 return;
277}
278
279void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
280 for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
281 E = ClassDecl->instmeth_end(); I != E; ++I)
282 RewriteMethodDecl(*I);
283 for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
284 E = ClassDecl->classmeth_end(); I != E; ++I)
285 RewriteMethodDecl(*I);
286}
287
288void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
289 for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
290 E = CatDecl->instmeth_end(); I != E; ++I)
291 RewriteMethodDecl(*I);
292 for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
293 E = CatDecl->classmeth_end(); I != E; ++I)
294 RewriteMethodDecl(*I);
295}
296
297void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
298 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
299 E = PDecl->instmeth_end(); I != E; ++I)
300 RewriteMethodDecl(*I);
301 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
302 E = PDecl->classmeth_end(); I != E; ++I)
303 RewriteMethodDecl(*I);
304}
305
306//===----------------------------------------------------------------------===//
307// Top Level Driver Code
308//===----------------------------------------------------------------------===//
309
310void RewriteBlocks::HandleTopLevelDecl(Decl *D) {
311 // Two cases: either the decl could be in the main file, or it could be in a
312 // #included file. If the former, rewrite it now. If the later, check to see
313 // if we rewrote the #include/#import.
314 SourceLocation Loc = D->getLocation();
315 Loc = SM->getLogicalLoc(Loc);
316
317 // If this is for a builtin, ignore it.
318 if (Loc.isInvalid()) return;
319
320 if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
321 RewriteInterfaceDecl(MD);
322 else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
323 RewriteCategoryDecl(CD);
324 else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
325 RewriteProtocolDecl(PD);
326
327 // If we have a decl in the main file, see if we should rewrite it.
328 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
329 HandleDeclInMainFile(D);
330 return;
331}
332
333std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
334 const char *funcName,
335 std::string Tag) {
336 const FunctionType *AFT = CE->getFunctionType();
337 QualType RT = AFT->getResultType();
338 std::string S = "static " + RT.getAsString() + " __" +
339 funcName + "_" + "closure_" + utostr(i);
340
341 if (isa<FunctionTypeNoProto>(AFT)) {
342 S += "()";
343 } else if (CE->arg_empty()) {
344 S += "(" + Tag + " *__cself)";
345 } else {
346 const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
347 assert(FT && "SynthesizeBlockFunc: No function proto");
348 S += '(';
349 // first add the implicit argument.
350 S += Tag + " *__cself, ";
351 std::string ParamStr;
Steve Naroff9c3c9022008-09-17 18:37:59 +0000352 for (BlockExpr::arg_iterator AI = CE->arg_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000353 E = CE->arg_end(); AI != E; ++AI) {
354 if (AI != CE->arg_begin()) S += ", ";
355 ParamStr = (*AI)->getName();
356 (*AI)->getType().getAsStringInternal(ParamStr);
357 S += ParamStr;
358 }
359 if (FT->isVariadic()) {
360 if (!CE->arg_empty()) S += ", ";
361 S += "...";
362 }
363 S += ')';
364 }
365 S += " {\n";
366
367 bool haveByRefDecls = false;
368
369 // Create local declarations to avoid rewriting all closure decl ref exprs.
370 // First, emit a declaration for all "by ref" decls.
371 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
372 E = BlockByRefDecls.end(); I != E; ++I) {
373 // Note: It is not possible to have "by ref" closure pointer decls.
374 haveByRefDecls = true;
375 S += " ";
376 std::string Name = (*I)->getName();
377 Context->getPointerType((*I)->getType()).getAsStringInternal(Name);
378 S += Name + " = __cself->" + (*I)->getName() + "; // bound by ref\n";
379 }
380 // Next, emit a declaration for all "by copy" declarations.
381 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
382 E = BlockByCopyDecls.end(); I != E; ++I) {
383 S += " ";
384 std::string Name = (*I)->getName();
385 // Handle nested closure invocation. For example:
386 //
387 // void (^myImportedClosure)(void);
388 // myImportedClosure = ^(void) { setGlobalInt(x + y); };
389 //
390 // void (^anotherClosure)(void);
391 // anotherClosure = ^(void) {
392 // myImportedClosure(); // import and invoke the closure
393 // };
394 //
395 if (isBlockPointerType((*I)->getType()))
396 S += "struct __closure_impl *";
397 else
398 (*I)->getType().getAsStringInternal(Name);
399 S += Name + " = __cself->" + (*I)->getName() + "; // bound by copy\n";
400 }
Steve Naroff9c3c9022008-09-17 18:37:59 +0000401 if (BlockExpr *CBE = dyn_cast<BlockExpr>(CE)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000402 std::string BodyBuf;
403
404 SourceLocation BodyLocStart = CBE->getBody()->getLocStart();
405 SourceLocation BodyLocEnd = CBE->getBody()->getLocEnd();
406 const char *BodyStartBuf = SM->getCharacterData(BodyLocStart);
407 const char *BodyEndBuf = SM->getCharacterData(BodyLocEnd);
408
409 BodyBuf.append(BodyStartBuf, BodyEndBuf-BodyStartBuf+1);
410
411 if (BlockDeclRefs.size()) {
412 unsigned int nCharsAdded = 0;
413 for (unsigned i = 0; i < BlockDeclRefs.size(); i++) {
414 if (BlockDeclRefs[i]->isByRef()) {
415 // Add a level of indirection! The code below assumes
416 // the closure decl refs/locations are in strictly ascending
417 // order. The traversal performed by GetBlockDeclRefExprs()
418 // currently does this. FIXME: Wrap the *x with parens,
419 // just in case x is a more complex expression, like x->member,
420 // which needs to be rewritten to (*x)->member.
421 SourceLocation StarLoc = BlockDeclRefs[i]->getLocStart();
422 const char *StarBuf = SM->getCharacterData(StarLoc);
423 BodyBuf.insert(StarBuf-BodyStartBuf+nCharsAdded, 1, '*');
424 // Get a fresh buffer, the insert might have caused it to grow.
425 BodyStartBuf = SM->getCharacterData(BodyLocStart);
426 nCharsAdded++;
427 } else if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
428 Diags.Report(NoNestedBlockCalls);
429
430 GetBlockCallExprs(CE);
431
432 // Rewrite the closure in place.
433 // The character based equivalent of RewriteBlockCall().
434 // Need to get the CallExpr associated with this BlockDeclRef.
435 std::string BlockCall = SynthesizeBlockCall(BlockCallExprs[BlockDeclRefs[i]]);
436
437 SourceLocation CallLocStart = BlockCallExprs[BlockDeclRefs[i]]->getLocStart();
438 SourceLocation CallLocEnd = BlockCallExprs[BlockDeclRefs[i]]->getLocEnd();
439 const char *CallStart = SM->getCharacterData(CallLocStart);
440 const char *CallEnd = SM->getCharacterData(CallLocEnd);
441 unsigned CallBytes = CallEnd-CallStart;
442 BodyBuf.replace(CallStart-BodyStartBuf, CallBytes, BlockCall.c_str());
443 nCharsAdded += CallBytes;
444 }
445 }
446 }
447 if (haveByRefDecls) {
448 // Remove |...|.
449 const char *firstBarPtr = strchr(BodyStartBuf, '|');
450 const char *secondBarPtr = strchr(firstBarPtr+1, '|');
451 BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, "");
452 }
453 S += " ";
454 S += BodyBuf;
455 }
456 S += "\n}\n";
457 return S;
458}
459
460std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE,
461 std::string Tag) {
462 std::string S = Tag + " {\n struct __closure_impl impl;\n";
463
464 GetBlockDeclRefExprs(CE);
465 if (BlockDeclRefs.size()) {
466 // Unique all "by copy" declarations.
467 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
468 if (!BlockDeclRefs[i]->isByRef())
469 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
470 // Unique all "by ref" declarations.
471 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
472 if (BlockDeclRefs[i]->isByRef())
473 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
474
475 // Output all "by copy" declarations.
476 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
477 E = BlockByCopyDecls.end(); I != E; ++I) {
478 S += " ";
479 std::string Name = (*I)->getName();
480 // Handle nested closure invocation. For example:
481 //
482 // void (^myImportedBlock)(void);
483 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
484 //
485 // void (^anotherBlock)(void);
486 // anotherBlock = ^(void) {
487 // myImportedBlock(); // import and invoke the closure
488 // };
489 //
490 if (isBlockPointerType((*I)->getType()))
491 S += "struct __closure_impl *";
492 else
493 (*I)->getType().getAsStringInternal(Name);
494 S += Name + ";\n";
495 }
496 // Output all "by ref" declarations.
497 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
498 E = BlockByRefDecls.end(); I != E; ++I) {
499 S += " ";
500 std::string Name = (*I)->getName();
501 if (isBlockPointerType((*I)->getType()))
502 S += "struct __closure_impl *";
503 else
504 Context->getPointerType((*I)->getType()).getAsStringInternal(Name);
505 S += Name + "; // by ref\n";
506 }
507 }
508 S += "};\n";
509 return S;
510}
511
512void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
513 const char *FunName) {
514 // Insert closures that were part of the function.
515 for (unsigned i = 0; i < Blocks.size(); i++) {
516
517 std::string Tag = "struct __" + std::string(FunName) +
518 "_closure_impl_" + utostr(i);
519
520 std::string CI = SynthesizeBlockImpl(Blocks[i], Tag);
521
522 InsertText(FunLocStart, CI.c_str(), CI.size());
523
524 std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
525
526 InsertText(FunLocStart, CF.c_str(), CF.size());
527
528 BlockDeclRefs.clear();
529 BlockByRefDecls.clear();
530 BlockByCopyDecls.clear();
531 BlockCallExprs.clear();
532 }
533 Blocks.clear();
534}
535
536void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
537 SourceLocation FunLocStart = FD->getLocation();
538 const char *FuncName = FD->getName();
539
540 SynthesizeBlockLiterals(FunLocStart, FuncName);
541}
542
543void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
544 SourceLocation FunLocStart = MD->getLocStart();
545 std::string FuncName = std::string(MD->getSelector().getName());
546 // Convert colons to underscores.
547 std::string::size_type loc = 0;
548 while ((loc = FuncName.find(":", loc)) != std::string::npos)
549 FuncName.replace(loc, 1, "_");
550
551 SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
552}
553
554/// HandleDeclInMainFile - This is called for each top-level decl defined in the
555/// main file of the input.
556void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
557 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
558
559 // Since function prototypes don't have ParmDecl's, we check the function
560 // prototype. This enables us to rewrite function declarations and
561 // definitions using the same code.
562 QualType funcType = FD->getType();
563
564 if (FunctionTypeProto *fproto = dyn_cast<FunctionTypeProto>(funcType)) {
565 for (FunctionTypeProto::arg_type_iterator I = fproto->arg_type_begin(),
566 E = fproto->arg_type_end(); I && (I != E); ++I)
567 if (isBlockPointerType(*I)) {
568 // All the args are checked/rewritten. Don't call twice!
569 RewriteBlockPointerDecl(FD);
570 break;
571 }
572 }
573 if (Stmt *Body = FD->getBody()) {
574 CurFunctionDef = FD;
575 FD->setBody(RewriteFunctionBody(Body));
576 InsertBlockLiteralsWithinFunction(FD);
577 CurFunctionDef = 0;
578 }
579 return;
580 }
581 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
582 RewriteMethodDecl(MD);
583 if (Stmt *Body = MD->getBody()) {
584 CurMethodDef = MD;
585 RewriteFunctionBody(Body);
586 InsertBlockLiteralsWithinMethod(MD);
587 CurMethodDef = 0;
588 }
589 }
590 if (ValueDecl *ND = dyn_cast<ValueDecl>(D)) {
591 if (isBlockPointerType(ND->getType()))
592 RewriteBlockPointerDecl(ND);
593 return;
594 }
595 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
596 if (isBlockPointerType(TD->getUnderlyingType()))
597 RewriteBlockPointerDecl(TD);
598 return;
599 }
600}
601
602void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
603 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
604 CI != E; ++CI)
605 if (*CI)
606 GetBlockDeclRefExprs(*CI);
607
608 // Handle specific things.
609 if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
610 // FIXME: Handle enums.
611 if (!isa<FunctionDecl>(CDRE->getDecl()))
612 BlockDeclRefs.push_back(CDRE);
613 return;
614}
615
616void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
617 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
618 CI != E; ++CI)
619 if (*CI)
620 GetBlockCallExprs(*CI);
621
622 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
623 if (CE->getCallee()->getType()->isBlockPointerType())
624 BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
625 }
626 return;
627}
628
629//===----------------------------------------------------------------------===//
630// Function Body / Expression rewriting
631//===----------------------------------------------------------------------===//
632
633Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
634 // Start by rewriting all children.
635 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
636 CI != E; ++CI)
637 if (*CI) {
Steve Naroff9c3c9022008-09-17 18:37:59 +0000638 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000639 // We intentionally avoid rewritting the contents of a closure block
640 // expr. InsertBlockLiteralsWithinFunction() will rewrite the body.
Steve Naroff9c3c9022008-09-17 18:37:59 +0000641 RewriteBlockExpr(CBE);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000642 } else {
643 Stmt *newStmt = RewriteFunctionBody(*CI);
644 if (newStmt)
645 *CI = newStmt;
646 }
647 }
648 // Handle specific things.
649 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
650 if (CE->getCallee()->getType()->isBlockPointerType())
651 RewriteBlockCall(CE);
652 }
653 if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
654 ScopedDecl *SD = DS->getDecl();
655 if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
656 if (isBlockPointerType(ND->getType()))
657 RewriteBlockPointerDecl(ND);
658 }
659 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
660 if (isBlockPointerType(TD->getUnderlyingType()))
661 RewriteBlockPointerDecl(TD);
662 }
663 }
664 // Return this stmt unmodified.
665 return S;
666}
667
668std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
669 // Navigate to relevant type information.
670 const char *closureName;
671 const BlockPointerType *CPT;
672
673 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
674 closureName = DRE->getDecl()->getName();
675 CPT = DRE->getType()->getAsBlockPointerType();
676 } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
677 closureName = CDRE->getDecl()->getName();
678 CPT = CDRE->getType()->getAsBlockPointerType();
679 } else {
680 assert(1 && "RewriteBlockClass: Bad type");
681 }
682 assert(CPT && "RewriteBlockClass: Bad type");
683 const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
684 assert(FT && "RewriteBlockClass: Bad type");
685 const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FT);
686 // FTP will be null for closures that don't take arguments.
687
688 // Build a closure call - start with a paren expr to enforce precedence.
689 std::string BlockCall = "(";
690
691 // Synthesize the cast.
692 BlockCall += "(" + Exp->getType().getAsString() + "(*)";
693 BlockCall += "(struct __closure_impl *";
694 if (FTP) {
695 for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
696 E = FTP->arg_type_end(); I && (I != E); ++I)
697 BlockCall += ", " + (*I).getAsString();
698 }
699 BlockCall += "))"; // close the argument list and paren expression.
700
701 // Invoke the closure.
702 BlockCall += closureName;
703 BlockCall += "->Invoke)";
704
705 // Add the arguments.
706 BlockCall += "(";
707 BlockCall += closureName;
708 for (CallExpr::arg_iterator I = Exp->arg_begin(),
709 E = Exp->arg_end(); I != E; ++I) {
710 std::string syncExprBufS;
711 llvm::raw_string_ostream Buf(syncExprBufS);
712 (*I)->printPretty(Buf);
713 BlockCall += ", " + Buf.str();
714 }
715 return BlockCall;
716}
717
718void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
719 std::string BlockCall = SynthesizeBlockCall(Exp);
720
721 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
722 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
723
724 ReplaceText(Exp->getLocStart(), endBuf-startBuf,
725 BlockCall.c_str(), BlockCall.size());
726}
727
728void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
729 SourceLocation DeclLoc = FD->getLocation();
730 unsigned parenCount = 0, nArgs = 0;
731
732 // We have 1 or more arguments that have closure pointers.
733 const char *startBuf = SM->getCharacterData(DeclLoc);
734 const char *startArgList = strchr(startBuf, '(');
735
736 assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
737
738 parenCount++;
739 // advance the location to startArgList.
740 DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf+1);
741 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
742
743 const char *topLevelCommaCursor = 0;
744 const char *argPtr = startArgList;
745 bool scannedBlockDecl = false;
746 std::string Tag = "struct __closure_impl *";
747
748 while (*argPtr++ && parenCount) {
749 switch (*argPtr) {
750 case '^':
751 scannedBlockDecl = true;
752 break;
753 case '(':
754 parenCount++;
755 break;
756 case ')':
757 parenCount--;
758 if (parenCount == 0) {
759 if (scannedBlockDecl) {
760 // If we are rewriting a definition, don't forget the arg name.
761 if (FD->getBody())
762 Tag += FD->getParamDecl(nArgs)->getName();
763 // The last argument is a closure pointer decl, rewrite it!
764 if (topLevelCommaCursor)
765 ReplaceText(DeclLoc, argPtr-topLevelCommaCursor-2, Tag.c_str(), Tag.size());
766 else
767 ReplaceText(DeclLoc, argPtr-startArgList-1, Tag.c_str(), Tag.size());
768 scannedBlockDecl = false; // reset.
769 }
770 nArgs++;
771 }
772 break;
773 case ',':
774 if (parenCount == 1) {
775 // Make sure the function takes more than one argument.
776 assert((FD->getNumParams() > 1) && "Rewriter fuzzy parser confused");
777 if (scannedBlockDecl) {
778 // If we are rewriting a definition, don't forget the arg name.
779 if (FD->getBody())
780 Tag += FD->getParamDecl(nArgs)->getName();
781 // The current argument is a closure pointer decl, rewrite it!
782 if (topLevelCommaCursor)
783 ReplaceText(DeclLoc, argPtr-topLevelCommaCursor-1, Tag.c_str(), Tag.size());
784 else
785 ReplaceText(DeclLoc, argPtr-startArgList-1, Tag.c_str(), Tag.size());
786 scannedBlockDecl = false;
787 }
788 nArgs++;
789 // advance the location to topLevelCommaCursor.
790 if (topLevelCommaCursor)
791 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-topLevelCommaCursor);
792 else
793 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList+1);
794 topLevelCommaCursor = argPtr;
795 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
796 }
797 break;
798 }
799 }
800 return;
801}
802
803void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
804 SourceLocation DeclLoc = ND->getLocation();
805 const char *startBuf, *endBuf;
806
807 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
808 RewriteBlockPointerFunctionArgs(FD);
809 return;
810 } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
811 DeclLoc = VD->getLocation();
812 startBuf = SM->getCharacterData(DeclLoc);
813 endBuf = startBuf;
814 } else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) {
815 DeclLoc = TDD->getLocation();
816 startBuf = SM->getCharacterData(DeclLoc);
817 if (!strncmp("typedef ", startBuf, 8)) {
818 startBuf += 8; // skip the typedef...
819 DeclLoc = DeclLoc.getFileLocWithOffset(8);
820 }
821 endBuf = startBuf;
822 }
823 // FIXME: need to skip past the argument list...then check for ','.
824 while (*endBuf && *endBuf != '=' && *endBuf != ';')
825 endBuf++;
826
827 SourceLocation DeclEndLoc = DeclLoc.getFileLocWithOffset(endBuf-startBuf);
828
829 std::string Tag = "struct __closure_impl *" + std::string(ND->getName());
830 ReplaceText(DeclLoc, endBuf-startBuf, Tag.c_str(), Tag.size());
831 return;
832}
833
Steve Naroff9c3c9022008-09-17 18:37:59 +0000834void RewriteBlocks::RewriteBlockExpr(BlockExpr *Exp) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000835 Blocks.push_back(Exp);
836 bool haveByRefDecls = false;
837
838 // Add initializers for any closure decl refs.
839 GetBlockDeclRefExprs(Exp);
840 if (BlockDeclRefs.size()) {
841 // Unique all "by copy" declarations.
842 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
843 if (!BlockDeclRefs[i]->isByRef())
844 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
845 // Unique all "by ref" declarations.
846 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
847 if (BlockDeclRefs[i]->isByRef()) {
848 haveByRefDecls = true;
849 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
850 }
851 }
852 std::string FuncName;
853
854 if (CurFunctionDef)
855 FuncName = std::string(CurFunctionDef->getName());
856 else if (CurMethodDef) {
857 FuncName = std::string(CurMethodDef->getSelector().getName());
858 // Convert colons to underscores.
859 std::string::size_type loc = 0;
860 while ((loc = FuncName.find(":", loc)) != std::string::npos)
861 FuncName.replace(loc, 1, "_");
862 }
863 std::string BlockNumber = utostr(Blocks.size()-1);
864
865 std::string Tag = "struct __" + FuncName + "_closure_impl_" + BlockNumber;
866 std::string Func = "__" + FuncName + "_" + "closure_" + BlockNumber;
867
868 // Rewrite the closure block with a compound literal. The first cast is
869 // to prevent warnings from the C compiler.
870 std::string Init = "(struct __closure_impl *)&(" + Tag + "){{0,";
871
872 // Initialize the Flags, Size, and Invoke fields.
873 Init += (haveByRefDecls ? "HAS_BYREF," : "0,");
874 Init += "sizeof(" + Tag + ")," + Func + "}";
875
876 // Add initializers for any closure decl refs.
877 if (BlockDeclRefs.size()) {
878 // Output all "by copy" declarations.
879 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
880 E = BlockByCopyDecls.end(); I != E; ++I) {
881 Init += ",";
882 if (isObjCType((*I)->getType())) {
883 Init += "[[";
884 Init += (*I)->getName();
885 Init += " retain] autorelease]";
886 } else {
887 Init += (*I)->getName();
888 }
889 }
890 // Output all "by ref" declarations.
891 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
892 E = BlockByRefDecls.end(); I != E; ++I) {
893 Init += ",&";
894 Init += (*I)->getName();
895 }
896 }
897 Init += "}";
898 BlockDeclRefs.clear();
899 BlockByRefDecls.clear();
900 BlockByCopyDecls.clear();
901
902 // Do the rewrite.
903 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
904 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
905 ReplaceText(Exp->getLocStart(), endBuf-startBuf+1, Init.c_str(), Init.size());
906 return;
907}