1 //===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This files defines TypeLocBuilder, a class for building TypeLocs
11 //  bottom-up.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "TypeLocBuilder.h"
16 
17 using namespace clang;
18 
pushFullCopy(TypeLoc L)19 void TypeLocBuilder::pushFullCopy(TypeLoc L) {
20   size_t Size = L.getFullDataSize();
21   reserve(Size);
22 
23   SmallVector<TypeLoc, 4> TypeLocs;
24   TypeLoc CurTL = L;
25   while (CurTL) {
26     TypeLocs.push_back(CurTL);
27     CurTL = CurTL.getNextTypeLoc();
28   }
29 
30   for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
31     TypeLoc CurTL = TypeLocs[e-i-1];
32     switch (CurTL.getTypeLocClass()) {
33 #define ABSTRACT_TYPELOC(CLASS, PARENT)
34 #define TYPELOC(CLASS, PARENT) \
35     case TypeLoc::CLASS: { \
36       CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
37       memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
38       break; \
39     }
40 #include "clang/AST/TypeLocNodes.def"
41     }
42   }
43 }
44 
grow(size_t NewCapacity)45 void TypeLocBuilder::grow(size_t NewCapacity) {
46   assert(NewCapacity > Capacity);
47 
48   // Allocate the new buffer and copy the old data into it.
49   char *NewBuffer = new char[NewCapacity];
50   unsigned NewIndex = Index + NewCapacity - Capacity;
51   memcpy(&NewBuffer[NewIndex],
52          &Buffer[Index],
53          Capacity - Index);
54 
55   if (Buffer != InlineBuffer.buffer)
56     delete[] Buffer;
57 
58   Buffer = NewBuffer;
59   Capacity = NewCapacity;
60   Index = NewIndex;
61 }
62 
pushImpl(QualType T,size_t LocalSize,unsigned LocalAlignment)63 TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
64 #ifndef NDEBUG
65   QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
66   assert(TLast == LastTy &&
67          "mismatch between last type and new type's inner type");
68   LastTy = T;
69 #endif
70 
71   assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
72 
73   // If we need to grow, grow by a factor of 2.
74   if (LocalSize > Index) {
75     size_t RequiredCapacity = Capacity + (LocalSize - Index);
76     size_t NewCapacity = Capacity * 2;
77     while (RequiredCapacity > NewCapacity)
78       NewCapacity *= 2;
79     grow(NewCapacity);
80   }
81 
82   // Because we're adding elements to the TypeLoc backwards, we have to
83   // do some extra work to keep everything aligned appropriately.
84   // FIXME: This algorithm is a absolute mess because every TypeLoc returned
85   // needs to be valid.  Partial TypeLocs are a terrible idea.
86   // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
87   // hardcode them.
88   if (LocalAlignment == 4) {
89     if (NumBytesAtAlign8 == 0) {
90       NumBytesAtAlign4 += LocalSize;
91     } else {
92       unsigned Padding = NumBytesAtAlign4 % 8;
93       if (Padding == 0) {
94         if (LocalSize % 8 == 0) {
95           // Everything is set: there's no padding and we don't need to add
96           // any.
97         } else {
98           assert(LocalSize % 8 == 4);
99           // No existing padding; add in 4 bytes padding
100           memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
101           Index -= 4;
102         }
103       } else {
104         assert(Padding == 4);
105         if (LocalSize % 8 == 0) {
106           // Everything is set: there's 4 bytes padding and we don't need
107           // to add any.
108         } else {
109           assert(LocalSize % 8 == 4);
110           // There are 4 bytes padding, but we don't need any; remove it.
111           memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
112           Index += 4;
113         }
114       }
115       NumBytesAtAlign4 += LocalSize;
116     }
117   } else if (LocalAlignment == 8) {
118     if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) {
119       // No existing padding and misaligned members; add in 4 bytes padding
120       memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
121       Index -= 4;
122     }
123     // Forget about any padding.
124     NumBytesAtAlign4 = 0;
125     NumBytesAtAlign8 += LocalSize;
126   } else {
127     assert(LocalSize == 0);
128   }
129 
130   Index -= LocalSize;
131 
132   assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
133          "incorrect data size provided to CreateTypeSourceInfo!");
134 
135   return getTemporaryTypeLoc(T);
136 }
137