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 
17 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
18 
19 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
20 
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 
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 
34 Pointer::~Pointer() {
35   if (Pointee) {
36     Pointee->removePointer(this);
37     Pointee->cleanup();
38   }
39 }
40 
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 
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 
75 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 
135 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 
154 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 
177 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 
183 void Pointer::deactivate() const {
184   // TODO: this only appears in constructors, so nothing to deactivate.
185 }
186 
187 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
188   return A.Pointee == B.Pointee;
189 }
190 
191 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
192   return A.Base == B.Base && A.getFieldDesc()->IsArray;
193 }
194