xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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->replacePointer(&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->replacePointer(&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 if (Desc->asExpr()) {
107       // Pointer pointing to a an expression.
108       IsOnePastEnd = false;
109       Offset = CharUnits::Zero();
110     } else {
111       // TODO: compute the offset into the object.
112       Offset = CharUnits::Zero();
113 
114       // Build the path into the object.
115       Pointer Ptr = *this;
116       while (Ptr.isField() || Ptr.isArrayElement()) {
117         if (Ptr.isArrayElement()) {
118           Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
119           Ptr = Ptr.getArray();
120         } else {
121           // TODO: figure out if base is virtual
122           bool IsVirtual = false;
123 
124           // Create a path entry for the field.
125           Descriptor *Desc = Ptr.getFieldDesc();
126           if (auto *BaseOrMember = Desc->asDecl()) {
127             Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
128             Ptr = Ptr.getBase();
129             continue;
130           }
131           llvm_unreachable("Invalid field type");
132         }
133       }
134 
135       IsOnePastEnd = isOnePastEnd();
136     }
137   }
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   std::reverse(Path.begin(), Path.end());
144 
145   return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
146 }
147 
148 bool Pointer::isInitialized() const {
149   assert(Pointee && "Cannot check if null pointer was initialized");
150   const Descriptor *Desc = getFieldDesc();
151   assert(Desc);
152   if (Desc->isPrimitiveArray()) {
153     if (isStatic() && Base == 0)
154       return true;
155     // Primitive array field are stored in a bitset.
156     InitMap *Map = getInitMap();
157     if (!Map)
158       return false;
159     if (Map == (InitMap *)-1)
160       return true;
161     return Map->isInitialized(getIndex());
162   }
163 
164   // Field has its bit in an inline descriptor.
165   return Base == 0 || getInlineDesc()->IsInitialized;
166 }
167 
168 void Pointer::initialize() const {
169   assert(Pointee && "Cannot initialize null pointer");
170   const Descriptor *Desc = getFieldDesc();
171 
172   assert(Desc);
173   if (Desc->isPrimitiveArray()) {
174     // Primitive global arrays don't have an initmap.
175     if (isStatic() && Base == 0)
176       return;
177 
178     // Primitive array initializer.
179     InitMap *&Map = getInitMap();
180     if (Map == (InitMap *)-1)
181       return;
182     if (Map == nullptr)
183       Map = InitMap::allocate(Desc->getNumElems());
184     if (Map->initialize(getIndex())) {
185       free(Map);
186       Map = (InitMap *)-1;
187     }
188     return;
189   }
190 
191   // Field has its bit in an inline descriptor.
192   assert(Base != 0 && "Only composite fields can be initialised");
193   getInlineDesc()->IsInitialized = true;
194 }
195 
196 void Pointer::activate() const {
197   // Field has its bit in an inline descriptor.
198   assert(Base != 0 && "Only composite fields can be initialised");
199   getInlineDesc()->IsActive = true;
200 }
201 
202 void Pointer::deactivate() const {
203   // TODO: this only appears in constructors, so nothing to deactivate.
204 }
205 
206 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
207   return A.Pointee == B.Pointee;
208 }
209 
210 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
211   return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
212 }
213