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