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