text: // Copyright 2018 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_OBJECTS_MAYBE_OBJECT_INL_H_
  #define V8_OBJECTS_MAYBE_OBJECT_INL_H_
  
  #include "src/objects/maybe-object.h"
  
  #ifdef V8_COMPRESS_POINTERS
  #include "src/isolate.h"
  #endif
  #include "src/objects-inl.h"
  #include "src/objects/slots-inl.h"
  
  namespace v8 {
  namespace internal {
  
  bool MaybeObject::ToSmi(Smi* value) {
    if (HAS_SMI_TAG(ptr_)) {
      *value = Smi::cast(ObjectPtr(ptr_));
      return true;
    }
    return false;
  }
  
  Smi MaybeObject::ToSmi() const {
    DCHECK(HAS_SMI_TAG(ptr_));
    return Smi::cast(ObjectPtr(ptr_));
  }
  
  bool MaybeObject::IsStrongOrWeak() const {
    if (IsSmi() || IsCleared()) {
      return false;
    }
    return true;
  }
  
  bool MaybeObject::GetHeapObject(HeapObject* result) const {
    if (IsSmi() || IsCleared()) {
      return false;
    }
    *result = GetHeapObject();
    return true;
  }
  
  bool MaybeObject::GetHeapObject(HeapObject* result,
                                  HeapObjectReferenceType* reference_type) const {
    if (IsSmi() || IsCleared()) {
      return false;
    }
    *reference_type = HasWeakHeapObjectTag(ptr_)
                          ? HeapObjectReferenceType::WEAK
                          : HeapObjectReferenceType::STRONG;
    *result = GetHeapObject();
    return true;
  }
  
  bool MaybeObject::IsStrong() const {
    return !HasWeakHeapObjectTag(ptr_) && !IsSmi();
  }
  
  bool MaybeObject::GetHeapObjectIfStrong(HeapObject* result) const {
    if (!HasWeakHeapObjectTag(ptr_) && !IsSmi()) {
      *result = HeapObject::cast(ObjectPtr(ptr_));
      return true;
    }
    return false;
  }
  
  HeapObject MaybeObject::GetHeapObjectAssumeStrong() const {
    DCHECK(IsStrong());
    return HeapObject::cast(ObjectPtr(ptr_));
  }
  
  bool MaybeObject::IsWeak() const {
    return HasWeakHeapObjectTag(ptr_) && !IsCleared();
  }
  
  bool MaybeObject::IsWeakOrCleared() const { return HasWeakHeapObjectTag(ptr_); }
  
  bool MaybeObject::GetHeapObjectIfWeak(HeapObject* result) const {
    if (IsWeak()) {
      *result = GetHeapObject();
      return true;
    }
    return false;
  }
  
  HeapObject MaybeObject::GetHeapObjectAssumeWeak() const {
    DCHECK(IsWeak());
    return GetHeapObject();
  }
  
  HeapObject MaybeObject::GetHeapObject() const {
    DCHECK(!IsSmi());
    DCHECK(!IsCleared());
    return HeapObject::cast(ObjectPtr(ptr_ & ~kWeakHeapObjectMask));
  }
  
  Object MaybeObject::GetHeapObjectOrSmi() const {
    if (IsSmi()) {
      return Object(ptr_);
    }
    return GetHeapObject();
  }
  
  bool MaybeObject::IsObject() const { return IsSmi() || IsStrong(); }
  
  MaybeObject MaybeObject::MakeWeak(MaybeObject object) {
    DCHECK(object.IsStrongOrWeak());
    return MaybeObject(object.ptr_ | kWeakHeapObjectMask);
  }
  
  // static
  HeapObjectReference HeapObjectReference::ClearedValue(Isolate* isolate) {
    // Construct cleared weak ref value.
    Address raw_value = kClearedWeakHeapObjectLower32;
  #ifdef V8_COMPRESS_POINTERS
    // This is necessary to make pointer decompression computation also
    // suitable for cleared weak references.
    Address isolate_root = isolate->isolate_root();
    raw_value |= isolate_root;
    DCHECK_EQ(raw_value & (~static_cast<Address>(kClearedWeakHeapObjectLower32)),
              isolate_root);
  #endif
    // The rest of the code will check only the lower 32-bits.
    DCHECK_EQ(kClearedWeakHeapObjectLower32, static_cast<uint32_t>(raw_value));
    return HeapObjectReference(raw_value);
  }
  
  template <typename THeapObjectSlot>
  void HeapObjectReference::Update(THeapObjectSlot slot, HeapObject value) {
    static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
                      std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
                  "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
    Address old_value = (*slot).ptr();
    DCHECK(!HAS_SMI_TAG(old_value));
    Address new_value = value->ptr();
    DCHECK(Internals::HasHeapObjectTag(new_value));
  
  #ifdef DEBUG
    bool weak_before = HasWeakHeapObjectTag(old_value);
  #endif
  
    slot.store(
        HeapObjectReference(new_value | (old_value & kWeakHeapObjectMask)));
  
  #ifdef DEBUG
    bool weak_after = HasWeakHeapObjectTag((*slot).ptr());
    DCHECK_EQ(weak_before, weak_after);
  #endif
  }
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_OBJECTS_MAYBE_OBJECT_INL_H_
  