// Copyright 2020 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.

#include "tools/v8windbg/src/object-inspection.h"

#include "src/flags/flags.h"
#include "tools/v8windbg/base/utilities.h"
#include "tools/v8windbg/src/v8-debug-helper-interop.h"
#include "tools/v8windbg/src/v8windbg-extension.h"

V8CachedObject::V8CachedObject(Location location,
                               std::string uncompressed_type_name,
                               WRL::ComPtr<IDebugHostContext> context,
                               bool is_compressed)
    : location_(std::move(location)),
      uncompressed_type_name_(std::move(uncompressed_type_name)),
      context_(std::move(context)),
      is_compressed_(is_compressed) {}
HRESULT V8CachedObject::Create(IModelObject* p_v8_object_instance,
                               IV8CachedObject** result) {
  Location location;
  RETURN_IF_FAIL(p_v8_object_instance->GetLocation(&location));

  WRL::ComPtr<IDebugHostContext> context;
  RETURN_IF_FAIL(p_v8_object_instance->GetContext(&context));

  // If the object is of type v8::internal::TaggedValue, and this build uses
  // compressed pointers, then the value is compressed. Other types such as
  // v8::internal::Object represent uncompressed tagged values.
  WRL::ComPtr<IDebugHostType> sp_type;
  _bstr_t type_name;
  bool is_compressed =
      COMPRESS_POINTERS_BOOL &&
      SUCCEEDED(p_v8_object_instance->GetTypeInfo(&sp_type)) &&
      SUCCEEDED(sp_type->GetName(type_name.GetAddress())) &&
      static_cast<const char*>(type_name) == std::string(kTaggedValue);

  const char* uncompressed_type_name =
      is_compressed ? kObject : static_cast<const char*>(type_name);

  *result = WRL::Make<V8CachedObject>(location, uncompressed_type_name, context,
                                      is_compressed)
                .Detach();
  return S_OK;
}
V8CachedObject::V8CachedObject(V8HeapObject heap_object)
    : heap_object_(std::move(heap_object)), heap_object_initialized_(true) {}

V8CachedObject::~V8CachedObject() = default;

IFACEMETHODIMP V8CachedObject::GetCachedV8HeapObject(
    V8HeapObject** pp_heap_object) noexcept {
  if (!heap_object_initialized_) {
    heap_object_initialized_ = true;
    uint64_t tagged_ptr = 0;
    uint64_t bytes_read;
    HRESULT hr = sp_debug_host_memory->ReadBytes(
        context_.Get(), location_, reinterpret_cast<void*>(&tagged_ptr),
        is_compressed_ ? i::kTaggedSize : sizeof(void*), &bytes_read);
    // S_FALSE can be returned if fewer bytes were read than were requested. We
    // need all of the bytes, so check for S_OK.
    if (hr != S_OK) {
      std::stringstream message;
      message << "Unable to read memory";
      if (location_.IsVirtualAddress()) {
        message << " at 0x" << std::hex << location_.GetOffset();
      }
      heap_object_.friendly_name = ConvertToU16String(message.str());
    } else {
      if (is_compressed_)
        tagged_ptr = ExpandCompressedPointer(static_cast<uint32_t>(tagged_ptr));
      heap_object_ =
          ::GetHeapObject(context_, tagged_ptr, location_.GetOffset(),
                          uncompressed_type_name_.c_str(), is_compressed_);
    }
  }
  *pp_heap_object = &this->heap_object_;
  return S_OK;
}

IndexedFieldData::IndexedFieldData(Property property)
    : property_(std::move(property)) {}

IndexedFieldData::~IndexedFieldData() = default;

IFACEMETHODIMP IndexedFieldData::GetProperty(Property** property) noexcept {
  if (!property) return E_POINTER;
  *property = &this->property_;
  return S_OK;
}

V8ObjectKeyEnumerator::V8ObjectKeyEnumerator(
    WRL::ComPtr<IV8CachedObject>& v8_cached_object)
    : sp_v8_cached_object_{v8_cached_object} {}
V8ObjectKeyEnumerator::~V8ObjectKeyEnumerator() = default;

