clang 17.0.0git
Pointer.cpp
Go to the documentation of this file.
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
14using namespace clang;
15using namespace clang::interp;
16
17Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
18
19Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
20 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
21
22Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
23
25 : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
26 if (Pointee)
27 Pointee->movePointer(&P, this);
28}
29
30Pointer::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
38 if (Pointee) {
39 Pointee->removePointer(this);
40 Pointee->cleanup();
41 }
42}
43
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
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
82 bool IsNullPtr;
83 bool IsOnePastEnd;
84
85 if (isZero()) {
86 Base = static_cast<const Expr *>(nullptr);
87 IsNullPtr = true;
88 IsOnePastEnd = false;
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;
106 } else if (Desc->asExpr()) {
107 // Pointer pointing to a an expression.
108 IsOnePastEnd = false;
110 } else {
111 // TODO: compute the offset into the object.
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
149 assert(Pointee && "Cannot check if null pointer was initialized");
150 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 } else {
163 // Field has its bit in an inline descriptor.
164 return Base == 0 || getInlineDesc()->IsInitialized;
165 }
166}
167
169 assert(Pointee && "Cannot initialize null pointer");
170 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 } else {
189 // Field has its bit in an inline descriptor.
190 assert(Base != 0 && "Only composite fields can be initialised");
191 getInlineDesc()->IsInitialized = true;
192 }
193}
194
195void Pointer::activate() const {
196 // Field has its bit in an inline descriptor.
197 assert(Base != 0 && "Only composite fields can be initialised");
198 getInlineDesc()->IsActive = true;
199}
200
202 // TODO: this only appears in constructors, so nothing to deactivate.
203}
204
205bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
206 return A.Pointee == B.Pointee;
207}
208
209bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
210 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
211}
StringRef P
unsigned Offset
Definition: Format.cpp:2778
A non-discriminated union of a base, field, or array index.
Definition: APValue.h:208
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition: APValue.h:216
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
This represents one expression.
Definition: Expr.h:110
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
void movePointer(Pointer *From, Pointer *To)
Definition: InterpBlock.cpp:47
void addPointer(Pointer *P)
Definition: InterpBlock.cpp:21
void removePointer(Pointer *P)
Definition: InterpBlock.cpp:31
A pointer to a memory block, live or dead.
Definition: Pointer.h:61
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:205
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:201
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:148
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:260
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:296
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:184
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:237
void activate() const
Activats a field.
Definition: Pointer.cpp:195
void operator=(const Pointer &P)
Definition: Pointer.cpp:44
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:241
Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:194
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:174
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:163
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:170
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:305
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:209
APValue toAPValue() const
Converts the pointer to an APValue.
Definition: Pointer.cpp:78
void initialize() const
Initializes a field.
Definition: Pointer.cpp:168
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:167
Describes a memory block created by an allocation site.
Definition: Descriptor.h:76
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:171
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:145
const Decl * asDecl() const
Definition: Descriptor.h:142
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:110
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:176
const Expr * asExpr() const
Definition: Descriptor.h:143
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition: Descriptor.h:193
static InitMap * allocate(unsigned N)
Allocates a map holding N elements.
Definition: Descriptor.cpp:314
bool isInitialized(unsigned I) const
Checks if an element was initialized.
Definition: Descriptor.cpp:309
bool initialize(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition: Descriptor.cpp:299
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:68
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:64