diff options
Diffstat (limited to 'clang/lib/AST/Interp/Pointer.cpp')
| -rw-r--r-- | clang/lib/AST/Interp/Pointer.cpp | 193 | 
1 files changed, 193 insertions, 0 deletions
| diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp new file mode 100644 index 000000000000..1a10723aaca5 --- /dev/null +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -0,0 +1,193 @@ +//===--- 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 "Block.h" +#include "Function.h" +#include "PrimType.h" + +using namespace clang; +using namespace clang::interp; + +Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} + +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()) { +        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(); +    } +  } + +  return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); +} + +bool Pointer::isInitialized() const { +  assert(Pointee && "Cannot check if null pointer was initialized"); +  Descriptor *Desc = getFieldDesc(); +  if (Desc->isPrimitiveArray()) { +    if (Pointee->IsStatic) +      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(); +  if (Desc->isPrimitiveArray()) { +    if (!Pointee->IsStatic) { +      // 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 A.Base == B.Base && A.getFieldDesc()->IsArray; +} | 