IFACEMETHODIMP V8ObjectKeyEnumerator::Reset() noexcept {
  index_ = 0;
  return S_OK;
}

IFACEMETHODIMP V8ObjectKeyEnumerator::GetNext(BSTR* key, IModelObject** value,
                                              IKeyStore** metadata) noexcept {
  V8HeapObject* p_v8_heap_object;
  sp_v8_cached_object_->GetCachedV8HeapObject(&p_v8_heap_object);

  if (static_cast<size_t>(index_) >= p_v8_heap_object->properties.size())
    return E_BOUNDS;

  auto* name_ptr = p_v8_heap_object->properties[index_].name.c_str();
  *key = ::SysAllocString(U16ToWChar(name_ptr));
  ++index_;
  return S_OK;
}

IFACEMETHODIMP V8LocalDataModel::InitializeObject(
    IModelObject* model_object,
    IDebugHostTypeSignature* matching_type_signature,
    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
  return S_OK;
}

IFACEMETHODIMP V8LocalDataModel::GetName(BSTR* model_name) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP V8ObjectDataModel::InitializeObject(
    IModelObject* model_object,
    IDebugHostTypeSignature* matching_type_signature,
    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
  return S_OK;
}

IFACEMETHODIMP V8ObjectDataModel::GetName(BSTR* model_name) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP V8ObjectDataModel::ToDisplayString(
    IModelObject* context_object, IKeyStore* metadata,
    BSTR* display_string) noexcept {
  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));
  V8HeapObject* p_v8_heap_object;
  RETURN_IF_FAIL(sp_v8_cached_object->GetCachedV8HeapObject(&p_v8_heap_object));
  *display_string = ::SysAllocString(
      reinterpret_cast<const wchar_t*>(p_v8_heap_object->friendly_name.data()));
  return S_OK;
}

