/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/Pointer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===// |
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 | | #include "Pointer.h" |
10 | | #include "Function.h" |
11 | | #include "InterpBlock.h" |
12 | | #include "PrimType.h" |
13 | | |
14 | | using namespace clang; |
15 | | using namespace clang::interp; |
16 | | |
17 | 1.42k | Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Block*) clang::interp::Pointer::Pointer(clang::interp::Block*) Line | Count | Source | 17 | 1.42k | Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} |
|
18 | | |
19 | | Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) |
20 | 5.14k | : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Block*, unsigned int) clang::interp::Pointer::Pointer(clang::interp::Block*, unsigned int) Line | Count | Source | 20 | 5.14k | : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} |
|
21 | | |
22 | 3.40k | Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Pointer const&) clang::interp::Pointer::Pointer(clang::interp::Pointer const&) Line | Count | Source | 22 | 3.40k | Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} |
|
23 | | |
24 | | Pointer::Pointer(Pointer &&P) |
25 | 12.5k | : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { |
26 | 12.5k | if (Pointee) |
27 | 12.4k | Pointee->movePointer(&P, this); |
28 | 12.5k | } |
29 | | |
30 | | Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) |
31 | 14.2k | : Pointee(Pointee), Base(Base), Offset(Offset) { |
32 | 14.2k | assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); |
33 | 14.2k | if (Pointee) |
34 | 14.1k | Pointee->addPointer(this); |
35 | 14.2k | } |
36 | | |
37 | 39.6k | Pointer::~Pointer() { |
38 | 39.6k | if (Pointee) { |
39 | 27.1k | Pointee->removePointer(this); |
40 | 27.1k | Pointee->cleanup(); |
41 | 27.1k | } |
42 | 39.6k | } |
43 | | |
44 | 1.00k | void Pointer::operator=(const Pointer &P) { |
45 | 1.00k | Block *Old = Pointee; |
46 | | |
47 | 1.00k | if (Pointee) |
48 | 262 | Pointee->removePointer(this); |
49 | | |
50 | 1.00k | Offset = P.Offset; |
51 | 1.00k | Base = P.Base; |
52 | | |
53 | 1.00k | Pointee = P.Pointee; |
54 | 1.00k | if (Pointee) |
55 | 995 | Pointee->addPointer(this); |
56 | | |
57 | 1.00k | if (Old) |
58 | 262 | Old->cleanup(); |
59 | 1.00k | } |
60 | | |
61 | 283 | void Pointer::operator=(Pointer &&P) { |
62 | 283 | Block *Old = Pointee; |
63 | | |
64 | 283 | if (Pointee) |
65 | 201 | Pointee->removePointer(this); |
66 | | |
67 | 283 | Offset = P.Offset; |
68 | 283 | Base = P.Base; |
69 | | |
70 | 283 | Pointee = P.Pointee; |
71 | 283 | if (Pointee) |
72 | 272 | Pointee->movePointer(&P, this); |
73 | | |
74 | 283 | if (Old) |
75 | 201 | Old->cleanup(); |
76 | 283 | } |
77 | | |
78 | 197 | APValue Pointer::toAPValue() const { |
79 | 197 | APValue::LValueBase Base; |
80 | 197 | llvm::SmallVector<APValue::LValuePathEntry, 5> Path; |
81 | 197 | CharUnits Offset; |
82 | 197 | bool IsNullPtr; |
83 | 197 | bool IsOnePastEnd; |
84 | | |
85 | 197 | if (isZero()) { |
86 | 28 | Base = static_cast<const Expr *>(nullptr); |
87 | 28 | IsNullPtr = true; |
88 | 28 | IsOnePastEnd = false; |
89 | 28 | Offset = CharUnits::Zero(); |
90 | 169 | } else { |
91 | | // Build the lvalue base from the block. |
92 | 169 | Descriptor *Desc = getDeclDesc(); |
93 | 169 | if (auto *VD = Desc->asValueDecl()) |
94 | 129 | Base = VD; |
95 | 40 | else if (auto *E = Desc->asExpr()) |
96 | 40 | Base = E; |
97 | 0 | else |
98 | 0 | llvm_unreachable("Invalid allocation type"); |
99 | | |
100 | | // Not a null pointer. |
101 | 169 | IsNullPtr = false; |
102 | | |
103 | 169 | if (isUnknownSizeArray()) { |
104 | 5 | IsOnePastEnd = false; |
105 | 5 | Offset = CharUnits::Zero(); |
106 | 164 | } else if (Desc->asExpr()) { |
107 | | // Pointer pointing to a an expression. |
108 | 40 | IsOnePastEnd = false; |
109 | 40 | Offset = CharUnits::Zero(); |
110 | 124 | } else { |
111 | | // TODO: compute the offset into the object. |
112 | 124 | Offset = CharUnits::Zero(); |
113 | | |
114 | | // Build the path into the object. |
115 | 124 | Pointer Ptr = *this; |
116 | 232 | while (Ptr.isField() || Ptr.isArrayElement()170 ) { |
117 | 108 | if (Ptr.isArrayElement()) { |
118 | 46 | Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); |
119 | 46 | Ptr = Ptr.getArray(); |
120 | 62 | } else { |
121 | | // TODO: figure out if base is virtual |
122 | 62 | bool IsVirtual = false; |
123 | | |
124 | | // Create a path entry for the field. |
125 | 62 | Descriptor *Desc = Ptr.getFieldDesc(); |
126 | 62 | if (auto *BaseOrMember = Desc->asDecl()) { |
127 | 62 | Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); |
128 | 62 | Ptr = Ptr.getBase(); |
129 | 62 | continue; |
130 | 62 | } |
131 | 0 | llvm_unreachable("Invalid field type"); |
132 | 0 | } |
133 | 108 | } |
134 | | |
135 | 124 | IsOnePastEnd = isOnePastEnd(); |
136 | 124 | } |
137 | 169 | } |
138 | | |
139 | | // We assemble the LValuePath starting from the innermost pointer to the |
140 | | // outermost one. SO in a.b.c, the first element in Path will refer to |
141 | | // the field 'c', while later code expects it to refer to 'a'. |
142 | | // Just invert the order of the elements. |
143 | 197 | std::reverse(Path.begin(), Path.end()); |
144 | | |
145 | 197 | return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); |
146 | 197 | } |
147 | | |
148 | 4.50k | bool Pointer::isInitialized() const { |
149 | 4.50k | assert(Pointee && "Cannot check if null pointer was initialized"); |
150 | 4.50k | const Descriptor *Desc = getFieldDesc(); |
151 | 4.50k | assert(Desc); |
152 | 4.50k | if (Desc->isPrimitiveArray()) { |
153 | 574 | if (isStatic() && Base == 0347 ) |
154 | 213 | return true; |
155 | | // Primitive array field are stored in a bitset. |
156 | 361 | InitMap *Map = getInitMap(); |
157 | 361 | if (!Map) |
158 | 4 | return false; |
159 | 357 | if (Map == (InitMap *)-1) |
160 | 357 | return true; |
161 | 0 | return Map->isInitialized(getIndex()); |
162 | 3.92k | } else { |
163 | | // Field has its bit in an inline descriptor. |
164 | 3.92k | return Base == 0 || getInlineDesc()->IsInitialized3.70k ; |
165 | 3.92k | } |
166 | 4.50k | } |
167 | | |
168 | 2.13k | void Pointer::initialize() const { |
169 | 2.13k | assert(Pointee && "Cannot initialize null pointer"); |
170 | 2.13k | const Descriptor *Desc = getFieldDesc(); |
171 | | |
172 | 2.13k | assert(Desc); |
173 | 2.13k | if (Desc->isPrimitiveArray()) { |
174 | | // Primitive global arrays don't have an initmap. |
175 | 510 | if (isStatic() && Base == 0177 ) |
176 | 112 | return; |
177 | | |
178 | | // Primitive array initializer. |
179 | 398 | InitMap *&Map = getInitMap(); |
180 | 398 | if (Map == (InitMap *)-1) |
181 | 50 | return; |
182 | 348 | if (Map == nullptr) |
183 | 97 | Map = InitMap::allocate(Desc->getNumElems()); |
184 | 348 | if (Map->initialize(getIndex())) { |
185 | 96 | free(Map); |
186 | 96 | Map = (InitMap *)-1; |
187 | 96 | } |
188 | 1.62k | } else { |
189 | | // Field has its bit in an inline descriptor. |
190 | 1.62k | assert(Base != 0 && "Only composite fields can be initialised"); |
191 | 1.62k | getInlineDesc()->IsInitialized = true; |
192 | 1.62k | } |
193 | 2.13k | } |
194 | | |
195 | 213 | void Pointer::activate() const { |
196 | | // Field has its bit in an inline descriptor. |
197 | 213 | assert(Base != 0 && "Only composite fields can be initialised"); |
198 | 213 | getInlineDesc()->IsActive = true; |
199 | 213 | } |
200 | | |
201 | 0 | void Pointer::deactivate() const { |
202 | | // TODO: this only appears in constructors, so nothing to deactivate. |
203 | 0 | } |
204 | | |
205 | 206 | bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { |
206 | 206 | return A.Pointee == B.Pointee; |
207 | 206 | } |
208 | | |
209 | 7 | bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { |
210 | 7 | return hasSameBase(A, B) && A.Base == B.Base4 && A.getFieldDesc()->IsArray4 ; |
211 | 7 | } |