summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruno Ricci <riccibrun@gmail.com>2018-11-15 17:31:16 +0000
committerBruno Ricci <riccibrun@gmail.com>2018-11-15 17:31:16 +0000
commit2b074a4200135c633ba23aadb1d86b8b60b9c871 (patch)
tree50c38439f76e9a418b6f7a5609bc940a309e73e9 /lib
parentb9e6abd1ea926a4d0b2395a4e6e1a1f2f4fe1f7b (diff)
downloadclang-2b074a4200135c633ba23aadb1d86b8b60b9c871.tar.gz
[AST] Store the string data in StringLiteral in a trailing array of chars
Use the newly available space in the bit-fields of Stmt and store the string data in a trailing array of chars after the trailing array of SourceLocation. This cuts the size of StringLiteral by 2 pointers. Also refactor slightly StringLiteral::Create and StringLiteral::CreateEmpty so that StringLiteral::Create is just responsible for the allocation, and the constructor is responsible for doing all the initialization. This match what is done for the other classes in general. This patch should have no other functional changes apart from this. A concern was raised during review about the interaction between this patch and serialization abbreviations. I believe however that there is currently no abbreviation defined for StringLiteral. The only statements/expressions which have abbreviations are currently DeclRefExpr, IntegerLiteral, CharacterLiteral and ImplicitCastExpr. Differential Revision: https://reviews.llvm.org/D54166 Reviewed By: dblaikie, rjmccall git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@346969 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Expr.cpp132
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp48
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp18
3 files changed, 111 insertions, 87 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 37575e7ba2..b811b22239 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -912,42 +912,80 @@ unsigned StringLiteral::mapCharByteWidth(TargetInfo const &Target,
return CharByteWidth;
}
-StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str,
- StringKind Kind, bool Pascal, QualType Ty,
- const SourceLocation *Loc,
- unsigned NumStrs) {
- assert(C.getAsConstantArrayType(Ty) &&
+StringLiteral::StringLiteral(const ASTContext &Ctx, StringRef Str,
+ StringKind Kind, bool Pascal, QualType Ty,
+ const SourceLocation *Loc,
+ unsigned NumConcatenated)
+ : Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false,
+ false) {
+ assert(Ctx.getAsConstantArrayType(Ty) &&
"StringLiteral must be of constant array type!");
+ unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
+ unsigned ByteLength = Str.size();
+ assert((ByteLength % CharByteWidth == 0) &&
+ "The size of the data must be a multiple of CharByteWidth!");
+
+ // Avoid the expensive division. The compiler should be able to figure it
+ // out by itself. However as of clang 7, even with the appropriate
+ // llvm_unreachable added just here, it is not able to do so.
+ unsigned Length;
+ switch (CharByteWidth) {
+ case 1:
+ Length = ByteLength;
+ break;
+ case 2:
+ Length = ByteLength / 2;
+ break;
+ case 4:
+ Length = ByteLength / 4;
+ break;
+ default:
+ llvm_unreachable("Unsupported character width!");
+ }
- // Allocate enough space for the StringLiteral plus an array of locations for
- // any concatenated string tokens.
- void *Mem =
- C.Allocate(sizeof(StringLiteral) + sizeof(SourceLocation) * (NumStrs - 1),
- alignof(StringLiteral));
- StringLiteral *SL = new (Mem) StringLiteral(Ty);
+ StringLiteralBits.Kind = Kind;
+ StringLiteralBits.CharByteWidth = CharByteWidth;
+ StringLiteralBits.IsPascal = Pascal;
+ StringLiteralBits.NumConcatenated = NumConcatenated;
+ *getTrailingObjects<unsigned>() = Length;
- // OPTIMIZE: could allocate this appended to the StringLiteral.
- SL->setString(C,Str,Kind,Pascal);
+ // Initialize the trailing array of SourceLocation.
+ // This is safe since SourceLocation is POD-like.
+ std::memcpy(getTrailingObjects<SourceLocation>(), Loc,
+ NumConcatenated * sizeof(SourceLocation));
- SL->TokLocs[0] = Loc[0];
- SL->NumConcatenated = NumStrs;
+ // Initialize the trailing array of char holding the string data.
+ std::memcpy(getTrailingObjects<char>(), Str.data(), ByteLength);
+}
- if (NumStrs != 1)
- memcpy(&SL->TokLocs[1], Loc+1, sizeof(SourceLocation)*(NumStrs-1));
- return SL;
+StringLiteral::StringLiteral(EmptyShell Empty, unsigned NumConcatenated,
+ unsigned Length, unsigned CharByteWidth)
+ : Expr(StringLiteralClass, Empty) {
+ StringLiteralBits.CharByteWidth = CharByteWidth;
+ StringLiteralBits.NumConcatenated = NumConcatenated;
+ *getTrailingObjects<unsigned>() = Length;
}
-StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C,
- unsigned NumStrs) {
- void *Mem =
- C.Allocate(sizeof(StringLiteral) + sizeof(SourceLocation) * (NumStrs - 1),
- alignof(StringLiteral));
- StringLiteral *SL =
- new (Mem) StringLiteral(C.adjustStringLiteralBaseType(QualType()));
- SL->CharByteWidth = 0;
- SL->Length = 0;
- SL->NumConcatenated = NumStrs;
- return SL;
+StringLiteral *StringLiteral::Create(const ASTContext &Ctx, StringRef Str,
+ StringKind Kind, bool Pascal, QualType Ty,
+ const SourceLocation *Loc,
+ unsigned NumConcatenated) {
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned, SourceLocation, char>(
+ 1, NumConcatenated, Str.size()),
+ alignof(StringLiteral));
+ return new (Mem)
+ StringLiteral(Ctx, Str, Kind, Pascal, Ty, Loc, NumConcatenated);
+}
+
+StringLiteral *StringLiteral::CreateEmpty(const ASTContext &Ctx,
+ unsigned NumConcatenated,
+ unsigned Length,
+ unsigned CharByteWidth) {
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned, SourceLocation, char>(
+ 1, NumConcatenated, Length * CharByteWidth),
+ alignof(StringLiteral));
+ return new (Mem)
+ StringLiteral(EmptyShell(), NumConcatenated, Length, CharByteWidth);
}
void StringLiteral::outputString(raw_ostream &OS) const {
@@ -1046,42 +1084,6 @@ void StringLiteral::outputString(raw_ostream &OS) const {
OS << '"';
}
-void StringLiteral::setString(const ASTContext &C, StringRef Str,
- StringKind Kind, bool IsPascal) {
- //FIXME: we assume that the string data comes from a target that uses the same
- // code unit size and endianness for the type of string.
- this->Kind = Kind;
- this->IsPascal = IsPascal;
-
- CharByteWidth = mapCharByteWidth(C.getTargetInfo(),Kind);
- assert((Str.size()%CharByteWidth == 0)
- && "size of data must be multiple of CharByteWidth");
- Length = Str.size()/CharByteWidth;
-
- switch(CharByteWidth) {
- case 1: {
- char *AStrData = new (C) char[Length];
- std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
- StrData.asChar = AStrData;
- break;
- }
- case 2: {
- uint16_t *AStrData = new (C) uint16_t[Length];
- std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
- StrData.asUInt16 = AStrData;
- break;
- }
- case 4: {
- uint32_t *AStrData = new (C) uint32_t[Length];
- std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
- StrData.asUInt32 = AStrData;
- break;
- }
- default:
- llvm_unreachable("unsupported CharByteWidth");
- }
-}
-
/// getLocationOfByte - Return a source location that points to the specified
/// byte of this string literal.
///
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index ef370260c5..15e89db209 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -595,22 +595,35 @@ void ASTStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
VisitExpr(E);
- unsigned Len = Record.readInt();
- assert(Record.peekInt() == E->getNumConcatenated() &&
- "Wrong number of concatenated tokens!");
- Record.skipInts(1);
- auto kind = static_cast<StringLiteral::StringKind>(Record.readInt());
- bool isPascal = Record.readInt();
- // Read string data
- auto B = &Record.peekInt();
- SmallString<16> Str(B, B + Len);
- E->setString(Record.getContext(), Str, kind, isPascal);
- Record.skipInts(Len);
-
- // Read source locations
- for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ // NumConcatenated, Length and CharByteWidth are set by the empty
+ // ctor since they are needed to allocate storage for the trailing objects.
+ unsigned NumConcatenated = Record.readInt();
+ unsigned Length = Record.readInt();
+ unsigned CharByteWidth = Record.readInt();
+ assert((NumConcatenated == E->getNumConcatenated()) &&
+ "Wrong number of concatenated tokens!");
+ assert((Length == E->getLength()) && "Wrong Length!");
+ assert((CharByteWidth == E->getCharByteWidth()) && "Wrong character width!");
+ E->StringLiteralBits.Kind = Record.readInt();
+ E->StringLiteralBits.IsPascal = Record.readInt();
+
+ // The character width is originally computed via mapCharByteWidth.
+ // Check that the deserialized character width is consistant with the result
+ // of calling mapCharByteWidth.
+ assert((CharByteWidth ==
+ StringLiteral::mapCharByteWidth(Record.getContext().getTargetInfo(),
+ E->getKind())) &&
+ "Wrong character width!");
+
+ // Deserialize the trailing array of SourceLocation.
+ for (unsigned I = 0; I < NumConcatenated; ++I)
E->setStrTokenLoc(I, ReadSourceLocation());
+
+ // Deserialize the trailing array of char holding the string data.
+ char *StrData = E->getStrDataAsChar();
+ for (unsigned I = 0; I < Length * CharByteWidth; ++I)
+ StrData[I] = Record.readInt();
}
void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
@@ -2423,8 +2436,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_STRING_LITERAL:
- S = StringLiteral::CreateEmpty(Context,
- Record[ASTStmtReader::NumExprFields + 1]);
+ S = StringLiteral::CreateEmpty(
+ Context,
+ /* NumConcatenated=*/Record[ASTStmtReader::NumExprFields + 0],
+ /* Length=*/Record[ASTStmtReader::NumExprFields + 1],
+ /* CharByteWidth=*/Record[ASTStmtReader::NumExprFields + 2]);
break;
case EXPR_CHARACTER_LITERAL:
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index f32705c2ef..9f861bef89 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -518,17 +518,23 @@ void ASTStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) {
void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) {
VisitExpr(E);
- Record.push_back(E->getByteLength());
+
+ // Store the various bits of data of StringLiteral.
Record.push_back(E->getNumConcatenated());
+ Record.push_back(E->getLength());
+ Record.push_back(E->getCharByteWidth());
Record.push_back(E->getKind());
Record.push_back(E->isPascal());
- // FIXME: String data should be stored as a blob at the end of the
- // StringLiteral. However, we can't do so now because we have no
- // provision for coping with abbreviations when we're jumping around
- // the AST file during deserialization.
- Record.append(E->getBytes().begin(), E->getBytes().end());
+
+ // Store the trailing array of SourceLocation.
for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
Record.AddSourceLocation(E->getStrTokenLoc(I));
+
+ // Store the trailing array of char holding the string data.
+ StringRef StrData = E->getBytes();
+ for (unsigned I = 0, N = E->getByteLength(); I != N; ++I)
+ Record.push_back(StrData[I]);
+
Code = serialization::EXPR_STRING_LITERAL;
}