namespace {

// Creates a synthetic object, attaches a parent model, and sets the context
// object for that parent data model. Caller is responsible for ensuring that
// the parent model's Concepts have been initialized correctly and that the
// data model context is of an appropriate type for the parent model.
HRESULT CreateSyntheticObjectWithParentAndDataContext(
    IDebugHostContext* ctx, IModelObject* parent_model, IUnknown* data_context,
    IModelObject** result) {
  WRL::ComPtr<IModelObject> value;
  RETURN_IF_FAIL(sp_data_model_manager->CreateSyntheticObject(ctx, &value));
  RETURN_IF_FAIL(
      value->AddParentModel(parent_model, nullptr, true /*override*/));
  RETURN_IF_FAIL(value->SetContextForDataModel(parent_model, data_context));
  *result = value.Detach();
  return S_OK;
}

// Creates an IModelObject for a V8 object whose value is represented by the
// data in cached_object. This is an alternative to  CreateTypedObject for
// particularly complex cases (compressed values and those that don't exist
// anywhere in memory).
HRESULT CreateSyntheticObjectForV8Object(IDebugHostContext* ctx,
                                         V8CachedObject* cached_object,
                                         IModelObject** result) {
  // Explicitly add the parent model and data context. On a plain typed object,
  // the parent model would be attached automatically because we registered for
  // a matching type signature, and the data context would be set during
  // V8ObjectDataModel::GetCachedObject.
  return CreateSyntheticObjectWithParentAndDataContext(
      ctx, Extension::Current()->GetObjectDataModel(), cached_object, result);
}

// Creates an IModelObject to represent a field that is not a struct or array.
HRESULT GetModelForBasicField(const uint64_t address,
                              const std::u16string& type_name,
                              const std::string& uncompressed_type_name,
                              WRL::ComPtr<IDebugHostContext>& sp_ctx,
                              IModelObject** result) {
  if (type_name == ConvertToU16String(uncompressed_type_name)) {
    // For untagged and uncompressed tagged fields, create an IModelObject
    // representing a normal native data type.
    WRL::ComPtr<IDebugHostType> type =
        Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
    if (type == nullptr) return E_FAIL;
    return sp_data_model_manager->CreateTypedObject(
        sp_ctx.Get(), Location{address}, type.Get(), result);
  }

  // For compressed tagged fields, we need to do something a little more
  // complicated. We could just use CreateTypedObject with the type
  // v8::internal::TaggedValue, but then we'd sacrifice any other data
  // that we've learned about the field's specific type. So instead we
  // create a synthetic object.
  WRL::ComPtr<V8CachedObject> cached_object = WRL::Make<V8CachedObject>(
      Location(address), uncompressed_type_name, sp_ctx,
      /*is_compressed=*/true);
  return CreateSyntheticObjectForV8Object(sp_ctx.Get(), cached_object.Get(),
                                          result);
}

// Creates an IModelObject representing the value of a bitfield.
HRESULT GetModelForBitField(uint64_t address, const uint8_t num_bits,
                            uint8_t shift_bits, const std::u16string& type_name,
                            WRL::ComPtr<IDebugHostContext>& sp_ctx,
                            IModelObject** result) {
  // Look up the type by name.
  WRL::ComPtr<IDebugHostType> type =
      Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
  if (type == nullptr) return E_FAIL;

  // Figure out exactly which bytes contain the bitfield's data. This depends on
  // platform byte order (little-endian for Windows).
  constexpr int kBitsPerByte = 8;
  uint8_t shift_bytes = shift_bits / kBitsPerByte;
  address += shift_bytes;
  shift_bits -= shift_bytes * kBitsPerByte;
  size_t bits_to_read = shift_bits + num_bits;
  size_t bytes_to_read = (bits_to_read + kBitsPerByte - 1) / kBitsPerByte;

  uintptr_t value = 0;

  // V8 guarantees that bitfield structs are no bigger than a single pointer.
  if (bytes_to_read > sizeof(value)) {
    std::stringstream message;
    message << "Fatal v8windbg error: found bitfield struct of "
            << bytes_to_read << "bytes, which exceeds the supported size of "
            << sizeof(value);
    return CreateString(ConvertToU16String(message.str()), result);
  }

  uint64_t bytes_read;
  HRESULT hr = sp_debug_host_memory->ReadBytes(sp_ctx.Get(), address,
                                               reinterpret_cast<void*>(&value),
                                               bytes_to_read, &bytes_read);

  // S_FALSE can be returned if fewer bytes were read than were requested. We
  // need all of the bytes, so check for S_OK.
  if (hr != S_OK) {
    std::stringstream message;
    message << "Unable to read memory at 0x" << std::hex << address;
    return CreateString(ConvertToU16String(message.str()), result);
  }

  // Decode the bitfield.
  value = (value >> shift_bits) & ((1 << num_bits) - 1);

  return CreateTypedIntrinsic(value, type.Get(), result);
}

// Creates an IModelObject to represent the packed fields in a Torque struct.
// Note that Torque structs are not C++ structs and do not have any type
// definitions in the V8 symbols.
HRESULT GetModelForStruct(const uint64_t address,
                          const std::vector<StructField>& fields,
                          WRL::ComPtr<IDebugHostContext>& sp_ctx,
                          IModelObject** result) {
  WRL::ComPtr<IModelObject> sp_value;
  RETURN_IF_FAIL(
      sp_data_model_manager->CreateSyntheticObject(sp_ctx.Get(), &sp_value));

  // There's no need for any fancy Concepts here; just add key-value pairs for
  // each field.
  for (const StructField& field : fields) {
    WRL::ComPtr<IModelObject> field_model;
    if (field.num_bits == 0) {
      RETURN_IF_FAIL(GetModelForBasicField(
          address + field.offset, field.type_name, field.uncompressed_type_name,
          sp_ctx, &field_model));
    } else {
      RETURN_IF_FAIL(GetModelForBitField(address + field.offset, field.num_bits,
                                         field.shift_bits, field.type_name,
                                         sp_ctx, &field_model));
    }
    RETURN_IF_FAIL(
        sp_value->SetKey(reinterpret_cast<const wchar_t*>(field.name.c_str()),
                         field_model.Get(), nullptr));
  }

  *result = sp_value.Detach();
  return S_OK;
}

// Creates an IModelObject representing an array of some type that we expect to
// be defined in the V8 symbols.
HRESULT GetModelForNativeArray(const uint64_t address,
                               const std::u16string& type_name, size_t count,
                               WRL::ComPtr<IDebugHostContext>& sp_ctx,
                               IModelObject** result) {
  WRL::ComPtr<IDebugHostType> type =
      Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
  if (type == nullptr) return E_FAIL;

  ULONG64 object_size{};
  RETURN_IF_FAIL(type->GetSize(&object_size));

  ArrayDimension dimensions[] = {
      {/*start=*/0, /*length=*/count, /*stride=*/object_size}};
  WRL::ComPtr<IDebugHostType> array_type;
  RETURN_IF_FAIL(
      type->CreateArrayOf(/*dimensions=*/1, dimensions, &array_type));

  return sp_data_model_manager->CreateTypedObject(
      sp_ctx.Get(), Location{address}, array_type.Get(), result);
}

// Creates an IModelObject that represents an array of structs or compressed
// tagged values.
HRESULT GetModelForCustomArray(const Property& prop,
                               WRL::ComPtr<IDebugHostContext>& sp_ctx,
                               IModelObject** result) {
  // Create the context which should be provided to the indexing and iterating
  // functionality provided by the parent model. This is instance-specific data,
  // whereas the parent model object could be shared among many custom arrays.
  WRL::ComPtr<IndexedFieldData> context_data =
      WRL::Make<IndexedFieldData>(prop);

  return CreateSyntheticObjectWithParentAndDataContext(
      sp_ctx.Get(), Extension::Current()->GetIndexedFieldDataModel(),
      context_data.Get(), result);
}


// Creates an IModelObject representing the data in an array at the given index.
// context_object is expected to be an object of the form created by
// GetModelForCustomArray, meaning its context for the IndexedFieldParent data
// model is an IIndexedFieldData containing the description of the array.
HRESULT GetModelForCustomArrayElement(IModelObject* context_object,
                                      size_t index, IModelObject** object) {
  // Open a few layers of wrapper objects to get to the Property object that
  // describes the array.
  WRL::ComPtr<IUnknown> data_model_context;
  RETURN_IF_FAIL(context_object->GetContextForDataModel(
      Extension::Current()->GetIndexedFieldDataModel(), &data_model_context));
  WRL::ComPtr<IIndexedFieldData> indexed_field_data;
  RETURN_IF_FAIL(data_model_context.As(&indexed_field_data));
  Property* prop;
  RETURN_IF_FAIL(indexed_field_data->GetProperty(&prop));

  if (index >= prop->length) {
    return E_BOUNDS;
  }

  WRL::ComPtr<IDebugHostContext> sp_ctx;
  RETURN_IF_FAIL(context_object->GetContext(&sp_ctx));

  ULONG64 address = prop->addr_value + index * prop->item_size;

  switch (prop->type) {
    case PropertyType::kArray:
      return GetModelForBasicField(address, prop->type_name,
                                   prop->uncompressed_type_name, sp_ctx,
                                   object);
    case PropertyType::kStructArray:
      return GetModelForStruct(address, prop->fields, sp_ctx, object);
    default:
      return E_FAIL;  // Only array properties should be possible here.
  }
}

}  // namespace

