123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "Pointer.h"
- #include "Function.h"
- #include "InterpBlock.h"
- #include "PrimType.h"
- using namespace clang;
- using namespace clang::interp;
- Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
- Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
- : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
- Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
- Pointer::Pointer(Pointer &&P)
- : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
- if (Pointee)
- Pointee->movePointer(&P, this);
- }
- Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
- : Pointee(Pointee), Base(Base), Offset(Offset) {
- assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
- if (Pointee)
- Pointee->addPointer(this);
- }
- Pointer::~Pointer() {
- if (Pointee) {
- Pointee->removePointer(this);
- Pointee->cleanup();
- }
- }
- void Pointer::operator=(const Pointer &P) {
- Block *Old = Pointee;
- if (Pointee)
- Pointee->removePointer(this);
- Offset = P.Offset;
- Base = P.Base;
- Pointee = P.Pointee;
- if (Pointee)
- Pointee->addPointer(this);
- if (Old)
- Old->cleanup();
- }
- void Pointer::operator=(Pointer &&P) {
- Block *Old = Pointee;
- if (Pointee)
- Pointee->removePointer(this);
- Offset = P.Offset;
- Base = P.Base;
- Pointee = P.Pointee;
- if (Pointee)
- Pointee->movePointer(&P, this);
- if (Old)
- Old->cleanup();
- }
- APValue Pointer::toAPValue() const {
- APValue::LValueBase Base;
- llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
- CharUnits Offset;
- bool IsNullPtr;
- bool IsOnePastEnd;
- if (isZero()) {
- Base = static_cast<const Expr *>(nullptr);
- IsNullPtr = true;
- IsOnePastEnd = false;
- Offset = CharUnits::Zero();
- } else {
- // Build the lvalue base from the block.
- Descriptor *Desc = getDeclDesc();
- if (auto *VD = Desc->asValueDecl())
- Base = VD;
- else if (auto *E = Desc->asExpr())
- Base = E;
- else
- llvm_unreachable("Invalid allocation type");
- // Not a null pointer.
- IsNullPtr = false;
- if (isUnknownSizeArray()) {
- IsOnePastEnd = false;
- Offset = CharUnits::Zero();
- } else {
- // TODO: compute the offset into the object.
- Offset = CharUnits::Zero();
- // Build the path into the object.
- Pointer Ptr = *this;
- while (Ptr.isField() || Ptr.isArrayElement()) {
- if (Ptr.isArrayElement()) {
- Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
- Ptr = Ptr.getArray();
- } else {
- // TODO: figure out if base is virtual
- bool IsVirtual = false;
- // Create a path entry for the field.
- Descriptor *Desc = Ptr.getFieldDesc();
- if (auto *BaseOrMember = Desc->asDecl()) {
- Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
- Ptr = Ptr.getBase();
- continue;
- }
- llvm_unreachable("Invalid field type");
- }
- }
- IsOnePastEnd = isOnePastEnd();
- }
- }
- // We assemble the LValuePath starting from the innermost pointer to the
- // outermost one. SO in a.b.c, the first element in Path will refer to
- // the field 'c', while later code expects it to refer to 'a'.
- // Just invert the order of the elements.
- std::reverse(Path.begin(), Path.end());
- return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
- }
- bool Pointer::isInitialized() const {
- assert(Pointee && "Cannot check if null pointer was initialized");
- Descriptor *Desc = getFieldDesc();
- assert(Desc);
- if (Desc->isPrimitiveArray()) {
- if (isStatic() && Base == 0)
- return true;
- // Primitive array field are stored in a bitset.
- InitMap *Map = getInitMap();
- if (!Map)
- return false;
- if (Map == (InitMap *)-1)
- return true;
- return Map->isInitialized(getIndex());
- } else {
- // Field has its bit in an inline descriptor.
- return Base == 0 || getInlineDesc()->IsInitialized;
- }
- }
- void Pointer::initialize() const {
- assert(Pointee && "Cannot initialize null pointer");
- Descriptor *Desc = getFieldDesc();
- assert(Desc);
- if (Desc->isArray()) {
- if (Desc->isPrimitiveArray()) {
- // Primitive global arrays don't have an initmap.
- if (isStatic() && Base == 0)
- return;
- // Primitive array initializer.
- InitMap *&Map = getInitMap();
- if (Map == (InitMap *)-1)
- return;
- if (Map == nullptr)
- Map = InitMap::allocate(Desc->getNumElems());
- if (Map->initialize(getIndex())) {
- free(Map);
- Map = (InitMap *)-1;
- }
- }
- } else {
- // Field has its bit in an inline descriptor.
- assert(Base != 0 && "Only composite fields can be initialised");
- getInlineDesc()->IsInitialized = true;
- }
- }
- void Pointer::activate() const {
- // Field has its bit in an inline descriptor.
- assert(Base != 0 && "Only composite fields can be initialised");
- getInlineDesc()->IsActive = true;
- }
- void Pointer::deactivate() const {
- // TODO: this only appears in constructors, so nothing to deactivate.
- }
- bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
- return A.Pointee == B.Pointee;
- }
- bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
- return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
- }
|