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