IFACEMETHODIMP IndexedFieldParent::InitializeObject(
    IModelObject* model_object,
    IDebugHostTypeSignature* matching_type_signature,
    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
  return S_OK;
}

IFACEMETHODIMP IndexedFieldParent::GetName(BSTR* model_name) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP IndexedFieldParent::GetDimensionality(
    IModelObject* context_object, ULONG64* dimensionality) noexcept {
  *dimensionality = 1;
  return S_OK;
}

IFACEMETHODIMP IndexedFieldParent::GetAt(IModelObject* context_object,
                                         ULONG64 indexer_count,
                                         IModelObject** indexers,
                                         IModelObject** object,
                                         IKeyStore** metadata) noexcept {
  if (indexer_count != 1) return E_INVALIDARG;
  if (metadata != nullptr) *metadata = nullptr;

  ULONG64 index;
  RETURN_IF_FAIL(UnboxULong64(indexers[0], &index, /*convert=*/true));

  return GetModelForCustomArrayElement(context_object, index, object);
}

IFACEMETHODIMP IndexedFieldParent::SetAt(IModelObject* context_object,
                                         ULONG64 indexer_count,
                                         IModelObject** indexers,
                                         IModelObject* value) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP IndexedFieldParent::GetDefaultIndexDimensionality(
    IModelObject* context_object, ULONG64* dimensionality) noexcept {
  *dimensionality = 1;
  return S_OK;
}

