aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGObjC.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-04-04 00:20:38 +0000
committerJohn McCall <rjmccall@apple.com>2013-04-04 00:20:38 +0000
commit527842f97b684831de2b1a455649131ed381ece4 (patch)
treed0afc6daf5a438c0ce684163afc53dc816d2a98d /lib/CodeGen/CGObjC.cpp
parente145bfd06c7eaf0cff0f7d825d1c6244127c26df (diff)
Protect the values of array and dictionary literals from the
ARC optimizer while they're held in local unsafe buffers. Based on a patch by Jesse Rusak! rdar://13573224 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178721 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGObjC.cpp')
-rw-r--r--lib/CodeGen/CGObjC.cpp39
1 files changed, 33 insertions, 6 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 2e3bd5f7f1..79d97b99b4 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -109,32 +109,50 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
+ // In ARC, we may need to do extra work to keep all the keys and
+ // values alive until after the call.
+ SmallVector<llvm::Value *, 16> NeededObjects;
+ bool TrackNeededObjects =
+ (getLangOpts().ObjCAutoRefCount &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0);
+
// Perform the actual initialialization of the array(s).
for (uint64_t i = 0; i < NumElements; i++) {
if (ALE) {
- // Emit the initializer.
+ // Emit the element and store it to the appropriate array slot.
const Expr *Rhs = ALE->getElement(i);
LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Rhs->getType()),
Context);
- EmitScalarInit(Rhs, /*D=*/0, LV, /*capturedByInit=*/false);
+
+ llvm::Value *value = EmitScalarExpr(Rhs);
+ EmitStoreThroughLValue(RValue::get(value), LV, true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(value);
+ }
} else {
- // Emit the key initializer.
+ // Emit the key and store it to the appropriate array slot.
const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i),
ElementType,
Context.getTypeAlignInChars(Key->getType()),
Context);
- EmitScalarInit(Key, /*D=*/0, KeyLV, /*capturedByInit=*/false);
+ llvm::Value *keyValue = EmitScalarExpr(Key);
+ EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
- // Emit the value initializer.
+ // Emit the value and store it to the appropriate array slot.
const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Value->getType()),
Context);
- EmitScalarInit(Value, /*D=*/0, ValueLV, /*capturedByInit=*/false);
+ llvm::Value *valueValue = EmitScalarExpr(Value);
+ EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(keyValue);
+ NeededObjects.push_back(valueValue);
+ }
}
}
@@ -172,6 +190,15 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
Sel,
Receiver, Args, Class,
MethodWithObjects);
+
+ // The above message send needs these objects, but in ARC they are
+ // passed in a buffer that is essentially __unsafe_unretained.
+ // Therefore we must prevent the optimizer from releasing them until
+ // after the call.
+ if (TrackNeededObjects) {
+ EmitARCIntrinsicUse(NeededObjects);
+ }
+
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}