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