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
Pointer(Block * Pointee)17 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
18
Pointer(Block * Pointee,unsigned BaseAndOffset)19 Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
20 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
21
Pointer(const Pointer & P)22 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
23
Pointer(Pointer && P)24 Pointer::Pointer(Pointer &&P)
25 : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
26 if (Pointee)
27 Pointee->movePointer(&P, this);
28 }
29
Pointer(Block * Pointee,unsigned Base,unsigned Offset)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
~Pointer()37 Pointer::~Pointer() {
38 if (Pointee) {
39 Pointee->removePointer(this);
40 Pointee->cleanup();
41 }
42 }
43
operator =(const Pointer & P)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
operator =(Pointer && P)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->movePointer(&P, this);
73
74 if (Old)
75 Old->cleanup();
76 }
77
toAPValue() const78 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 {
107 // TODO: compute the offset into the object.
108 Offset = CharUnits::Zero();
109
110 // Build the path into the object.
111 Pointer Ptr = *this;
112 while (Ptr.isField() || Ptr.isArrayElement()) {
113 if (Ptr.isArrayElement()) {
114 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
115 Ptr = Ptr.getArray();
116 } else {
117 // TODO: figure out if base is virtual
118 bool IsVirtual = false;
119
120 // Create a path entry for the field.
121 Descriptor *Desc = Ptr.getFieldDesc();
122 if (auto *BaseOrMember = Desc->asDecl()) {
123 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
124 Ptr = Ptr.getBase();
125 continue;
126 }
127 llvm_unreachable("Invalid field type");
128 }
129 }
130
131 IsOnePastEnd = isOnePastEnd();
132 }
133 }
134
135 // We assemble the LValuePath starting from the innermost pointer to the
136 // outermost one. SO in a.b.c, the first element in Path will refer to
137 // the field 'c', while later code expects it to refer to 'a'.
138 // Just invert the order of the elements.
139 std::reverse(Path.begin(), Path.end());
140
141 return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
142 }
143
isInitialized() const144 bool Pointer::isInitialized() const {
145 assert(Pointee && "Cannot check if null pointer was initialized");
146 Descriptor *Desc = getFieldDesc();
147 assert(Desc);
148 if (Desc->isPrimitiveArray()) {
149 if (isStatic() && Base == 0)
150 return true;
151 // Primitive array field are stored in a bitset.
152 InitMap *Map = getInitMap();
153 if (!Map)
154 return false;
155 if (Map == (InitMap *)-1)
156 return true;
157 return Map->isInitialized(getIndex());
158 } else {
159 // Field has its bit in an inline descriptor.
160 return Base == 0 || getInlineDesc()->IsInitialized;
161 }
162 }
163
initialize() const164 void Pointer::initialize() const {
165 assert(Pointee && "Cannot initialize null pointer");
166 Descriptor *Desc = getFieldDesc();
167
168 assert(Desc);
169 if (Desc->isArray()) {
170 if (Desc->isPrimitiveArray()) {
171 // Primitive global arrays don't have an initmap.
172 if (isStatic() && Base == 0)
173 return;
174
175 // Primitive array initializer.
176 InitMap *&Map = getInitMap();
177 if (Map == (InitMap *)-1)
178 return;
179 if (Map == nullptr)
180 Map = InitMap::allocate(Desc->getNumElems());
181 if (Map->initialize(getIndex())) {
182 free(Map);
183 Map = (InitMap *)-1;
184 }
185 }
186 } else {
187 // Field has its bit in an inline descriptor.
188 assert(Base != 0 && "Only composite fields can be initialised");
189 getInlineDesc()->IsInitialized = true;
190 }
191 }
192
activate() const193 void Pointer::activate() const {
194 // Field has its bit in an inline descriptor.
195 assert(Base != 0 && "Only composite fields can be initialised");
196 getInlineDesc()->IsActive = true;
197 }
198
deactivate() const199 void Pointer::deactivate() const {
200 // TODO: this only appears in constructors, so nothing to deactivate.
201 }
202
hasSameBase(const Pointer & A,const Pointer & B)203 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
204 return A.Pointee == B.Pointee;
205 }
206
hasSameArray(const Pointer & A,const Pointer & B)207 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
208 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
209 }
210