IFACEMETHODIMP IndexedFieldParent::GetIterator(
    IModelObject* context_object, IModelIterator** iterator) noexcept {
  auto indexed_field_iterator{WRL::Make<IndexedFieldIterator>(context_object)};
  *iterator = indexed_field_iterator.Detach();
  return S_OK;
}

IndexedFieldIterator::IndexedFieldIterator(IModelObject* context_object)
    : context_object_(context_object) {}
IndexedFieldIterator::~IndexedFieldIterator() = default;

IFACEMETHODIMP IndexedFieldIterator::Reset() noexcept {
  next_ = 0;
  return S_OK;
}

IFACEMETHODIMP IndexedFieldIterator::GetNext(IModelObject** object,
                                             ULONG64 dimensions,
                                             IModelObject** indexers,
                                             IKeyStore** metadata) noexcept {
  if (dimensions > 1) return E_INVALIDARG;

  WRL::ComPtr<IModelObject> sp_index, sp_value;
  RETURN_IF_FAIL(
      GetModelForCustomArrayElement(context_object_.Get(), next_, &sp_value));
  RETURN_IF_FAIL(CreateULong64(next_, &sp_index));

  // Everything that could fail (including the bounds check) has succeeded, so
  // increment the index.
  ++next_;

  // Write results (none of these steps can fail, which is important because we
  // transfer ownership of two separate objects).
  if (dimensions == 1) {
    indexers[0] = sp_index.Detach();
  }
  *object = sp_value.Detach();
  if (metadata != nullptr) *metadata = nullptr;
  return S_OK;
}

IFACEMETHODIMP V8ObjectDataModel::GetKey(IModelObject* context_object,
                                         PCWSTR key, IModelObject** key_value,
                                         IKeyStore** metadata,
                                         bool* has_key) noexcept {
  if (metadata != nullptr) *metadata = nullptr;

  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));
  V8HeapObject* p_v8_heap_object;
  RETURN_IF_FAIL(sp_v8_cached_object->GetCachedV8HeapObject(&p_v8_heap_object));

  *has_key = false;
  for (const auto& prop : p_v8_heap_object->properties) {
    const char16_t* p_key = reinterpret_cast<const char16_t*>(key);
    if (prop.name.compare(p_key) == 0) {
      *has_key = true;
      if (key_value != nullptr) {
        WRL::ComPtr<IDebugHostContext> sp_ctx;
        RETURN_IF_FAIL(context_object->GetContext(&sp_ctx));
        RETURN_IF_FAIL(GetModelForProperty(prop, sp_ctx, key_value));
      }
      return S_OK;
    }
  }

  return S_OK;
}

IFACEMETHODIMP V8ObjectDataModel::SetKey(IModelObject* context_object,
                                         PCWSTR key, IModelObject* key_value,
                                         IKeyStore* metadata) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP V8ObjectDataModel::EnumerateKeys(
    IModelObject* context_object, IKeyEnumerator** pp_enumerator) noexcept {
  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));

  auto enumerator{WRL::Make<V8ObjectKeyEnumerator>(sp_v8_cached_object)};
  *pp_enumerator = enumerator.Detach();
  return S_OK;
}

