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