зеркало из https://github.com/microsoft/clang-1.git
Plug a long standing memory leak in TemplateArgument.
The integral APSInt value is now stored in a decomposed form and the backing store for large values is allocated via the ASTContext. This way its not leaked as TemplateArguments are never destructed when they are allocated in the ASTContext. Since the integral data is immutable it is now shared between instances, making copying TemplateArguments a trivial operation. Currently getting the integral data out of a TemplateArgument requires creating a new APSInt object. This is cheap when the value is small but can be expensive if it's not. If this turns out to be an issue a more efficient accessor could be added. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158150 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
575b66a8e0
Коммит
855243789c
|
@ -73,7 +73,15 @@ private:
|
|||
union {
|
||||
uintptr_t TypeOrValue;
|
||||
struct {
|
||||
char Value[sizeof(llvm::APSInt)];
|
||||
// We store a decomposed APSInt with the data allocated by ASTContext if
|
||||
// BitWidth > 64. The memory may be shared between multiple
|
||||
// TemplateArgument instances.
|
||||
union {
|
||||
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
|
||||
const uint64_t *pVal; ///< Used to store the >64 bits integer value.
|
||||
};
|
||||
unsigned BitWidth : 31;
|
||||
unsigned IsUnsigned : 1;
|
||||
void *Type;
|
||||
} Integer;
|
||||
struct {
|
||||
|
@ -104,11 +112,15 @@ public:
|
|||
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||
}
|
||||
|
||||
/// \brief Construct an integral constant template argument.
|
||||
TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
new (Integer.Value) llvm::APSInt(Value);
|
||||
/// \brief Construct an integral constant template argument. The memory to
|
||||
/// store the value is allocated with Ctx.
|
||||
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
|
||||
|
||||
/// \brief Construct an integral constant template argument with the same
|
||||
/// value as Other but a different type.
|
||||
TemplateArgument(const TemplateArgument &Other, QualType Type)
|
||||
: Kind(Integral) {
|
||||
Integer = Other.Integer;
|
||||
Integer.Type = Type.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
|
@ -165,62 +177,6 @@ public:
|
|||
this->Args.NumArgs = NumArgs;
|
||||
}
|
||||
|
||||
/// \brief Copy constructor for a template argument.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
if (Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Other.Kind && Kind == Integral) {
|
||||
// Copy integral values.
|
||||
*this->getAsIntegral() = *Other.getAsIntegral();
|
||||
Integer.Type = Other.Integer.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroy the current integral value, if that's what we're holding.
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
|
||||
Kind = Other.Kind;
|
||||
|
||||
if (Other.Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Other.Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else {
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TemplateArgument() {
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
}
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgument CreatePackCopy(ASTContext &Context,
|
||||
|
@ -286,14 +242,14 @@ public:
|
|||
llvm::Optional<unsigned> getNumTemplateExpansions() const;
|
||||
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
llvm::APSInt *getAsIntegral() {
|
||||
if (Kind != Integral)
|
||||
return 0;
|
||||
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
|
||||
}
|
||||
|
||||
const llvm::APSInt *getAsIntegral() const {
|
||||
return const_cast<TemplateArgument*>(this)->getAsIntegral();
|
||||
// FIXME: Provide a way to read the integral data without copying the value.
|
||||
llvm::APSInt getAsIntegral() const {
|
||||
if (Integer.BitWidth <= 64)
|
||||
return llvm::APSInt(llvm::APInt(Integer.BitWidth, Integer.VAL),
|
||||
Integer.IsUnsigned);
|
||||
return llvm::APSInt(llvm::APInt(Integer.BitWidth,
|
||||
llvm::makeArrayRef(Integer.pVal, Integer.BitWidth / 8)),
|
||||
Integer.IsUnsigned);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type of the integral value.
|
||||
|
|
|
@ -152,10 +152,11 @@ namespace clang {
|
|||
|
||||
/// \brief Construct an integral non-type template argument that
|
||||
/// has been deduced, possibly from an array bound.
|
||||
DeducedTemplateArgument(const llvm::APSInt &Value,
|
||||
DeducedTemplateArgument(ASTContext &Ctx,
|
||||
const llvm::APSInt &Value,
|
||||
QualType ValueType,
|
||||
bool DeducedFromArrayBound)
|
||||
: TemplateArgument(Value, ValueType),
|
||||
: TemplateArgument(Ctx, Value, ValueType),
|
||||
DeducedFromArrayBound(DeducedFromArrayBound) { }
|
||||
|
||||
/// \brief For a non-type template argument, determine whether the
|
||||
|
|
|
@ -3336,8 +3336,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
|
|||
Arg.getNumTemplateExpansions());
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
return TemplateArgument(*Arg.getAsIntegral(),
|
||||
getCanonicalType(Arg.getIntegralType()));
|
||||
return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));
|
||||
|
||||
case TemplateArgument::Type:
|
||||
return TemplateArgument(getCanonicalType(Arg.getAsType()));
|
||||
|
|
|
@ -322,7 +322,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
Arg2.getIntegralType()))
|
||||
return false;
|
||||
|
||||
return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral());
|
||||
return IsSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
|
||||
|
||||
case TemplateArgument::Declaration:
|
||||
if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
|
||||
|
@ -1992,7 +1992,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
|
|||
QualType ToType = Importer.Import(From.getIntegralType());
|
||||
if (ToType.isNull())
|
||||
return TemplateArgument();
|
||||
return TemplateArgument(*From.getAsIntegral(), ToType);
|
||||
return TemplateArgument(From, ToType);
|
||||
}
|
||||
|
||||
case TemplateArgument::Declaration:
|
||||
|
|
|
@ -326,7 +326,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
|
|||
}
|
||||
case TemplateArgument::Integral: {
|
||||
push("integer");
|
||||
setInteger("value", *A.getAsIntegral());
|
||||
setInteger("value", A.getAsIntegral());
|
||||
completeAttrs();
|
||||
pop();
|
||||
break;
|
||||
|
|
|
@ -3132,7 +3132,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
|
|||
break;
|
||||
}
|
||||
case TemplateArgument::Integral:
|
||||
mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
|
||||
mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
|
||||
break;
|
||||
case TemplateArgument::Declaration: {
|
||||
assert(P && "Missing template parameter for declaration argument");
|
||||
|
|
|
@ -638,7 +638,7 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs
|
|||
mangleType(TA.getAsType());
|
||||
break;
|
||||
case TemplateArgument::Integral:
|
||||
mangleIntegerLiteral(TA.getIntegralType(), *TA.getAsIntegral());
|
||||
mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
|
||||
break;
|
||||
default: {
|
||||
// Issue a diagnostic.
|
||||
|
|
|
@ -1275,7 +1275,7 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
|
|||
const TemplateArgument &Pack = Args->get(0);
|
||||
for (TemplateArgument::pack_iterator I = Pack.pack_begin(),
|
||||
E = Pack.pack_end(); I != E; ++I) {
|
||||
char C = (char)I->getAsIntegral()->getZExtValue();
|
||||
char C = (char)I->getAsIntegral().getZExtValue();
|
||||
OS << C;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1161,7 +1161,7 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
|
|||
break;
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
Arg.getAsIntegral()->Profile(ID);
|
||||
Arg.getAsIntegral().Profile(ID);
|
||||
VisitType(Arg.getIntegralType());
|
||||
break;
|
||||
|
||||
|
|
|
@ -36,17 +36,17 @@ using namespace clang;
|
|||
static void printIntegral(const TemplateArgument &TemplArg,
|
||||
raw_ostream &Out) {
|
||||
const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
|
||||
const llvm::APSInt *Val = TemplArg.getAsIntegral();
|
||||
const llvm::APSInt &Val = TemplArg.getAsIntegral();
|
||||
|
||||
if (T->isBooleanType()) {
|
||||
Out << (Val->getBoolValue() ? "true" : "false");
|
||||
Out << (Val.getBoolValue() ? "true" : "false");
|
||||
} else if (T->isCharType()) {
|
||||
const char Ch = Val->getZExtValue();
|
||||
const char Ch = Val.getZExtValue();
|
||||
Out << ((Ch == '\'') ? "'\\" : "'");
|
||||
Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true);
|
||||
Out << "'";
|
||||
} else {
|
||||
Out << Val->toString(10);
|
||||
Out << Val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,24 @@ static void printIntegral(const TemplateArgument &TemplArg,
|
|||
// TemplateArgument Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
|
||||
QualType Type)
|
||||
: Kind(Integral) {
|
||||
// Copy the APSInt value into our decomposed form.
|
||||
Integer.BitWidth = Value.getBitWidth();
|
||||
Integer.IsUnsigned = Value.isUnsigned();
|
||||
// If the value is large, we have to get additional memory from the ASTContext
|
||||
if (Integer.BitWidth > 64) {
|
||||
void *Mem = Ctx.Allocate(Integer.BitWidth / 8);
|
||||
std::memcpy(Mem, Value.getRawData(), Integer.BitWidth / 8);
|
||||
Integer.pVal = static_cast<uint64_t *>(Mem);
|
||||
} else {
|
||||
Integer.VAL = Value.getZExtValue();
|
||||
}
|
||||
|
||||
Integer.Type = Type.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs) {
|
||||
|
@ -246,7 +264,7 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
|
|||
}
|
||||
|
||||
case Integral:
|
||||
getAsIntegral()->Profile(ID);
|
||||
getAsIntegral().Profile(ID);
|
||||
getIntegralType().Profile(ID);
|
||||
break;
|
||||
|
||||
|
@ -275,7 +293,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
|
|||
|
||||
case Integral:
|
||||
return getIntegralType() == Other.getIntegralType() &&
|
||||
*getAsIntegral() == *Other.getAsIntegral();
|
||||
getAsIntegral() == Other.getAsIntegral();
|
||||
|
||||
case Pack:
|
||||
if (Args.NumArgs != Other.Args.NumArgs) return false;
|
||||
|
@ -498,7 +516,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
|
|||
return DB << "nullptr";
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
return DB << Arg.getAsIntegral()->toString(10);
|
||||
return DB << Arg.getAsIntegral().toString(10);
|
||||
|
||||
case TemplateArgument::Template:
|
||||
return DB << Arg.getAsTemplate();
|
||||
|
|
|
@ -1086,7 +1086,7 @@ CollectTemplateParams(const TemplateParameterList *TPList,
|
|||
llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
|
||||
llvm::DITemplateValueParameter TVP =
|
||||
DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
|
||||
TA.getAsIntegral()->getZExtValue());
|
||||
TA.getAsIntegral().getZExtValue());
|
||||
TemplateParams.push_back(TVP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2605,7 +2605,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
|
|||
llvm::APSInt Value(CharBits, CharIsUnsigned);
|
||||
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
|
||||
Value = ThisTokBegin[I];
|
||||
TemplateArgument Arg(Value, Context.CharTy);
|
||||
TemplateArgument Arg(Context, Value, Context.CharTy);
|
||||
TemplateArgumentLocInfo ArgInfo;
|
||||
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
|
||||
}
|
||||
|
|
|
@ -4125,7 +4125,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
IntegerType = Enum->getDecl()->getIntegerType();
|
||||
Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
|
||||
|
||||
Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
|
||||
Converted = TemplateArgument(Context, Value,
|
||||
Context.getCanonicalType(ParamType));
|
||||
return ArgResult;
|
||||
}
|
||||
|
||||
|
@ -4251,7 +4252,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
}
|
||||
}
|
||||
|
||||
Converted = TemplateArgument(Value,
|
||||
Converted = TemplateArgument(Context, Value,
|
||||
ParamType->isEnumeralType()
|
||||
? Context.getCanonicalType(ParamType)
|
||||
: IntegerType);
|
||||
|
@ -4569,13 +4570,13 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
|
|||
Kind = CharacterLiteral::Ascii;
|
||||
|
||||
return Owned(new (Context) CharacterLiteral(
|
||||
Arg.getAsIntegral()->getZExtValue(),
|
||||
Arg.getAsIntegral().getZExtValue(),
|
||||
Kind, T, Loc));
|
||||
}
|
||||
|
||||
if (T->isBooleanType())
|
||||
return Owned(new (Context) CXXBoolLiteralExpr(
|
||||
Arg.getAsIntegral()->getBoolValue(),
|
||||
Arg.getAsIntegral().getBoolValue(),
|
||||
T, Loc));
|
||||
|
||||
if (T->isNullPtrType())
|
||||
|
@ -4590,7 +4591,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
|
|||
else
|
||||
BT = T;
|
||||
|
||||
Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc);
|
||||
Expr *E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), BT, Loc);
|
||||
if (T->isEnumeralType()) {
|
||||
// FIXME: This is a hack. We need a better way to handle substituted
|
||||
// non-type template parameters.
|
||||
|
|
|
@ -193,7 +193,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
|||
if (Y.getKind() == TemplateArgument::Expression ||
|
||||
Y.getKind() == TemplateArgument::Declaration ||
|
||||
(Y.getKind() == TemplateArgument::Integral &&
|
||||
hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral())))
|
||||
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
|
||||
return DeducedTemplateArgument(X,
|
||||
X.wasDeducedFromArrayBound() &&
|
||||
Y.wasDeducedFromArrayBound());
|
||||
|
@ -293,7 +293,8 @@ DeduceNonTypeTemplateArgument(Sema &S,
|
|||
assert(NTTP->getDepth() == 0 &&
|
||||
"Cannot deduce non-type template argument with depth > 0");
|
||||
|
||||
DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound);
|
||||
DeducedTemplateArgument NewDeduced(S.Context, Value, ValueType,
|
||||
DeducedFromArrayBound);
|
||||
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
|
||||
Deduced[NTTP->getIndex()],
|
||||
NewDeduced);
|
||||
|
@ -1595,7 +1596,7 @@ DeduceTemplateArguments(Sema &S,
|
|||
|
||||
case TemplateArgument::Integral:
|
||||
if (Arg.getKind() == TemplateArgument::Integral) {
|
||||
if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral()))
|
||||
if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
|
||||
return Sema::TDK_Success;
|
||||
|
||||
Info.FirstArg = Param;
|
||||
|
@ -1618,7 +1619,7 @@ DeduceTemplateArguments(Sema &S,
|
|||
= getDeducedParameterFromExpr(Param.getAsExpr())) {
|
||||
if (Arg.getKind() == TemplateArgument::Integral)
|
||||
return DeduceNonTypeTemplateArgument(S, NTTP,
|
||||
*Arg.getAsIntegral(),
|
||||
Arg.getAsIntegral(),
|
||||
Arg.getIntegralType(),
|
||||
/*ArrayBound=*/false,
|
||||
Info, Deduced);
|
||||
|
@ -1867,7 +1868,7 @@ static bool isSameTemplateArg(ASTContext &Context,
|
|||
Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer();
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
return *X.getAsIntegral() == *Y.getAsIntegral();
|
||||
return X.getAsIntegral() == Y.getAsIntegral();
|
||||
|
||||
case TemplateArgument::Expression: {
|
||||
llvm::FoldingSetNodeID XID, YID;
|
||||
|
|
|
@ -5905,7 +5905,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
|
|||
case TemplateArgument::Integral: {
|
||||
llvm::APSInt Value = ReadAPSInt(Record, Idx);
|
||||
QualType T = readType(F, Record, Idx);
|
||||
return TemplateArgument(Value, T);
|
||||
return TemplateArgument(Context, Value, T);
|
||||
}
|
||||
case TemplateArgument::Template:
|
||||
return TemplateArgument(ReadTemplateName(F, Record, Idx));
|
||||
|
|
|
@ -4147,7 +4147,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
|
|||
AddDeclRef(Arg.getAsDecl(), Record);
|
||||
break;
|
||||
case TemplateArgument::Integral:
|
||||
AddAPSInt(*Arg.getAsIntegral(), Record);
|
||||
AddAPSInt(Arg.getAsIntegral(), Record);
|
||||
AddTypeRef(Arg.getIntegralType(), Record);
|
||||
break;
|
||||
case TemplateArgument::Template:
|
||||
|
|
|
@ -754,7 +754,7 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
|
|||
case TemplateArgument::Integral:
|
||||
Out << 'V';
|
||||
VisitType(Arg.getIntegralType());
|
||||
Out << *Arg.getAsIntegral();
|
||||
Out << Arg.getAsIntegral();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче