Pointer.cpp revision 356998
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 "Block.h"
11#include "Function.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(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
20
21Pointer::Pointer(Pointer &&P)
22    : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
23  if (Pointee)
24    Pointee->movePointer(&P, this);
25}
26
27Pointer::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
34Pointer::~Pointer() {
35  if (Pointee) {
36    Pointee->removePointer(this);
37    Pointee->cleanup();
38  }
39}
40
41void 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
58void 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
75APValue 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
135bool 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
154void 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
177void 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
183void Pointer::deactivate() const {
184  // TODO: this only appears in constructors, so nothing to deactivate.
185}
186
187bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
188  return A.Pointee == B.Pointee;
189}
190
191bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
192  return A.Base == B.Base && A.getFieldDesc()->IsArray;
193}
194