Fix the memory leak of FloatingLiteral/IntegerLiteral.
For large floats/integers, APFloat/APInt will allocate memory from the heap to represent these numbers. Unfortunately, when we use a BumpPtrAllocator to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with the APFloat/APInt values will never get freed. I introduce the class 'APNumericStorage' which uses ASTContext's allocator for memory allocation and is used internally by FloatingLiteral/IntegerLiteral. Fixes rdar://7637185 llvm-svn: 112361
This commit is contained in:
parent
1177ff1740
commit
43b205796f
|
@ -757,28 +757,84 @@ public:
|
|||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
class IntegerLiteral : public Expr {
|
||||
llvm::APInt Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
IntegerLiteral(const llvm::APInt &V, QualType type, SourceLocation l)
|
||||
: Expr(IntegerLiteralClass, type, false, false), Value(V), Loc(l) {
|
||||
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
|
||||
/// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without
|
||||
/// leaking memory.
|
||||
///
|
||||
/// For large floats/integers, APFloat/APInt will allocate memory from the heap
|
||||
/// to represent these numbers. Unfortunately, when we use a BumpPtrAllocator
|
||||
/// to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with
|
||||
/// the APFloat/APInt values will never get freed. APNumericStorage uses
|
||||
/// ASTContext's allocator for memory allocation.
|
||||
class APNumericStorage {
|
||||
unsigned BitWidth;
|
||||
union {
|
||||
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
|
||||
uint64_t *pVal; ///< Used to store the >64 bits integer value.
|
||||
};
|
||||
|
||||
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
|
||||
|
||||
APNumericStorage(const APNumericStorage&); // do not implement
|
||||
APNumericStorage& operator=(const APNumericStorage&); // do not implement
|
||||
|
||||
protected:
|
||||
APNumericStorage() : BitWidth(0), VAL(0) { }
|
||||
|
||||
llvm::APInt getIntValue() const {
|
||||
unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
|
||||
if (NumWords > 1)
|
||||
return llvm::APInt(BitWidth, NumWords, pVal);
|
||||
else
|
||||
return llvm::APInt(BitWidth, VAL);
|
||||
}
|
||||
void setIntValue(ASTContext &C, const llvm::APInt &Val);
|
||||
};
|
||||
|
||||
class APIntStorage : public APNumericStorage {
|
||||
public:
|
||||
llvm::APInt getValue() const { return getIntValue(); }
|
||||
void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); }
|
||||
};
|
||||
|
||||
class APFloatStorage : public APNumericStorage {
|
||||
public:
|
||||
llvm::APFloat getValue() const { return llvm::APFloat(getIntValue()); }
|
||||
void setValue(ASTContext &C, const llvm::APFloat &Val) {
|
||||
setIntValue(C, Val.bitcastToAPInt());
|
||||
}
|
||||
};
|
||||
|
||||
class IntegerLiteral : public Expr {
|
||||
APIntStorage Num;
|
||||
SourceLocation Loc;
|
||||
|
||||
/// \brief Construct an empty integer literal.
|
||||
explicit IntegerLiteral(EmptyShell Empty)
|
||||
: Expr(IntegerLiteralClass, Empty) { }
|
||||
|
||||
const llvm::APInt &getValue() const { return Value; }
|
||||
public:
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
IntegerLiteral(ASTContext &C, const llvm::APInt &V,
|
||||
QualType type, SourceLocation l)
|
||||
: Expr(IntegerLiteralClass, type, false, false), Loc(l) {
|
||||
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
|
||||
setValue(C, V);
|
||||
}
|
||||
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V,
|
||||
QualType type, SourceLocation l);
|
||||
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
llvm::APInt getValue() const { return Num.getValue(); }
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
/// \brief Retrieve the location of the literal.
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
void setValue(const llvm::APInt &Val) { Value = Val; }
|
||||
void setValue(ASTContext &C, const llvm::APInt &Val) { Num.setValue(C, Val); }
|
||||
void setLocation(SourceLocation Location) { Loc = Location; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
@ -827,21 +883,30 @@ public:
|
|||
};
|
||||
|
||||
class FloatingLiteral : public Expr {
|
||||
llvm::APFloat Value;
|
||||
APFloatStorage Num;
|
||||
bool IsExact : 1;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
FloatingLiteral(const llvm::APFloat &V, bool isexact,
|
||||
|
||||
FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact,
|
||||
QualType Type, SourceLocation L)
|
||||
: Expr(FloatingLiteralClass, Type, false, false), Value(V),
|
||||
IsExact(isexact), Loc(L) {}
|
||||
: Expr(FloatingLiteralClass, Type, false, false),
|
||||
IsExact(isexact), Loc(L) {
|
||||
setValue(C, V);
|
||||
}
|
||||
|
||||
/// \brief Construct an empty floating-point literal.
|
||||
explicit FloatingLiteral(EmptyShell Empty)
|
||||
: Expr(FloatingLiteralClass, Empty), Value(0.0) { }
|
||||
: Expr(FloatingLiteralClass, Empty), IsExact(false) { }
|
||||
|
||||
const llvm::APFloat &getValue() const { return Value; }
|
||||
void setValue(const llvm::APFloat &Val) { Value = Val; }
|
||||
public:
|
||||
static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V,
|
||||
bool isexact, QualType Type, SourceLocation L);
|
||||
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
llvm::APFloat getValue() const { return Num.getValue(); }
|
||||
void setValue(ASTContext &C, const llvm::APFloat &Val) {
|
||||
Num.setValue(C, Val);
|
||||
}
|
||||
|
||||
bool isExact() const { return IsExact; }
|
||||
void setExact(bool E) { IsExact = E; }
|
||||
|
|
|
@ -2818,8 +2818,9 @@ Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
|
|||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
return new (Importer.getToContext())
|
||||
IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation()));
|
||||
return IntegerLiteral::Create(Importer.getToContext(),
|
||||
E->getValue(), T,
|
||||
Importer.Import(E->getLocation()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
|
||||
|
|
|
@ -374,6 +374,44 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
|
|||
return "";
|
||||
}
|
||||
|
||||
void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
|
||||
if (hasAllocation())
|
||||
C.Deallocate(pVal);
|
||||
|
||||
BitWidth = Val.getBitWidth();
|
||||
unsigned NumWords = Val.getNumWords();
|
||||
const uint64_t* Words = Val.getRawData();
|
||||
if (NumWords > 1) {
|
||||
pVal = new (C) uint64_t[NumWords];
|
||||
std::copy(Words, Words + NumWords, pVal);
|
||||
} else if (NumWords == 1)
|
||||
VAL = Words[0];
|
||||
else
|
||||
VAL = 0;
|
||||
}
|
||||
|
||||
IntegerLiteral *
|
||||
IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V,
|
||||
QualType type, SourceLocation l) {
|
||||
return new (C) IntegerLiteral(C, V, type, l);
|
||||
}
|
||||
|
||||
IntegerLiteral *
|
||||
IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) {
|
||||
return new (C) IntegerLiteral(Empty);
|
||||
}
|
||||
|
||||
FloatingLiteral *
|
||||
FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V,
|
||||
bool isexact, QualType Type, SourceLocation L) {
|
||||
return new (C) FloatingLiteral(C, V, isexact, Type, L);
|
||||
}
|
||||
|
||||
FloatingLiteral *
|
||||
FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
|
||||
return new (C) FloatingLiteral(Empty);
|
||||
}
|
||||
|
||||
/// getValueAsApproximateDouble - This returns the value as an inaccurate
|
||||
/// double. Note that this may cause loss of precision, but is useful for
|
||||
/// debugging dumps, etc.
|
||||
|
|
|
@ -3029,9 +3029,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
|||
// is needed to decide what to do.
|
||||
unsigned IntSize =
|
||||
static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
|
||||
IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8),
|
||||
Context->IntTy,
|
||||
SourceLocation());
|
||||
IntegerLiteral *limit = IntegerLiteral::Create(*Context,
|
||||
llvm::APInt(IntSize, 8),
|
||||
Context->IntTy,
|
||||
SourceLocation());
|
||||
BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit,
|
||||
BO_LE,
|
||||
Context->IntTy,
|
||||
|
@ -5268,8 +5269,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
|||
int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
|
||||
unsigned IntSize =
|
||||
static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
|
||||
Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag),
|
||||
Context->IntTy, SourceLocation());
|
||||
Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
|
||||
Context->IntTy, SourceLocation());
|
||||
InitExprs.push_back(FlagExp);
|
||||
}
|
||||
NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
|
||||
|
|
|
@ -6480,8 +6480,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl,
|
|||
}
|
||||
// All conditions are met. Add a new bitfield to the tail end of ivars.
|
||||
llvm::APInt Zero(Context.getTypeSize(Context.CharTy), 0);
|
||||
Expr * BW =
|
||||
new (Context) IntegerLiteral(Zero, Context.CharTy, DeclLoc);
|
||||
Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc);
|
||||
|
||||
Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl),
|
||||
DeclLoc, 0,
|
||||
|
|
|
@ -4669,7 +4669,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
|
|||
|
||||
// Initialize the iteration variable to zero.
|
||||
llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
|
||||
IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc));
|
||||
IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
|
||||
|
||||
// Create a reference to the iteration variable; we'll use this several
|
||||
// times throughout.
|
||||
|
@ -4685,8 +4685,9 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
|
|||
Upper.zextOrTrunc(S.Context.getTypeSize(SizeType));
|
||||
Expr *Comparison
|
||||
= new (S.Context) BinaryOperator(IterationVarRef->Retain(),
|
||||
new (S.Context) IntegerLiteral(Upper, SizeType, Loc),
|
||||
BO_NE, S.Context.BoolTy, Loc);
|
||||
IntegerLiteral::Create(S.Context,
|
||||
Upper, SizeType, Loc),
|
||||
BO_NE, S.Context.BoolTy, Loc);
|
||||
|
||||
// Create the pre-increment of the iteration variable.
|
||||
Expr *Increment
|
||||
|
@ -5135,7 +5136,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
|||
ASTOwningVector<Expr*> CallArgs(*this);
|
||||
CallArgs.push_back(To.takeAs<Expr>());
|
||||
CallArgs.push_back(From.takeAs<Expr>());
|
||||
CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc));
|
||||
CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
|
||||
llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly
|
||||
Commas.push_back(Loc);
|
||||
Commas.push_back(Loc);
|
||||
|
|
|
@ -1946,7 +1946,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
|||
if (Tok.getLength() == 1) {
|
||||
const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok);
|
||||
unsigned IntSize = Context.Target.getIntWidth();
|
||||
return Owned(new (Context) IntegerLiteral(llvm::APInt(IntSize, Val-'0'),
|
||||
return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'),
|
||||
Context.IntTy, Tok.getLocation()));
|
||||
}
|
||||
|
||||
|
@ -2004,7 +2004,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
|||
}
|
||||
|
||||
bool isExact = (result == APFloat::opOK);
|
||||
Res = new (Context) FloatingLiteral(Val, isExact, Ty, Tok.getLocation());
|
||||
Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation());
|
||||
|
||||
} else if (!Literal.isIntegerLiteral()) {
|
||||
return ExprError();
|
||||
|
@ -2091,7 +2091,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
|||
if (ResultVal.getBitWidth() != Width)
|
||||
ResultVal.trunc(Width);
|
||||
}
|
||||
Res = new (Context) IntegerLiteral(ResultVal, Ty, Tok.getLocation());
|
||||
Res = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation());
|
||||
}
|
||||
|
||||
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
|
||||
|
|
|
@ -672,9 +672,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
|||
if (!ArraySize) {
|
||||
if (const ConstantArrayType *Array
|
||||
= Context.getAsConstantArrayType(AllocType)) {
|
||||
ArraySize = new (Context) IntegerLiteral(Array->getSize(),
|
||||
Context.getSizeType(),
|
||||
TypeRange.getEnd());
|
||||
ArraySize = IntegerLiteral::Create(Context, Array->getSize(),
|
||||
Context.getSizeType(),
|
||||
TypeRange.getEnd());
|
||||
AllocType = Array->getElementType();
|
||||
}
|
||||
}
|
||||
|
@ -922,7 +922,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
|
|||
// We don't care about the actual value of this argument.
|
||||
// FIXME: Should the Sema create the expression and embed it in the syntax
|
||||
// tree? Or should the consumer just recalculate the value?
|
||||
IntegerLiteral Size(llvm::APInt::getNullValue(
|
||||
IntegerLiteral Size(Context, llvm::APInt::getNullValue(
|
||||
Context.Target.getPointerWidth(0)),
|
||||
Context.getSizeType(),
|
||||
SourceLocation());
|
||||
|
|
|
@ -6754,8 +6754,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
|
|||
// post-decrement.
|
||||
if (Opc == UO_PostInc || Opc == UO_PostDec) {
|
||||
llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
|
||||
Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
|
||||
SourceLocation());
|
||||
Args[1] = IntegerLiteral::Create(Context, Zero, Context.IntTy,
|
||||
SourceLocation());
|
||||
NumArgs = 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -3149,7 +3149,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
|
|||
T,
|
||||
Loc));
|
||||
|
||||
return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc));
|
||||
return Owned(IntegerLiteral::Create(Context, *Arg.getAsIntegral(), T, Loc));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5332,10 +5332,10 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
|
|||
} else if (const ConstantArrayType *ConsArrayT
|
||||
= dyn_cast<ConstantArrayType>(ArrayT)) {
|
||||
ArraySize
|
||||
= SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
|
||||
ConsArrayT->getSize(),
|
||||
SemaRef.Context.getSizeType(),
|
||||
/*FIXME:*/E->getLocStart()));
|
||||
= SemaRef.Owned(IntegerLiteral::Create(SemaRef.Context,
|
||||
ConsArrayT->getSize(),
|
||||
SemaRef.Context.getSizeType(),
|
||||
/*FIXME:*/E->getLocStart()));
|
||||
AllocType = ConsArrayT->getElementType();
|
||||
} else if (const DependentSizedArrayType *DepArrayT
|
||||
= dyn_cast<DependentSizedArrayType>(ArrayT)) {
|
||||
|
@ -6352,7 +6352,8 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
|
|||
break;
|
||||
}
|
||||
|
||||
IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin());
|
||||
IntegerLiteral ArraySize(SemaRef.Context, *Size, SizeType,
|
||||
/*FIXME*/BracketsRange.getBegin());
|
||||
return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
|
||||
IndexTypeQuals, BracketsRange,
|
||||
getDerived().getBaseEntity());
|
||||
|
@ -6418,8 +6419,8 @@ QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType,
|
|||
llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy),
|
||||
NumElements, true);
|
||||
IntegerLiteral *VectorSize
|
||||
= new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy,
|
||||
AttributeLoc);
|
||||
= IntegerLiteral::Create(SemaRef.Context, numElements, SemaRef.Context.IntTy,
|
||||
AttributeLoc);
|
||||
return SemaRef.BuildExtVectorType(ElementType, VectorSize, AttributeLoc);
|
||||
}
|
||||
|
||||
|
|
|
@ -409,12 +409,12 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
|
||||
VisitExpr(E);
|
||||
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
E->setValue(Reader.ReadAPInt(Record, Idx));
|
||||
E->setValue(*Reader.getContext(), Reader.ReadAPInt(Record, Idx));
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
|
||||
VisitExpr(E);
|
||||
E->setValue(Reader.ReadAPFloat(Record, Idx));
|
||||
E->setValue(*Reader.getContext(), Reader.ReadAPFloat(Record, Idx));
|
||||
E->setExact(Record[Idx++]);
|
||||
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
}
|
||||
|
@ -1401,11 +1401,11 @@ Stmt *ASTReader::ReadStmtFromStream(llvm::BitstreamCursor &Cursor) {
|
|||
break;
|
||||
|
||||
case EXPR_INTEGER_LITERAL:
|
||||
S = new (Context) IntegerLiteral(Empty);
|
||||
S = IntegerLiteral::Create(*Context, Empty);
|
||||
break;
|
||||
|
||||
case EXPR_FLOATING_LITERAL:
|
||||
S = new (Context) FloatingLiteral(Empty);
|
||||
S = FloatingLiteral::Create(*Context, Empty);
|
||||
break;
|
||||
|
||||
case EXPR_IMAGINARY_LITERAL:
|
||||
|
|
Loading…
Reference in New Issue