IFACEMETHODIMP V8LocalValueProperty::GetValue(
    PCWSTR pwsz_key, IModelObject* p_v8_local_instance,
    IModelObject** pp_value) noexcept {
  // Get the parametric type within v8::Local<*>
  // Set value to a pointer to an instance of this type.

  WRL::ComPtr<IDebugHostType> sp_type;
  RETURN_IF_FAIL(p_v8_local_instance->GetTypeInfo(&sp_type));

  bool is_generic;
  RETURN_IF_FAIL(sp_type->IsGeneric(&is_generic));
  if (!is_generic) return E_FAIL;

  WRL::ComPtr<IDebugHostSymbol> sp_generic_arg;
  RETURN_IF_FAIL(sp_type->GetGenericArgumentAt(0, &sp_generic_arg));

  _bstr_t generic_name;
  RETURN_IF_FAIL(sp_generic_arg->GetName(generic_name.GetAddress()));

  WRL::ComPtr<IDebugHostContext> sp_ctx;
  RETURN_IF_FAIL(p_v8_local_instance->GetContext(&sp_ctx));

  WRL::ComPtr<IDebugHostType> sp_value_type =
      Extension::Current()->GetTypeFromV8Module(
          sp_ctx, reinterpret_cast<const char16_t*>(
                      static_cast<const wchar_t*>(generic_name)));
  if (sp_value_type == nullptr ||
      !Extension::Current()->DoesTypeDeriveFromObject(sp_value_type)) {
    // The value type doesn't derive from v8::internal::Object (probably a
    // public API type), so just use plain v8::internal::Object. We could
    // consider mapping some public API types to their corresponding internal
    // types here, at the possible cost of increased maintenance.
    sp_value_type = Extension::Current()->GetV8ObjectType(sp_ctx);
  }

  Location loc;
  RETURN_IF_FAIL(p_v8_local_instance->GetLocation(&loc));

  // Read the pointer at the Object location
  ULONG64 obj_address;
  RETURN_IF_FAIL(
      sp_debug_host_memory->ReadPointers(sp_ctx.Get(), loc, 1, &obj_address));

  // If the val_ is a nullptr, then there is no value in the Local.
  if (obj_address == 0) {
    RETURN_IF_FAIL(CreateString(std::u16string{u"<empty>"}, pp_value));
  } else {
    // Should be a v8::internal::Object at the address
    RETURN_IF_FAIL(sp_data_model_manager->CreateTypedObject(
        sp_ctx.Get(), obj_address, sp_value_type.Get(), pp_value));
  }

  return S_OK;
}

IFACEMETHODIMP V8LocalValueProperty::SetValue(
    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
    IModelObject* /*p_value*/) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP V8InternalCompilerNodeIdProperty::GetValue(
    PCWSTR pwsz_key, IModelObject* p_v8_compiler_node_instance,
    IModelObject** pp_value) noexcept {
  WRL::ComPtr<IModelObject> sp_bit_field;
  RETURN_IF_FAIL(p_v8_compiler_node_instance->GetRawValue(
      SymbolKind::SymbolField, L"bit_field_", RawSearchNone, &sp_bit_field));

  uint64_t bit_field_value;
  RETURN_IF_FAIL(
      UnboxULong64(sp_bit_field.Get(), &bit_field_value, true /*convert*/));

  WRL::ComPtr<IDebugHostContext> sp_host_context;
  RETURN_IF_FAIL(p_v8_compiler_node_instance->GetContext(&sp_host_context));

  WRL::ComPtr<IDebugHostType> sp_id_field_type;
  RETURN_IF_FAIL(Extension::Current()
                     ->GetV8Module(sp_host_context)
                     ->FindTypeByName(L"v8::internal::compiler::Node::IdField",
                                      &sp_id_field_type));

  // Get 2nd template parameter as 24 in class.
  // v8::base::BitField<v8::internal::compiler::NodeId, 0, 24>.
  bool is_generic;
  RETURN_IF_FAIL(sp_id_field_type->IsGeneric(&is_generic));
  if (!is_generic) return E_FAIL;

  WRL::ComPtr<IDebugHostSymbol> sp_k_size_arg;
  RETURN_IF_FAIL(sp_id_field_type->GetGenericArgumentAt(2, &sp_k_size_arg));

  WRL::ComPtr<IDebugHostConstant> sp_k_size_constant;
  RETURN_IF_FAIL(sp_k_size_arg.As(&sp_k_size_constant));

  int k_size;
  RETURN_IF_FAIL(GetInt32(sp_k_size_constant.Get(), &k_size));

  // Compute node_id.
  uint32_t node_id = bit_field_value & (0xFFFFFFFF >> k_size);
  RETURN_IF_FAIL(CreateUInt32(node_id, pp_value));

  return S_OK;
}

