aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExprCXX.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-09-17 00:50:28 +0000
committerJohn McCall <rjmccall@apple.com>2010-09-17 00:50:28 +0000
commit3019c444c672938c57f5573840071ecd73425ee7 (patch)
treeb638ccc0e22a7087da29add22019968b984491e5 /lib/CodeGen/CGExprCXX.cpp
parente5a37f48388c7e4cc081f44d13a4910bfa56cd35 (diff)
When emitting a new-expression inside a conditional expression,
the cleanup might not be dominated by the allocation code. In this case, we have to store aside all the delete arguments in case we need them later. There's room for optimization here in cases where we end up not actually needing the cleanup in different branches (or being able to pop it after the initialization code). Also make sure we only call this operator delete along the path where we actually allocated something. Fixes rdar://problem/8439196. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114145 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExprCXX.cpp')
-rw-r--r--lib/CodeGen/CGExprCXX.cpp205
1 files changed, 198 insertions, 7 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 584f6c099b..4dbfa7ee4f 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -675,6 +675,105 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
StoreAnyExprIntoOneUnit(CGF, E, NewPtr);
}
+/// A utility class for saving an rvalue.
+class SavedRValue {
+public:
+ enum Kind { ScalarLiteral, ScalarAddress,
+ AggregateLiteral, AggregateAddress,
+ Complex };
+
+private:
+ llvm::Value *Value;
+ Kind K;
+
+ SavedRValue(llvm::Value *V, Kind K) : Value(V), K(K) {}
+
+public:
+ SavedRValue() {}
+
+ static SavedRValue forScalarLiteral(llvm::Value *V) {
+ return SavedRValue(V, ScalarLiteral);
+ }
+
+ static SavedRValue forScalarAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, ScalarAddress);
+ }
+
+ static SavedRValue forAggregateLiteral(llvm::Value *V) {
+ return SavedRValue(V, AggregateLiteral);
+ }
+
+ static SavedRValue forAggregateAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, AggregateAddress);
+ }
+
+ static SavedRValue forComplexAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, Complex);
+ }
+
+ Kind getKind() const { return K; }
+ llvm::Value *getValue() const { return Value; }
+};
+
+/// Given an r-value, perform the code necessary to make sure that a
+/// future RestoreRValue will be able to load the value without
+/// domination concerns.
+static SavedRValue SaveRValue(CodeGenFunction &CGF, RValue RV) {
+ if (RV.isScalar()) {
+ llvm::Value *V = RV.getScalarVal();
+
+ // These automatically dominate and don't need to be saved.
+ if (isa<llvm::Constant>(V) || isa<llvm::AllocaInst>(V))
+ return SavedRValue::forScalarLiteral(V);
+
+ // Everything else needs an alloca.
+ llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
+ CGF.Builder.CreateStore(V, Addr);
+ return SavedRValue::forScalarAddress(Addr);
+ }
+
+ if (RV.isComplex()) {
+ CodeGenFunction::ComplexPairTy V = RV.getComplexVal();
+ const llvm::Type *ComplexTy =
+ llvm::StructType::get(CGF.getLLVMContext(),
+ V.first->getType(), V.second->getType(),
+ (void*) 0);
+ llvm::Value *Addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
+ CGF.StoreComplexToAddr(V, Addr, /*volatile*/ false);
+ return SavedRValue::forComplexAddress(Addr);
+ }
+
+ assert(RV.isAggregate());
+ llvm::Value *V = RV.getAggregateAddr(); // TODO: volatile?
+ if (isa<llvm::Constant>(V) || isa<llvm::AllocaInst>(V))
+ return SavedRValue::forAggregateLiteral(V);
+
+ llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
+ CGF.Builder.CreateStore(V, Addr);
+ return SavedRValue::forAggregateAddress(Addr);
+}
+
+/// Given a saved r-value produced by SaveRValue, perform the code
+/// necessary to restore it to usability at the current insertion
+/// point.
+static RValue RestoreRValue(CodeGenFunction &CGF, SavedRValue RV) {
+ switch (RV.getKind()) {
+ case SavedRValue::ScalarLiteral:
+ return RValue::get(RV.getValue());
+ case SavedRValue::ScalarAddress:
+ return RValue::get(CGF.Builder.CreateLoad(RV.getValue()));
+ case SavedRValue::AggregateLiteral:
+ return RValue::getAggregate(RV.getValue());
+ case SavedRValue::AggregateAddress:
+ return RValue::getAggregate(CGF.Builder.CreateLoad(RV.getValue()));
+ case SavedRValue::Complex:
+ return RValue::getComplex(CGF.LoadComplexFromAddr(RV.getValue(), false));
+ }
+
+ llvm_unreachable("bad saved r-value kind");
+ return RValue();
+}
+
namespace {
/// A cleanup to call the given 'operator delete' function upon
/// abnormal exit from a new expression.
@@ -729,6 +828,104 @@ namespace {
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
};
+
+ /// A cleanup to call the given 'operator delete' function upon
+ /// abnormal exit from a new expression when the new expression is
+ /// conditional.
+ class CallDeleteDuringConditionalNew : public EHScopeStack::Cleanup {
+ size_t NumPlacementArgs;
+ const FunctionDecl *OperatorDelete;
+ SavedRValue Ptr;
+ SavedRValue AllocSize;
+
+ SavedRValue *getPlacementArgs() {
+ return reinterpret_cast<SavedRValue*>(this+1);
+ }
+
+ public:
+ static size_t getExtraSize(size_t NumPlacementArgs) {
+ return NumPlacementArgs * sizeof(SavedRValue);
+ }
+
+ CallDeleteDuringConditionalNew(size_t NumPlacementArgs,
+ const FunctionDecl *OperatorDelete,
+ SavedRValue Ptr,
+ SavedRValue AllocSize)
+ : NumPlacementArgs(NumPlacementArgs), OperatorDelete(OperatorDelete),
+ Ptr(Ptr), AllocSize(AllocSize) {}
+
+ void setPlacementArg(unsigned I, SavedRValue Arg) {
+ assert(I < NumPlacementArgs && "index out of range");
+ getPlacementArgs()[I] = Arg;
+ }
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ const FunctionProtoType *FPT
+ = OperatorDelete->getType()->getAs<FunctionProtoType>();
+ assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
+ (FPT->getNumArgs() == 2 && NumPlacementArgs == 0));
+
+ CallArgList DeleteArgs;
+
+ // The first argument is always a void*.
+ FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
+ DeleteArgs.push_back(std::make_pair(RestoreRValue(CGF, Ptr), *AI++));
+
+ // A member 'operator delete' can take an extra 'size_t' argument.
+ if (FPT->getNumArgs() == NumPlacementArgs + 2) {
+ RValue RV = RestoreRValue(CGF, AllocSize);
+ DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ }
+
+ // Pass the rest of the arguments, which must match exactly.
+ for (unsigned I = 0; I != NumPlacementArgs; ++I) {
+ RValue RV = RestoreRValue(CGF, getPlacementArgs()[I]);
+ DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ }
+
+ // Call 'operator delete'.
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
+ CGF.CGM.GetAddrOfFunction(OperatorDelete),
+ ReturnValueSlot(), DeleteArgs, OperatorDelete);
+ }
+ };
+}
+
+/// Enter a cleanup to call 'operator delete' if the initializer in a
+/// new-expression throws.
+static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
+ const CXXNewExpr *E,
+ llvm::Value *NewPtr,
+ llvm::Value *AllocSize,
+ const CallArgList &NewArgs) {
+ // If we're not inside a conditional branch, then the cleanup will
+ // dominate and we can do the easier (and more efficient) thing.
+ if (!CGF.isInConditionalBranch()) {
+ CallDeleteDuringNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringNew>(EHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ NewPtr, AllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I, NewArgs[I+1].first);
+
+ return;
+ }
+
+ // Otherwise, we need to save all this stuff.
+ SavedRValue SavedNewPtr = SaveRValue(CGF, RValue::get(NewPtr));
+ SavedRValue SavedAllocSize = SaveRValue(CGF, RValue::get(AllocSize));
+
+ CallDeleteDuringConditionalNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringConditionalNew>(InactiveEHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ SavedNewPtr,
+ SavedAllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I, SaveRValue(CGF, NewArgs[I+1].first));
+
+ CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin());
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
@@ -827,13 +1024,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// exception is thrown.
EHScopeStack::stable_iterator CallOperatorDelete;
if (E->getOperatorDelete()) {
- CallDeleteDuringNew *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<CallDeleteDuringNew>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- NewPtr, AllocSize);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
- Cleanup->setPlacementArg(I, NewArgs[I+1].first);
+ EnterNewDeleteCleanup(*this, E, NewPtr, AllocSize, NewArgs);
CallOperatorDelete = EHStack.stable_begin();
}