modern objective-c rewriter: further improvement in

writing @synchronized statement; do not call locking
expression more than once and support early exits in
@synchronized's statement block (such as return).

llvm-svn: 152993
This commit is contained in:
Fariborz Jahanian 2012-03-17 17:46:02 +00:00
parent 97f889f43b
commit e8810768a9
2 changed files with 29 additions and 29 deletions

View File

@ -1703,18 +1703,30 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
assert((*startBuf == '@') && "bogus @synchronized location"); assert((*startBuf == '@') && "bogus @synchronized location");
std::string buf; std::string buf;
buf = "{ id volatile _rethrow = 0; objc_sync_enter((id)"; buf = "{ id _rethrow = 0; id _sync_obj = ";
const char *lparenBuf = startBuf; const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++; while (*lparenBuf != '(') lparenBuf++;
ReplaceText(startLoc, lparenBuf-startBuf+1, buf); ReplaceText(startLoc, lparenBuf-startBuf+1, buf);
SourceLocation endLoc = S->getSynchBody()->getLocStart();
const char *endBuf = SM->getCharacterData(endLoc); buf = "; objc_sync_enter(_sync_obj);\n";
while (*endBuf != ')') endBuf--; buf += "try {\n\tstruct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}";
SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf); buf += "\n\t~_SYNC_EXIT() {objc_sync_exit(sync_exit);}";
buf = ");\n"; buf += "\n\tid sync_exit;";
buf += "try "; buf += "\n\t} _sync_exit(_sync_obj);\n";
ReplaceText(rparenLoc, 1, buf);
// We can't use S->getSynchExpr()->getLocEnd() to find the end location, since
// the sync expression is typically a message expression that's already
// been rewritten! (which implies the SourceLocation's are invalid).
SourceLocation RParenExprLoc = S->getSynchBody()->getLocStart();
const char *RParenExprLocBuf = SM->getCharacterData(RParenExprLoc);
while (*RParenExprLocBuf != ')') RParenExprLocBuf--;
RParenExprLoc = startLoc.getLocWithOffset(RParenExprLocBuf-startBuf);
SourceLocation LBranceLoc = S->getSynchBody()->getLocStart();
const char *LBraceLocBuf = SM->getCharacterData(LBranceLoc);
assert (*LBraceLocBuf == '{');
ReplaceText(RParenExprLoc, (LBraceLocBuf - SM->getCharacterData(RParenExprLoc) + 1), buf);
SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd(); SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd();
assert((*SM->getCharacterData(startRBraceLoc) == '}') && assert((*SM->getCharacterData(startRBraceLoc) == '}') &&
@ -1722,27 +1734,6 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
buf = "} catch (id e) {_rethrow = e;}\n"; buf = "} catch (id e) {_rethrow = e;}\n";
Write_RethrowObject(buf); Write_RethrowObject(buf);
// produce objc_sync_exit(expr);
std::string syncBuf;
syncBuf += "\n\tobjc_sync_exit(";
Expr *syncExpr = S->getSynchExpr();
CastKind CK = syncExpr->getType()->isObjCObjectPointerType()
? CK_BitCast :
syncExpr->getType()->isBlockPointerType()
? CK_BlockPointerToObjCPointerCast
: CK_CPointerToObjCPointerCast;
syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CK, syncExpr);
std::string syncExprBufS;
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
syncExpr->printPretty(syncExprBuf, *Context, 0,
PrintingPolicy(LangOpts));
syncBuf += syncExprBuf.str();
syncBuf += ");";
buf += syncBuf;
buf += "}\n"; buf += "}\n";
buf += "}\n"; buf += "}\n";
@ -1908,6 +1899,8 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
SourceLocation endFinalBodyLoc = body->getLocEnd(); SourceLocation endFinalBodyLoc = body->getLocEnd();
ReplaceText(endFinalBodyLoc, 1, "}\n}"); ReplaceText(endFinalBodyLoc, 1, "}\n}");
// Now check for any return/continue/go statements within the @try.
WarnAboutReturnGotoStmts(S->getTryBody());
} }
return 0; return 0;

View File

@ -21,3 +21,10 @@ void foo(id sem)
return; return;
} }
} }
void test_sync_with_implicit_finally() {
id foo;
@synchronized (foo) {
return; // The rewriter knows how to generate code for implicit finally
}
}