// Copyright 2024 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_CASTING_INL_H_
#define V8_OBJECTS_CASTING_INL_H_

#include "src/objects/casting.h"
// Include the non-inl header before the rest of the headers.

#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-layout.h"
#include "src/heap/heap.h"
#include "src/objects/heap-object.h"

namespace v8::internal {

#ifdef DEBUG
template <typename T>
bool GCAwareObjectTypeCheck(Tagged<Object> object, const Heap* heap) {
  Tagged<HeapObject> heap_object = UncheckedCast<HeapObject>(object);
  // `heap_object` must be of type `T`. One of 4 cases can apply:
  // 1) A scavenger is ongoing and `object` is a promoted large object.
  if ((heap->gc_state() == Heap::SCAVENGE) &&
      MemoryChunk::FromHeapObject(heap_object)->IsLargePage()) {
    return true;
  }
  // 2) A conservative scavenge is ongoing and `object` was pinned by
  // conservative stack scanning.
  MapWord map_word = heap_object->map_word(
      PtrComprCageBase(heap->isolate()->cage_base()), kRelaxedLoad);
  if ((heap->gc_state() == Heap::SCAVENGE) &&
      HeapLayout::InYoungGeneration(heap_object) &&
      ((heap->ConservativeStackScanningModeForMinorGC() !=
        Heap::StackScanMode::kNone) ||
       heap->ShouldUsePrecisePinningForMinorGC()) &&
      map_word.IsForwardingAddress() &&
      HeapLayout::IsSelfForwarded(heap_object, map_word)) {
    return true;
  }
  // 3) A GC is ongoing, `object` was evacuated, and the new instance is a
  // `T`.
  if (heap->IsInGC() && map_word.IsForwardingAddress() &&
      Is<T>(map_word.ToForwardingAddress(heap_object))) {
    return true;
  }
  // 4) If none of the above special cases apply, `heap_object` must be a `T`.
  return Is<T>(object);
}
#endif  // DEBUG

}  // namespace v8::internal

#endif  // V8_OBJECTS_CASTING_INL_H_