11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/object-inspection.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/flags/flags.h"
81cb0ef41Sopenharmony_ci#include "tools/v8windbg/base/utilities.h"
91cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/v8-debug-helper-interop.h"
101cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/v8windbg-extension.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciV8CachedObject::V8CachedObject(Location location,
131cb0ef41Sopenharmony_ci                               std::string uncompressed_type_name,
141cb0ef41Sopenharmony_ci                               WRL::ComPtr<IDebugHostContext> context,
151cb0ef41Sopenharmony_ci                               bool is_compressed)
161cb0ef41Sopenharmony_ci    : location_(std::move(location)),
171cb0ef41Sopenharmony_ci      uncompressed_type_name_(std::move(uncompressed_type_name)),
181cb0ef41Sopenharmony_ci      context_(std::move(context)),
191cb0ef41Sopenharmony_ci      is_compressed_(is_compressed) {}
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciHRESULT V8CachedObject::Create(IModelObject* p_v8_object_instance,
221cb0ef41Sopenharmony_ci                               IV8CachedObject** result) {
231cb0ef41Sopenharmony_ci  Location location;
241cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_object_instance->GetLocation(&location));
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> context;
271cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_object_instance->GetContext(&context));
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> sp_type;
301cb0ef41Sopenharmony_ci  _bstr_t type_name;
311cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_object_instance->GetTypeInfo(&sp_type));
321cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_type->GetName(type_name.GetAddress()));
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  // If the object is of type v8::internal::TaggedValue, and this build uses
351cb0ef41Sopenharmony_ci  // compressed pointers, then the value is compressed. Other types such as
361cb0ef41Sopenharmony_ci  // v8::internal::Object represent uncompressed tagged values.
371cb0ef41Sopenharmony_ci  bool is_compressed =
381cb0ef41Sopenharmony_ci      COMPRESS_POINTERS_BOOL &&
391cb0ef41Sopenharmony_ci      static_cast<const char*>(type_name) == std::string(kTaggedValue);
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  const char* uncompressed_type_name =
421cb0ef41Sopenharmony_ci      is_compressed ? kObject : static_cast<const char*>(type_name);
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  *result = WRL::Make<V8CachedObject>(location, uncompressed_type_name, context,
451cb0ef41Sopenharmony_ci                                      is_compressed)
461cb0ef41Sopenharmony_ci                .Detach();
471cb0ef41Sopenharmony_ci  return S_OK;
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciV8CachedObject::V8CachedObject(V8HeapObject heap_object)
511cb0ef41Sopenharmony_ci    : heap_object_(std::move(heap_object)), heap_object_initialized_(true) {}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ciV8CachedObject::~V8CachedObject() = default;
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciIFACEMETHODIMP V8CachedObject::GetCachedV8HeapObject(
561cb0ef41Sopenharmony_ci    V8HeapObject** pp_heap_object) noexcept {
571cb0ef41Sopenharmony_ci  if (!heap_object_initialized_) {
581cb0ef41Sopenharmony_ci    heap_object_initialized_ = true;
591cb0ef41Sopenharmony_ci    uint64_t tagged_ptr = 0;
601cb0ef41Sopenharmony_ci    uint64_t bytes_read;
611cb0ef41Sopenharmony_ci    HRESULT hr = sp_debug_host_memory->ReadBytes(
621cb0ef41Sopenharmony_ci        context_.Get(), location_, reinterpret_cast<void*>(&tagged_ptr),
631cb0ef41Sopenharmony_ci        is_compressed_ ? i::kTaggedSize : sizeof(void*), &bytes_read);
641cb0ef41Sopenharmony_ci    // S_FALSE can be returned if fewer bytes were read than were requested. We
651cb0ef41Sopenharmony_ci    // need all of the bytes, so check for S_OK.
661cb0ef41Sopenharmony_ci    if (hr != S_OK) {
671cb0ef41Sopenharmony_ci      std::stringstream message;
681cb0ef41Sopenharmony_ci      message << "Unable to read memory";
691cb0ef41Sopenharmony_ci      if (location_.IsVirtualAddress()) {
701cb0ef41Sopenharmony_ci        message << " at 0x" << std::hex << location_.GetOffset();
711cb0ef41Sopenharmony_ci      }
721cb0ef41Sopenharmony_ci      heap_object_.friendly_name = ConvertToU16String(message.str());
731cb0ef41Sopenharmony_ci    } else {
741cb0ef41Sopenharmony_ci      if (is_compressed_)
751cb0ef41Sopenharmony_ci        tagged_ptr = ExpandCompressedPointer(static_cast<uint32_t>(tagged_ptr));
761cb0ef41Sopenharmony_ci      heap_object_ =
771cb0ef41Sopenharmony_ci          ::GetHeapObject(context_, tagged_ptr, location_.GetOffset(),
781cb0ef41Sopenharmony_ci                          uncompressed_type_name_.c_str(), is_compressed_);
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci  *pp_heap_object = &this->heap_object_;
821cb0ef41Sopenharmony_ci  return S_OK;
831cb0ef41Sopenharmony_ci}
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ciIndexedFieldData::IndexedFieldData(Property property)
861cb0ef41Sopenharmony_ci    : property_(std::move(property)) {}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciIndexedFieldData::~IndexedFieldData() = default;
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldData::GetProperty(Property** property) noexcept {
911cb0ef41Sopenharmony_ci  if (!property) return E_POINTER;
921cb0ef41Sopenharmony_ci  *property = &this->property_;
931cb0ef41Sopenharmony_ci  return S_OK;
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ciV8ObjectKeyEnumerator::V8ObjectKeyEnumerator(
971cb0ef41Sopenharmony_ci    WRL::ComPtr<IV8CachedObject>& v8_cached_object)
981cb0ef41Sopenharmony_ci    : sp_v8_cached_object_{v8_cached_object} {}
991cb0ef41Sopenharmony_ciV8ObjectKeyEnumerator::~V8ObjectKeyEnumerator() = default;
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectKeyEnumerator::Reset() noexcept {
1021cb0ef41Sopenharmony_ci  index_ = 0;
1031cb0ef41Sopenharmony_ci  return S_OK;
1041cb0ef41Sopenharmony_ci}
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectKeyEnumerator::GetNext(BSTR* key, IModelObject** value,
1071cb0ef41Sopenharmony_ci                                              IKeyStore** metadata) noexcept {
1081cb0ef41Sopenharmony_ci  V8HeapObject* p_v8_heap_object;
1091cb0ef41Sopenharmony_ci  sp_v8_cached_object_->GetCachedV8HeapObject(&p_v8_heap_object);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  if (static_cast<size_t>(index_) >= p_v8_heap_object->properties.size())
1121cb0ef41Sopenharmony_ci    return E_BOUNDS;
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  auto* name_ptr = p_v8_heap_object->properties[index_].name.c_str();
1151cb0ef41Sopenharmony_ci  *key = ::SysAllocString(U16ToWChar(name_ptr));
1161cb0ef41Sopenharmony_ci  ++index_;
1171cb0ef41Sopenharmony_ci  return S_OK;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalDataModel::InitializeObject(
1211cb0ef41Sopenharmony_ci    IModelObject* model_object,
1221cb0ef41Sopenharmony_ci    IDebugHostTypeSignature* matching_type_signature,
1231cb0ef41Sopenharmony_ci    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
1241cb0ef41Sopenharmony_ci  return S_OK;
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalDataModel::GetName(BSTR* model_name) noexcept {
1281cb0ef41Sopenharmony_ci  return E_NOTIMPL;
1291cb0ef41Sopenharmony_ci}
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::InitializeObject(
1321cb0ef41Sopenharmony_ci    IModelObject* model_object,
1331cb0ef41Sopenharmony_ci    IDebugHostTypeSignature* matching_type_signature,
1341cb0ef41Sopenharmony_ci    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
1351cb0ef41Sopenharmony_ci  return S_OK;
1361cb0ef41Sopenharmony_ci}
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::GetName(BSTR* model_name) noexcept {
1391cb0ef41Sopenharmony_ci  return E_NOTIMPL;
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::ToDisplayString(
1431cb0ef41Sopenharmony_ci    IModelObject* context_object, IKeyStore* metadata,
1441cb0ef41Sopenharmony_ci    BSTR* display_string) noexcept {
1451cb0ef41Sopenharmony_ci  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
1461cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));
1471cb0ef41Sopenharmony_ci  V8HeapObject* p_v8_heap_object;
1481cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_v8_cached_object->GetCachedV8HeapObject(&p_v8_heap_object));
1491cb0ef41Sopenharmony_ci  *display_string = ::SysAllocString(
1501cb0ef41Sopenharmony_ci      reinterpret_cast<const wchar_t*>(p_v8_heap_object->friendly_name.data()));
1511cb0ef41Sopenharmony_ci  return S_OK;
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_cinamespace {
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci// Creates a synthetic object, attaches a parent model, and sets the context
1571cb0ef41Sopenharmony_ci// object for that parent data model. Caller is responsible for ensuring that
1581cb0ef41Sopenharmony_ci// the parent model's Concepts have been initialized correctly and that the
1591cb0ef41Sopenharmony_ci// data model context is of an appropriate type for the parent model.
1601cb0ef41Sopenharmony_ciHRESULT CreateSyntheticObjectWithParentAndDataContext(
1611cb0ef41Sopenharmony_ci    IDebugHostContext* ctx, IModelObject* parent_model, IUnknown* data_context,
1621cb0ef41Sopenharmony_ci    IModelObject** result) {
1631cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> value;
1641cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_data_model_manager->CreateSyntheticObject(ctx, &value));
1651cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
1661cb0ef41Sopenharmony_ci      value->AddParentModel(parent_model, nullptr, true /*override*/));
1671cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(value->SetContextForDataModel(parent_model, data_context));
1681cb0ef41Sopenharmony_ci  *result = value.Detach();
1691cb0ef41Sopenharmony_ci  return S_OK;
1701cb0ef41Sopenharmony_ci}
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci// Creates an IModelObject for a V8 object whose value is represented by the
1731cb0ef41Sopenharmony_ci// data in cached_object. This is an alternative to  CreateTypedObject for
1741cb0ef41Sopenharmony_ci// particularly complex cases (compressed values and those that don't exist
1751cb0ef41Sopenharmony_ci// anywhere in memory).
1761cb0ef41Sopenharmony_ciHRESULT CreateSyntheticObjectForV8Object(IDebugHostContext* ctx,
1771cb0ef41Sopenharmony_ci                                         V8CachedObject* cached_object,
1781cb0ef41Sopenharmony_ci                                         IModelObject** result) {
1791cb0ef41Sopenharmony_ci  // Explicitly add the parent model and data context. On a plain typed object,
1801cb0ef41Sopenharmony_ci  // the parent model would be attached automatically because we registered for
1811cb0ef41Sopenharmony_ci  // a matching type signature, and the data context would be set during
1821cb0ef41Sopenharmony_ci  // V8ObjectDataModel::GetCachedObject.
1831cb0ef41Sopenharmony_ci  return CreateSyntheticObjectWithParentAndDataContext(
1841cb0ef41Sopenharmony_ci      ctx, Extension::Current()->GetObjectDataModel(), cached_object, result);
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci// Creates an IModelObject to represent a field that is not a struct or array.
1881cb0ef41Sopenharmony_ciHRESULT GetModelForBasicField(const uint64_t address,
1891cb0ef41Sopenharmony_ci                              const std::u16string& type_name,
1901cb0ef41Sopenharmony_ci                              const std::string& uncompressed_type_name,
1911cb0ef41Sopenharmony_ci                              WRL::ComPtr<IDebugHostContext>& sp_ctx,
1921cb0ef41Sopenharmony_ci                              IModelObject** result) {
1931cb0ef41Sopenharmony_ci  if (type_name == ConvertToU16String(uncompressed_type_name)) {
1941cb0ef41Sopenharmony_ci    // For untagged and uncompressed tagged fields, create an IModelObject
1951cb0ef41Sopenharmony_ci    // representing a normal native data type.
1961cb0ef41Sopenharmony_ci    WRL::ComPtr<IDebugHostType> type =
1971cb0ef41Sopenharmony_ci        Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
1981cb0ef41Sopenharmony_ci    if (type == nullptr) return E_FAIL;
1991cb0ef41Sopenharmony_ci    return sp_data_model_manager->CreateTypedObject(
2001cb0ef41Sopenharmony_ci        sp_ctx.Get(), Location{address}, type.Get(), result);
2011cb0ef41Sopenharmony_ci  }
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  // For compressed tagged fields, we need to do something a little more
2041cb0ef41Sopenharmony_ci  // complicated. We could just use CreateTypedObject with the type
2051cb0ef41Sopenharmony_ci  // v8::internal::TaggedValue, but then we'd sacrifice any other data
2061cb0ef41Sopenharmony_ci  // that we've learned about the field's specific type. So instead we
2071cb0ef41Sopenharmony_ci  // create a synthetic object.
2081cb0ef41Sopenharmony_ci  WRL::ComPtr<V8CachedObject> cached_object = WRL::Make<V8CachedObject>(
2091cb0ef41Sopenharmony_ci      Location(address), uncompressed_type_name, sp_ctx,
2101cb0ef41Sopenharmony_ci      /*is_compressed=*/true);
2111cb0ef41Sopenharmony_ci  return CreateSyntheticObjectForV8Object(sp_ctx.Get(), cached_object.Get(),
2121cb0ef41Sopenharmony_ci                                          result);
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci// Creates an IModelObject representing the value of a bitfield.
2161cb0ef41Sopenharmony_ciHRESULT GetModelForBitField(uint64_t address, const uint8_t num_bits,
2171cb0ef41Sopenharmony_ci                            uint8_t shift_bits, const std::u16string& type_name,
2181cb0ef41Sopenharmony_ci                            WRL::ComPtr<IDebugHostContext>& sp_ctx,
2191cb0ef41Sopenharmony_ci                            IModelObject** result) {
2201cb0ef41Sopenharmony_ci  // Look up the type by name.
2211cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> type =
2221cb0ef41Sopenharmony_ci      Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
2231cb0ef41Sopenharmony_ci  if (type == nullptr) return E_FAIL;
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  // Figure out exactly which bytes contain the bitfield's data. This depends on
2261cb0ef41Sopenharmony_ci  // platform byte order (little-endian for Windows).
2271cb0ef41Sopenharmony_ci  constexpr int kBitsPerByte = 8;
2281cb0ef41Sopenharmony_ci  uint8_t shift_bytes = shift_bits / kBitsPerByte;
2291cb0ef41Sopenharmony_ci  address += shift_bytes;
2301cb0ef41Sopenharmony_ci  shift_bits -= shift_bytes * kBitsPerByte;
2311cb0ef41Sopenharmony_ci  size_t bits_to_read = shift_bits + num_bits;
2321cb0ef41Sopenharmony_ci  size_t bytes_to_read = (bits_to_read + kBitsPerByte - 1) / kBitsPerByte;
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci  uintptr_t value = 0;
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  // V8 guarantees that bitfield structs are no bigger than a single pointer.
2371cb0ef41Sopenharmony_ci  if (bytes_to_read > sizeof(value)) {
2381cb0ef41Sopenharmony_ci    std::stringstream message;
2391cb0ef41Sopenharmony_ci    message << "Fatal v8windbg error: found bitfield struct of "
2401cb0ef41Sopenharmony_ci            << bytes_to_read << "bytes, which exceeds the supported size of "
2411cb0ef41Sopenharmony_ci            << sizeof(value);
2421cb0ef41Sopenharmony_ci    return CreateString(ConvertToU16String(message.str()), result);
2431cb0ef41Sopenharmony_ci  }
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  uint64_t bytes_read;
2461cb0ef41Sopenharmony_ci  HRESULT hr = sp_debug_host_memory->ReadBytes(sp_ctx.Get(), address,
2471cb0ef41Sopenharmony_ci                                               reinterpret_cast<void*>(&value),
2481cb0ef41Sopenharmony_ci                                               bytes_to_read, &bytes_read);
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  // S_FALSE can be returned if fewer bytes were read than were requested. We
2511cb0ef41Sopenharmony_ci  // need all of the bytes, so check for S_OK.
2521cb0ef41Sopenharmony_ci  if (hr != S_OK) {
2531cb0ef41Sopenharmony_ci    std::stringstream message;
2541cb0ef41Sopenharmony_ci    message << "Unable to read memory at 0x" << std::hex << address;
2551cb0ef41Sopenharmony_ci    return CreateString(ConvertToU16String(message.str()), result);
2561cb0ef41Sopenharmony_ci  }
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci  // Decode the bitfield.
2591cb0ef41Sopenharmony_ci  value = (value >> shift_bits) & ((1 << num_bits) - 1);
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  return CreateTypedIntrinsic(value, type.Get(), result);
2621cb0ef41Sopenharmony_ci}
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci// Creates an IModelObject to represent the packed fields in a Torque struct.
2651cb0ef41Sopenharmony_ci// Note that Torque structs are not C++ structs and do not have any type
2661cb0ef41Sopenharmony_ci// definitions in the V8 symbols.
2671cb0ef41Sopenharmony_ciHRESULT GetModelForStruct(const uint64_t address,
2681cb0ef41Sopenharmony_ci                          const std::vector<StructField>& fields,
2691cb0ef41Sopenharmony_ci                          WRL::ComPtr<IDebugHostContext>& sp_ctx,
2701cb0ef41Sopenharmony_ci                          IModelObject** result) {
2711cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> sp_value;
2721cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
2731cb0ef41Sopenharmony_ci      sp_data_model_manager->CreateSyntheticObject(sp_ctx.Get(), &sp_value));
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci  // There's no need for any fancy Concepts here; just add key-value pairs for
2761cb0ef41Sopenharmony_ci  // each field.
2771cb0ef41Sopenharmony_ci  for (const StructField& field : fields) {
2781cb0ef41Sopenharmony_ci    WRL::ComPtr<IModelObject> field_model;
2791cb0ef41Sopenharmony_ci    if (field.num_bits == 0) {
2801cb0ef41Sopenharmony_ci      RETURN_IF_FAIL(GetModelForBasicField(
2811cb0ef41Sopenharmony_ci          address + field.offset, field.type_name, field.uncompressed_type_name,
2821cb0ef41Sopenharmony_ci          sp_ctx, &field_model));
2831cb0ef41Sopenharmony_ci    } else {
2841cb0ef41Sopenharmony_ci      RETURN_IF_FAIL(GetModelForBitField(address + field.offset, field.num_bits,
2851cb0ef41Sopenharmony_ci                                         field.shift_bits, field.type_name,
2861cb0ef41Sopenharmony_ci                                         sp_ctx, &field_model));
2871cb0ef41Sopenharmony_ci    }
2881cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(
2891cb0ef41Sopenharmony_ci        sp_value->SetKey(reinterpret_cast<const wchar_t*>(field.name.c_str()),
2901cb0ef41Sopenharmony_ci                         field_model.Get(), nullptr));
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci  *result = sp_value.Detach();
2941cb0ef41Sopenharmony_ci  return S_OK;
2951cb0ef41Sopenharmony_ci}
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci// Creates an IModelObject representing an array of some type that we expect to
2981cb0ef41Sopenharmony_ci// be defined in the V8 symbols.
2991cb0ef41Sopenharmony_ciHRESULT GetModelForNativeArray(const uint64_t address,
3001cb0ef41Sopenharmony_ci                               const std::u16string& type_name, size_t count,
3011cb0ef41Sopenharmony_ci                               WRL::ComPtr<IDebugHostContext>& sp_ctx,
3021cb0ef41Sopenharmony_ci                               IModelObject** result) {
3031cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> type =
3041cb0ef41Sopenharmony_ci      Extension::Current()->GetTypeFromV8Module(sp_ctx, type_name.c_str());
3051cb0ef41Sopenharmony_ci  if (type == nullptr) return E_FAIL;
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci  ULONG64 object_size{};
3081cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(type->GetSize(&object_size));
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  ArrayDimension dimensions[] = {
3111cb0ef41Sopenharmony_ci      {/*start=*/0, /*length=*/count, /*stride=*/object_size}};
3121cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> array_type;
3131cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
3141cb0ef41Sopenharmony_ci      type->CreateArrayOf(/*dimensions=*/1, dimensions, &array_type));
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  return sp_data_model_manager->CreateTypedObject(
3171cb0ef41Sopenharmony_ci      sp_ctx.Get(), Location{address}, array_type.Get(), result);
3181cb0ef41Sopenharmony_ci}
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci// Creates an IModelObject that represents an array of structs or compressed
3211cb0ef41Sopenharmony_ci// tagged values.
3221cb0ef41Sopenharmony_ciHRESULT GetModelForCustomArray(const Property& prop,
3231cb0ef41Sopenharmony_ci                               WRL::ComPtr<IDebugHostContext>& sp_ctx,
3241cb0ef41Sopenharmony_ci                               IModelObject** result) {
3251cb0ef41Sopenharmony_ci  // Create the context which should be provided to the indexing and iterating
3261cb0ef41Sopenharmony_ci  // functionality provided by the parent model. This is instance-specific data,
3271cb0ef41Sopenharmony_ci  // whereas the parent model object could be shared among many custom arrays.
3281cb0ef41Sopenharmony_ci  WRL::ComPtr<IndexedFieldData> context_data =
3291cb0ef41Sopenharmony_ci      WRL::Make<IndexedFieldData>(prop);
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci  return CreateSyntheticObjectWithParentAndDataContext(
3321cb0ef41Sopenharmony_ci      sp_ctx.Get(), Extension::Current()->GetIndexedFieldDataModel(),
3331cb0ef41Sopenharmony_ci      context_data.Get(), result);
3341cb0ef41Sopenharmony_ci}
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci// Creates an IModelObject representing the data in an array at the given index.
3381cb0ef41Sopenharmony_ci// context_object is expected to be an object of the form created by
3391cb0ef41Sopenharmony_ci// GetModelForCustomArray, meaning its context for the IndexedFieldParent data
3401cb0ef41Sopenharmony_ci// model is an IIndexedFieldData containing the description of the array.
3411cb0ef41Sopenharmony_ciHRESULT GetModelForCustomArrayElement(IModelObject* context_object,
3421cb0ef41Sopenharmony_ci                                      size_t index, IModelObject** object) {
3431cb0ef41Sopenharmony_ci  // Open a few layers of wrapper objects to get to the Property object that
3441cb0ef41Sopenharmony_ci  // describes the array.
3451cb0ef41Sopenharmony_ci  WRL::ComPtr<IUnknown> data_model_context;
3461cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(context_object->GetContextForDataModel(
3471cb0ef41Sopenharmony_ci      Extension::Current()->GetIndexedFieldDataModel(), &data_model_context));
3481cb0ef41Sopenharmony_ci  WRL::ComPtr<IIndexedFieldData> indexed_field_data;
3491cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(data_model_context.As(&indexed_field_data));
3501cb0ef41Sopenharmony_ci  Property* prop;
3511cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(indexed_field_data->GetProperty(&prop));
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci  if (index >= prop->length) {
3541cb0ef41Sopenharmony_ci    return E_BOUNDS;
3551cb0ef41Sopenharmony_ci  }
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> sp_ctx;
3581cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(context_object->GetContext(&sp_ctx));
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  ULONG64 address = prop->addr_value + index * prop->item_size;
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci  switch (prop->type) {
3631cb0ef41Sopenharmony_ci    case PropertyType::kArray:
3641cb0ef41Sopenharmony_ci      return GetModelForBasicField(address, prop->type_name,
3651cb0ef41Sopenharmony_ci                                   prop->uncompressed_type_name, sp_ctx,
3661cb0ef41Sopenharmony_ci                                   object);
3671cb0ef41Sopenharmony_ci    case PropertyType::kStructArray:
3681cb0ef41Sopenharmony_ci      return GetModelForStruct(address, prop->fields, sp_ctx, object);
3691cb0ef41Sopenharmony_ci    default:
3701cb0ef41Sopenharmony_ci      return E_FAIL;  // Only array properties should be possible here.
3711cb0ef41Sopenharmony_ci  }
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci}  // namespace
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::InitializeObject(
3771cb0ef41Sopenharmony_ci    IModelObject* model_object,
3781cb0ef41Sopenharmony_ci    IDebugHostTypeSignature* matching_type_signature,
3791cb0ef41Sopenharmony_ci    IDebugHostSymbolEnumerator* wildcard_matches) noexcept {
3801cb0ef41Sopenharmony_ci  return S_OK;
3811cb0ef41Sopenharmony_ci}
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::GetName(BSTR* model_name) noexcept {
3841cb0ef41Sopenharmony_ci  return E_NOTIMPL;
3851cb0ef41Sopenharmony_ci}
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::GetDimensionality(
3881cb0ef41Sopenharmony_ci    IModelObject* context_object, ULONG64* dimensionality) noexcept {
3891cb0ef41Sopenharmony_ci  *dimensionality = 1;
3901cb0ef41Sopenharmony_ci  return S_OK;
3911cb0ef41Sopenharmony_ci}
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::GetAt(IModelObject* context_object,
3941cb0ef41Sopenharmony_ci                                         ULONG64 indexer_count,
3951cb0ef41Sopenharmony_ci                                         IModelObject** indexers,
3961cb0ef41Sopenharmony_ci                                         IModelObject** object,
3971cb0ef41Sopenharmony_ci                                         IKeyStore** metadata) noexcept {
3981cb0ef41Sopenharmony_ci  if (indexer_count != 1) return E_INVALIDARG;
3991cb0ef41Sopenharmony_ci  if (metadata != nullptr) *metadata = nullptr;
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ci  ULONG64 index;
4021cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(UnboxULong64(indexers[0], &index, /*convert=*/true));
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  return GetModelForCustomArrayElement(context_object, index, object);
4051cb0ef41Sopenharmony_ci}
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::SetAt(IModelObject* context_object,
4081cb0ef41Sopenharmony_ci                                         ULONG64 indexer_count,
4091cb0ef41Sopenharmony_ci                                         IModelObject** indexers,
4101cb0ef41Sopenharmony_ci                                         IModelObject* value) noexcept {
4111cb0ef41Sopenharmony_ci  return E_NOTIMPL;
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::GetDefaultIndexDimensionality(
4151cb0ef41Sopenharmony_ci    IModelObject* context_object, ULONG64* dimensionality) noexcept {
4161cb0ef41Sopenharmony_ci  *dimensionality = 1;
4171cb0ef41Sopenharmony_ci  return S_OK;
4181cb0ef41Sopenharmony_ci}
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldParent::GetIterator(
4211cb0ef41Sopenharmony_ci    IModelObject* context_object, IModelIterator** iterator) noexcept {
4221cb0ef41Sopenharmony_ci  auto indexed_field_iterator{WRL::Make<IndexedFieldIterator>(context_object)};
4231cb0ef41Sopenharmony_ci  *iterator = indexed_field_iterator.Detach();
4241cb0ef41Sopenharmony_ci  return S_OK;
4251cb0ef41Sopenharmony_ci}
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ciIndexedFieldIterator::IndexedFieldIterator(IModelObject* context_object)
4281cb0ef41Sopenharmony_ci    : context_object_(context_object) {}
4291cb0ef41Sopenharmony_ciIndexedFieldIterator::~IndexedFieldIterator() = default;
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldIterator::Reset() noexcept {
4321cb0ef41Sopenharmony_ci  next_ = 0;
4331cb0ef41Sopenharmony_ci  return S_OK;
4341cb0ef41Sopenharmony_ci}
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ciIFACEMETHODIMP IndexedFieldIterator::GetNext(IModelObject** object,
4371cb0ef41Sopenharmony_ci                                             ULONG64 dimensions,
4381cb0ef41Sopenharmony_ci                                             IModelObject** indexers,
4391cb0ef41Sopenharmony_ci                                             IKeyStore** metadata) noexcept {
4401cb0ef41Sopenharmony_ci  if (dimensions > 1) return E_INVALIDARG;
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> sp_index, sp_value;
4431cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
4441cb0ef41Sopenharmony_ci      GetModelForCustomArrayElement(context_object_.Get(), next_, &sp_value));
4451cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(CreateULong64(next_, &sp_index));
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci  // Everything that could fail (including the bounds check) has succeeded, so
4481cb0ef41Sopenharmony_ci  // increment the index.
4491cb0ef41Sopenharmony_ci  ++next_;
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci  // Write results (none of these steps can fail, which is important because we
4521cb0ef41Sopenharmony_ci  // transfer ownership of two separate objects).
4531cb0ef41Sopenharmony_ci  if (dimensions == 1) {
4541cb0ef41Sopenharmony_ci    indexers[0] = sp_index.Detach();
4551cb0ef41Sopenharmony_ci  }
4561cb0ef41Sopenharmony_ci  *object = sp_value.Detach();
4571cb0ef41Sopenharmony_ci  if (metadata != nullptr) *metadata = nullptr;
4581cb0ef41Sopenharmony_ci  return S_OK;
4591cb0ef41Sopenharmony_ci}
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::GetKey(IModelObject* context_object,
4621cb0ef41Sopenharmony_ci                                         PCWSTR key, IModelObject** key_value,
4631cb0ef41Sopenharmony_ci                                         IKeyStore** metadata,
4641cb0ef41Sopenharmony_ci                                         bool* has_key) noexcept {
4651cb0ef41Sopenharmony_ci  if (metadata != nullptr) *metadata = nullptr;
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_ci  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
4681cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));
4691cb0ef41Sopenharmony_ci  V8HeapObject* p_v8_heap_object;
4701cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_v8_cached_object->GetCachedV8HeapObject(&p_v8_heap_object));
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci  *has_key = false;
4731cb0ef41Sopenharmony_ci  for (const auto& prop : p_v8_heap_object->properties) {
4741cb0ef41Sopenharmony_ci    const char16_t* p_key = reinterpret_cast<const char16_t*>(key);
4751cb0ef41Sopenharmony_ci    if (prop.name.compare(p_key) == 0) {
4761cb0ef41Sopenharmony_ci      *has_key = true;
4771cb0ef41Sopenharmony_ci      if (key_value != nullptr) {
4781cb0ef41Sopenharmony_ci        WRL::ComPtr<IDebugHostContext> sp_ctx;
4791cb0ef41Sopenharmony_ci        RETURN_IF_FAIL(context_object->GetContext(&sp_ctx));
4801cb0ef41Sopenharmony_ci        RETURN_IF_FAIL(GetModelForProperty(prop, sp_ctx, key_value));
4811cb0ef41Sopenharmony_ci      }
4821cb0ef41Sopenharmony_ci      return S_OK;
4831cb0ef41Sopenharmony_ci    }
4841cb0ef41Sopenharmony_ci  }
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci  return S_OK;
4871cb0ef41Sopenharmony_ci}
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::SetKey(IModelObject* context_object,
4901cb0ef41Sopenharmony_ci                                         PCWSTR key, IModelObject* key_value,
4911cb0ef41Sopenharmony_ci                                         IKeyStore* metadata) noexcept {
4921cb0ef41Sopenharmony_ci  return E_NOTIMPL;
4931cb0ef41Sopenharmony_ci}
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ciIFACEMETHODIMP V8ObjectDataModel::EnumerateKeys(
4961cb0ef41Sopenharmony_ci    IModelObject* context_object, IKeyEnumerator** pp_enumerator) noexcept {
4971cb0ef41Sopenharmony_ci  WRL::ComPtr<IV8CachedObject> sp_v8_cached_object;
4981cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(GetCachedObject(context_object, &sp_v8_cached_object));
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci  auto enumerator{WRL::Make<V8ObjectKeyEnumerator>(sp_v8_cached_object)};
5011cb0ef41Sopenharmony_ci  *pp_enumerator = enumerator.Detach();
5021cb0ef41Sopenharmony_ci  return S_OK;
5031cb0ef41Sopenharmony_ci}
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalValueProperty::GetValue(
5061cb0ef41Sopenharmony_ci    PCWSTR pwsz_key, IModelObject* p_v8_local_instance,
5071cb0ef41Sopenharmony_ci    IModelObject** pp_value) noexcept {
5081cb0ef41Sopenharmony_ci  // Get the parametric type within v8::Local<*>
5091cb0ef41Sopenharmony_ci  // Set value to a pointer to an instance of this type.
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> sp_type;
5121cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_local_instance->GetTypeInfo(&sp_type));
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ci  bool is_generic;
5151cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_type->IsGeneric(&is_generic));
5161cb0ef41Sopenharmony_ci  if (!is_generic) return E_FAIL;
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostSymbol> sp_generic_arg;
5191cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_type->GetGenericArgumentAt(0, &sp_generic_arg));
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  _bstr_t generic_name;
5221cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_generic_arg->GetName(generic_name.GetAddress()));
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> sp_ctx;
5251cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_local_instance->GetContext(&sp_ctx));
5261cb0ef41Sopenharmony_ci
5271cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> sp_value_type =
5281cb0ef41Sopenharmony_ci      Extension::Current()->GetTypeFromV8Module(
5291cb0ef41Sopenharmony_ci          sp_ctx, reinterpret_cast<const char16_t*>(
5301cb0ef41Sopenharmony_ci                      static_cast<const wchar_t*>(generic_name)));
5311cb0ef41Sopenharmony_ci  if (sp_value_type == nullptr ||
5321cb0ef41Sopenharmony_ci      !Extension::Current()->DoesTypeDeriveFromObject(sp_value_type)) {
5331cb0ef41Sopenharmony_ci    // The value type doesn't derive from v8::internal::Object (probably a
5341cb0ef41Sopenharmony_ci    // public API type), so just use plain v8::internal::Object. We could
5351cb0ef41Sopenharmony_ci    // consider mapping some public API types to their corresponding internal
5361cb0ef41Sopenharmony_ci    // types here, at the possible cost of increased maintenance.
5371cb0ef41Sopenharmony_ci    sp_value_type = Extension::Current()->GetV8ObjectType(sp_ctx);
5381cb0ef41Sopenharmony_ci  }
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci  Location loc;
5411cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_local_instance->GetLocation(&loc));
5421cb0ef41Sopenharmony_ci
5431cb0ef41Sopenharmony_ci  // Read the pointer at the Object location
5441cb0ef41Sopenharmony_ci  ULONG64 obj_address;
5451cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
5461cb0ef41Sopenharmony_ci      sp_debug_host_memory->ReadPointers(sp_ctx.Get(), loc, 1, &obj_address));
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci  // If the val_ is a nullptr, then there is no value in the Local.
5491cb0ef41Sopenharmony_ci  if (obj_address == 0) {
5501cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(CreateString(std::u16string{u"<empty>"}, pp_value));
5511cb0ef41Sopenharmony_ci  } else {
5521cb0ef41Sopenharmony_ci    // Should be a v8::internal::Object at the address
5531cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(sp_data_model_manager->CreateTypedObject(
5541cb0ef41Sopenharmony_ci        sp_ctx.Get(), obj_address, sp_value_type.Get(), pp_value));
5551cb0ef41Sopenharmony_ci  }
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ci  return S_OK;
5581cb0ef41Sopenharmony_ci}
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalValueProperty::SetValue(
5611cb0ef41Sopenharmony_ci    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
5621cb0ef41Sopenharmony_ci    IModelObject* /*p_value*/) noexcept {
5631cb0ef41Sopenharmony_ci  return E_NOTIMPL;
5641cb0ef41Sopenharmony_ci}
5651cb0ef41Sopenharmony_ci
5661cb0ef41Sopenharmony_ciIFACEMETHODIMP V8InternalCompilerNodeIdProperty::GetValue(
5671cb0ef41Sopenharmony_ci    PCWSTR pwsz_key, IModelObject* p_v8_compiler_node_instance,
5681cb0ef41Sopenharmony_ci    IModelObject** pp_value) noexcept {
5691cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> sp_bit_field;
5701cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_compiler_node_instance->GetRawValue(
5711cb0ef41Sopenharmony_ci      SymbolKind::SymbolField, L"bit_field_", RawSearchNone, &sp_bit_field));
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci  uint64_t bit_field_value;
5741cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
5751cb0ef41Sopenharmony_ci      UnboxULong64(sp_bit_field.Get(), &bit_field_value, true /*convert*/));
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> sp_host_context;
5781cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_compiler_node_instance->GetContext(&sp_host_context));
5791cb0ef41Sopenharmony_ci
5801cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> sp_id_field_type;
5811cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(Extension::Current()
5821cb0ef41Sopenharmony_ci                     ->GetV8Module(sp_host_context)
5831cb0ef41Sopenharmony_ci                     ->FindTypeByName(L"v8::internal::compiler::Node::IdField",
5841cb0ef41Sopenharmony_ci                                      &sp_id_field_type));
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci  // Get 2nd template parameter as 24 in class.
5871cb0ef41Sopenharmony_ci  // v8::base::BitField<v8::internal::compiler::NodeId, 0, 24>.
5881cb0ef41Sopenharmony_ci  bool is_generic;
5891cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_id_field_type->IsGeneric(&is_generic));
5901cb0ef41Sopenharmony_ci  if (!is_generic) return E_FAIL;
5911cb0ef41Sopenharmony_ci
5921cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostSymbol> sp_k_size_arg;
5931cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_id_field_type->GetGenericArgumentAt(2, &sp_k_size_arg));
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostConstant> sp_k_size_constant;
5961cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_k_size_arg.As(&sp_k_size_constant));
5971cb0ef41Sopenharmony_ci
5981cb0ef41Sopenharmony_ci  int k_size;
5991cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(GetInt32(sp_k_size_constant.Get(), &k_size));
6001cb0ef41Sopenharmony_ci
6011cb0ef41Sopenharmony_ci  // Compute node_id.
6021cb0ef41Sopenharmony_ci  uint32_t node_id = bit_field_value & (0xFFFFFFFF >> k_size);
6031cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(CreateUInt32(node_id, pp_value));
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  return S_OK;
6061cb0ef41Sopenharmony_ci}
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ciIFACEMETHODIMP V8InternalCompilerNodeIdProperty::SetValue(
6091cb0ef41Sopenharmony_ci    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
6101cb0ef41Sopenharmony_ci    IModelObject* /*p_value*/) noexcept {
6111cb0ef41Sopenharmony_ci  return E_NOTIMPL;
6121cb0ef41Sopenharmony_ci}
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ciIFACEMETHODIMP V8InternalCompilerBitsetNameProperty::GetValue(
6151cb0ef41Sopenharmony_ci    PCWSTR pwsz_key, IModelObject* p_v8_compiler_type_instance,
6161cb0ef41Sopenharmony_ci    IModelObject** pp_value) noexcept {
6171cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> sp_payload;
6181cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(p_v8_compiler_type_instance->GetRawValue(
6191cb0ef41Sopenharmony_ci      SymbolKind::SymbolField, L"payload_", RawSearchNone, &sp_payload));
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_ci  uint64_t payload_value;
6221cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
6231cb0ef41Sopenharmony_ci      UnboxULong64(sp_payload.Get(), &payload_value, true /*convert*/));
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_ci  const char* bitset_name = ::BitsetName(payload_value);
6261cb0ef41Sopenharmony_ci  if (!bitset_name) return E_FAIL;
6271cb0ef41Sopenharmony_ci  std::string name(bitset_name);
6281cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(CreateString(ConvertToU16String(name), pp_value));
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci  return S_OK;
6311cb0ef41Sopenharmony_ci}
6321cb0ef41Sopenharmony_ci
6331cb0ef41Sopenharmony_ciIFACEMETHODIMP V8InternalCompilerBitsetNameProperty::SetValue(
6341cb0ef41Sopenharmony_ci    PCWSTR /*pwsz_key*/, IModelObject* /*p_process_instance*/,
6351cb0ef41Sopenharmony_ci    IModelObject* /*p_value*/) noexcept {
6361cb0ef41Sopenharmony_ci  return E_NOTIMPL;
6371cb0ef41Sopenharmony_ci}
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ciconstexpr wchar_t usage[] =
6401cb0ef41Sopenharmony_ci    LR"(Invalid arguments.
6411cb0ef41Sopenharmony_ciFirst argument should be a uint64 representing the tagged value to investigate.
6421cb0ef41Sopenharmony_ciSecond argument is optional, and may be a fully-qualified type name such as
6431cb0ef41Sopenharmony_civ8::internal::String.)";
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ciIFACEMETHODIMP InspectV8ObjectMethod::Call(IModelObject* p_context_object,
6461cb0ef41Sopenharmony_ci                                           ULONG64 arg_count,
6471cb0ef41Sopenharmony_ci                                           _In_reads_(arg_count)
6481cb0ef41Sopenharmony_ci                                               IModelObject** pp_arguments,
6491cb0ef41Sopenharmony_ci                                           IModelObject** pp_result,
6501cb0ef41Sopenharmony_ci                                           IKeyStore** pp_metadata) noexcept {
6511cb0ef41Sopenharmony_ci  // Read the arguments.
6521cb0ef41Sopenharmony_ci  ULONG64 tagged_value;
6531cb0ef41Sopenharmony_ci  _bstr_t type_name;
6541cb0ef41Sopenharmony_ci  if (arg_count < 1 ||
6551cb0ef41Sopenharmony_ci      FAILED(UnboxULong64(pp_arguments[0], &tagged_value, /*convert=*/true)) ||
6561cb0ef41Sopenharmony_ci      (arg_count >= 2 &&
6571cb0ef41Sopenharmony_ci       FAILED(UnboxString(pp_arguments[1], type_name.GetAddress())))) {
6581cb0ef41Sopenharmony_ci    sp_data_model_manager->CreateErrorObject(E_INVALIDARG, usage, pp_result);
6591cb0ef41Sopenharmony_ci    return E_INVALIDARG;
6601cb0ef41Sopenharmony_ci  }
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> sp_ctx;
6631cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_debug_host->GetCurrentContext(&sp_ctx));
6641cb0ef41Sopenharmony_ci
6651cb0ef41Sopenharmony_ci  // We can't use CreateTypedObject for a value which may not actually reside
6661cb0ef41Sopenharmony_ci  // anywhere in memory, so create a synthetic object.
6671cb0ef41Sopenharmony_ci  WRL::ComPtr<V8CachedObject> cached_object =
6681cb0ef41Sopenharmony_ci      WRL::Make<V8CachedObject>(::GetHeapObject(
6691cb0ef41Sopenharmony_ci          sp_ctx, tagged_value, 0, static_cast<const char*>(type_name),
6701cb0ef41Sopenharmony_ci          /*is_compressed=*/false));
6711cb0ef41Sopenharmony_ci  return CreateSyntheticObjectForV8Object(sp_ctx.Get(), cached_object.Get(),
6721cb0ef41Sopenharmony_ci                                          pp_result);
6731cb0ef41Sopenharmony_ci}
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_ci// Creates an IModelObject representing the data in the given property.
6761cb0ef41Sopenharmony_ciHRESULT GetModelForProperty(const Property& prop,
6771cb0ef41Sopenharmony_ci                            WRL::ComPtr<IDebugHostContext>& sp_ctx,
6781cb0ef41Sopenharmony_ci                            IModelObject** result) {
6791cb0ef41Sopenharmony_ci  switch (prop.type) {
6801cb0ef41Sopenharmony_ci    case PropertyType::kPointer:
6811cb0ef41Sopenharmony_ci      return GetModelForBasicField(prop.addr_value, prop.type_name,
6821cb0ef41Sopenharmony_ci                                   prop.uncompressed_type_name, sp_ctx, result);
6831cb0ef41Sopenharmony_ci    case PropertyType::kStruct:
6841cb0ef41Sopenharmony_ci      return GetModelForStruct(prop.addr_value, prop.fields, sp_ctx, result);
6851cb0ef41Sopenharmony_ci    case PropertyType::kArray:
6861cb0ef41Sopenharmony_ci    case PropertyType::kStructArray:
6871cb0ef41Sopenharmony_ci      if (prop.type == PropertyType::kArray &&
6881cb0ef41Sopenharmony_ci          prop.type_name == ConvertToU16String(prop.uncompressed_type_name)) {
6891cb0ef41Sopenharmony_ci        // An array of things that are not structs or compressed tagged values
6901cb0ef41Sopenharmony_ci        // is most cleanly represented by a native array.
6911cb0ef41Sopenharmony_ci        return GetModelForNativeArray(prop.addr_value, prop.type_name,
6921cb0ef41Sopenharmony_ci                                      prop.length, sp_ctx, result);
6931cb0ef41Sopenharmony_ci      }
6941cb0ef41Sopenharmony_ci      // Otherwise, we must construct a custom iterable object.
6951cb0ef41Sopenharmony_ci      return GetModelForCustomArray(prop, sp_ctx, result);
6961cb0ef41Sopenharmony_ci    default:
6971cb0ef41Sopenharmony_ci      return E_FAIL;
6981cb0ef41Sopenharmony_ci  }
6991cb0ef41Sopenharmony_ci}
700