IFACEMETHODIMP V8InternalCompilerNodeIdProperty::SetValue(
    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
    IModelObject* /*p_value*/) noexcept {
  return E_NOTIMPL;
}

IFACEMETHODIMP V8InternalCompilerBitsetNameProperty::GetValue(
    PCWSTR pwsz_key, IModelObject* p_v8_compiler_type_instance,
    IModelObject** pp_value) noexcept {
  WRL::ComPtr<IModelObject> sp_payload;
  RETURN_IF_FAIL(p_v8_compiler_type_instance->GetRawValue(
      SymbolKind::SymbolField, L"payload_", RawSearchNone, &sp_payload));

  uint64_t payload_value;
  RETURN_IF_FAIL(
      UnboxULong64(sp_payload.Get(), &payload_value, true /*convert*/));

  const char* bitset_name = ::BitsetName(payload_value);
  if (!bitset_name) return E_FAIL;
  std::string name(bitset_name);
  RETURN_IF_FAIL(CreateString(ConvertToU16String(name), pp_value));

  return S_OK;
}

IFACEMETHODIMP V8InternalCompilerBitsetNameProperty::SetValue(
    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
    IModelObject* /*p_value*/) noexcept {
  return E_NOTIMPL;
}

constexpr wchar_t usage[] =
    LR"(Invalid arguments.
First argument should be a uint64 representing the tagged value to investigate.
Second argument is optional, and may be a fully-qualified type name such as
v8::internal::String.)";

IFACEMETHODIMP InspectV8ObjectMethod::Call(IModelObject* p_context_object,
                                           ULONG64 arg_count,
                                           _In_reads_(arg_count)
                                               IModelObject** pp_arguments,
                                           IModelObject** pp_result,
                                           IKeyStore** pp_metadata) noexcept {
  // Read the arguments.
  ULONG64 tagged_value;
  _bstr_t type_name;
  if (arg_count < 1 ||
      FAILED(UnboxULong64(pp_arguments[0], &tagged_value, /*convert=*/true)) ||
      (arg_count >= 2 &&
       FAILED(UnboxString(pp_arguments[1], type_name.GetAddress())))) {
    sp_data_model_manager->CreateErrorObject(E_INVALIDARG, usage, pp_result);
    return E_INVALIDARG;
  }

  WRL::ComPtr<IDebugHostContext> sp_ctx;
  RETURN_IF_FAIL(sp_debug_host->GetCurrentContext(&sp_ctx));

  // We can't use CreateTypedObject for a value which may not actually reside
  // anywhere in memory, so create a synthetic object.
  WRL::ComPtr<V8CachedObject> cached_object =
      WRL::Make<V8CachedObject>(::GetHeapObject(
          sp_ctx, tagged_value, 0, static_cast<const char*>(type_name),
          /*is_compressed=*/false));
  return CreateSyntheticObjectForV8Object(sp_ctx.Get(), cached_object.Get(),
                                          pp_result);
}

// Creates an IModelObject representing the data in the given property.
HRESULT GetModelForProperty(const Property& prop,
                            WRL::ComPtr<IDebugHostContext>& sp_ctx,
                            IModelObject** result) {
  switch (prop.type) {
    case PropertyType::kPointer:
      return GetModelForBasicField(prop.addr_value, prop.type_name,
                                   prop.uncompressed_type_name, sp_ctx, result);
    case PropertyType::kStruct:
      return GetModelForStruct(prop.addr_value, prop.fields, sp_ctx, result);
    case PropertyType::kArray:
    case PropertyType::kStructArray:
      if (prop.type == PropertyType::kArray &&
          prop.type_name == ConvertToU16String(prop.uncompressed_type_name)) {
        // An array of things that are not structs or compressed tagged values
        // is most cleanly represented by a native array.
        return GetModelForNativeArray(prop.addr_value, prop.type_name,
                                      prop.length, sp_ctx, result);
      }
      // Otherwise, we must construct a custom iterable object.
      return GetModelForCustomArray(prop, sp_ctx, result);
    default:
      return E_FAIL;
  }
}
