forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			194 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===--- 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(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;
 | |
| }
 |