1 //===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This files defines TypeLocBuilder, a class for building TypeLocs
10 //  bottom-up.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "TypeLocBuilder.h"
15 
16 using namespace clang;
17 
pushFullCopy(TypeLoc L)18 void TypeLocBuilder::pushFullCopy(TypeLoc L) {
19   size_t Size = L.getFullDataSize();
20   reserve(Size);
21 
22   SmallVector<TypeLoc, 4> TypeLocs;
23   TypeLoc CurTL = L;
24   while (CurTL) {
25     TypeLocs.push_back(CurTL);
26     CurTL = CurTL.getNextTypeLoc();
27   }
28 
29   for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
30     TypeLoc CurTL = TypeLocs[e-i-1];
31     switch (CurTL.getTypeLocClass()) {
32 #define ABSTRACT_TYPELOC(CLASS, PARENT)
33 #define TYPELOC(CLASS, PARENT) \
34     case TypeLoc::CLASS: { \
35       CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
36       memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
37       break; \
38     }
39 #include "clang/AST/TypeLocNodes.def"
40     }
41   }
42 }
43 
pushTrivial(ASTContext & Context,QualType T,SourceLocation Loc)44 void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T,
45                                  SourceLocation Loc) {
46   auto L = TypeLoc(T, nullptr);
47   reserve(L.getFullDataSize());
48 
49   SmallVector<TypeLoc, 4> TypeLocs;
50   for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc())
51     TypeLocs.push_back(CurTL);
52 
53   for (const auto &CurTL : llvm::reverse(TypeLocs)) {
54     switch (CurTL.getTypeLocClass()) {
55 #define ABSTRACT_TYPELOC(CLASS, PARENT)
56 #define TYPELOC(CLASS, PARENT)                                                 \
57   case TypeLoc::CLASS: {                                                       \
58     auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType());                  \
59     NewTL.initializeLocal(Context, Loc);                                       \
60     break;                                                                     \
61   }
62 #include "clang/AST/TypeLocNodes.def"
63     }
64   }
65 }
66 
grow(size_t NewCapacity)67 void TypeLocBuilder::grow(size_t NewCapacity) {
68   assert(NewCapacity > Capacity);
69 
70   // Allocate the new buffer and copy the old data into it.
71   char *NewBuffer = new char[NewCapacity];
72   unsigned NewIndex = Index + NewCapacity - Capacity;
73   memcpy(&NewBuffer[NewIndex],
74          &Buffer[Index],
75          Capacity - Index);
76 
77   if (Buffer != InlineBuffer)
78     delete[] Buffer;
79 
80   Buffer = NewBuffer;
81   Capacity = NewCapacity;
82   Index = NewIndex;
83 }
84 
pushImpl(QualType T,size_t LocalSize,unsigned LocalAlignment)85 TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
86 #ifndef NDEBUG
87   QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
88   assert(TLast == LastTy &&
89          "mismatch between last type and new type's inner type");
90   LastTy = T;
91 #endif
92 
93   assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
94 
95   // If we need to grow, grow by a factor of 2.
96   if (LocalSize > Index) {
97     size_t RequiredCapacity = Capacity + (LocalSize - Index);
98     size_t NewCapacity = Capacity * 2;
99     while (RequiredCapacity > NewCapacity)
100       NewCapacity *= 2;
101     grow(NewCapacity);
102   }
103 
104   // Because we're adding elements to the TypeLoc backwards, we have to
105   // do some extra work to keep everything aligned appropriately.
106   // FIXME: This algorithm is a absolute mess because every TypeLoc returned
107   // needs to be valid.  Partial TypeLocs are a terrible idea.
108   // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
109   // hardcode them.
110   if (LocalAlignment == 4) {
111     if (!AtAlign8) {
112       NumBytesAtAlign4 += LocalSize;
113     } else {
114       unsigned Padding = NumBytesAtAlign4 % 8;
115       if (Padding == 0) {
116         if (LocalSize % 8 == 0) {
117           // Everything is set: there's no padding and we don't need to add
118           // any.
119         } else {
120           assert(LocalSize % 8 == 4);
121           // No existing padding; add in 4 bytes padding
122           memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
123           Index -= 4;
124         }
125       } else {
126         assert(Padding == 4);
127         if (LocalSize % 8 == 0) {
128           // Everything is set: there's 4 bytes padding and we don't need
129           // to add any.
130         } else {
131           assert(LocalSize % 8 == 4);
132           // There are 4 bytes padding, but we don't need any; remove it.
133           memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
134           Index += 4;
135         }
136       }
137       NumBytesAtAlign4 += LocalSize;
138     }
139   } else if (LocalAlignment == 8) {
140     if (!AtAlign8) {
141       // We have not seen any 8-byte aligned element yet. We insert a padding
142       // only if the new Index is not 8-byte-aligned.
143       if ((Index - LocalSize) % 8 != 0) {
144         memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
145         Index -= 4;
146       }
147     } else {
148       unsigned Padding = NumBytesAtAlign4 % 8;
149       if (Padding == 0) {
150         if (LocalSize % 8 == 0) {
151           // Everything is set: there's no padding and we don't need to add
152           // any.
153         } else {
154           assert(LocalSize % 8 == 4);
155           // No existing padding; add in 4 bytes padding
156           memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
157           Index -= 4;
158         }
159       } else {
160         assert(Padding == 4);
161         if (LocalSize % 8 == 0) {
162           // Everything is set: there's 4 bytes padding and we don't need
163           // to add any.
164         } else {
165           assert(LocalSize % 8 == 4);
166           // There are 4 bytes padding, but we don't need any; remove it.
167           memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
168           Index += 4;
169         }
170       }
171     }
172 
173     // Forget about any padding.
174     NumBytesAtAlign4 = 0;
175     AtAlign8 = true;
176   } else {
177     assert(LocalSize == 0);
178   }
179 
180   Index -= LocalSize;
181 
182   assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
183          "incorrect data size provided to CreateTypeSourceInfo!");
184 
185   return getTemporaryTypeLoc(T);
186 }
187