11cb0ef41Sopenharmony_ci// Copyright 2019 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 "src/flags/flags.h"
61cb0ef41Sopenharmony_ci#include "src/torque/implementation-visitor.h"
71cb0ef41Sopenharmony_ci#include "src/torque/type-oracle.h"
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_cinamespace v8 {
101cb0ef41Sopenharmony_cinamespace internal {
111cb0ef41Sopenharmony_cinamespace torque {
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciconstexpr char kTqObjectOverrideDecls[] =
141cb0ef41Sopenharmony_ci    R"(  std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
151cb0ef41Sopenharmony_ci      d::MemoryAccessor accessor) const override;
161cb0ef41Sopenharmony_ci  const char* GetName() const override;
171cb0ef41Sopenharmony_ci  void Visit(TqObjectVisitor* visitor) const override;
181cb0ef41Sopenharmony_ci  bool IsSuperclassOf(const TqObject* other) const override;
191cb0ef41Sopenharmony_ci)";
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciconstexpr char kObjectClassListDefinition[] = R"(
221cb0ef41Sopenharmony_ciconst d::ClassList kObjectClassList {
231cb0ef41Sopenharmony_ci  sizeof(kObjectClassNames) / sizeof(const char*),
241cb0ef41Sopenharmony_ci  kObjectClassNames,
251cb0ef41Sopenharmony_ci};
261cb0ef41Sopenharmony_ci)";
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_cinamespace {
291cb0ef41Sopenharmony_cienum TypeStorage {
301cb0ef41Sopenharmony_ci  kAsStoredInHeap,
311cb0ef41Sopenharmony_ci  kUncompressed,
321cb0ef41Sopenharmony_ci};
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci// An iterator for use in ValueTypeFieldsRange.
351cb0ef41Sopenharmony_ciclass ValueTypeFieldIterator {
361cb0ef41Sopenharmony_ci public:
371cb0ef41Sopenharmony_ci  ValueTypeFieldIterator(const Type* type, size_t index)
381cb0ef41Sopenharmony_ci      : type_(type), index_(index) {}
391cb0ef41Sopenharmony_ci  struct Result {
401cb0ef41Sopenharmony_ci    NameAndType name_and_type;
411cb0ef41Sopenharmony_ci    SourcePosition pos;
421cb0ef41Sopenharmony_ci    size_t offset_bytes;
431cb0ef41Sopenharmony_ci    int num_bits;
441cb0ef41Sopenharmony_ci    int shift_bits;
451cb0ef41Sopenharmony_ci  };
461cb0ef41Sopenharmony_ci  const Result operator*() const {
471cb0ef41Sopenharmony_ci    if (auto struct_type = type_->StructSupertype()) {
481cb0ef41Sopenharmony_ci      const auto& field = (*struct_type)->fields()[index_];
491cb0ef41Sopenharmony_ci      return {field.name_and_type, field.pos, *field.offset, 0, 0};
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci    const Type* type = type_;
521cb0ef41Sopenharmony_ci    int bitfield_start_offset = 0;
531cb0ef41Sopenharmony_ci    if (const auto type_wrapped_in_smi =
541cb0ef41Sopenharmony_ci            Type::MatchUnaryGeneric(type_, TypeOracle::GetSmiTaggedGeneric())) {
551cb0ef41Sopenharmony_ci      type = *type_wrapped_in_smi;
561cb0ef41Sopenharmony_ci      bitfield_start_offset = TargetArchitecture::SmiTagAndShiftSize();
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci    if (const BitFieldStructType* bit_field_struct_type =
591cb0ef41Sopenharmony_ci            BitFieldStructType::DynamicCast(type)) {
601cb0ef41Sopenharmony_ci      const auto& field = bit_field_struct_type->fields()[index_];
611cb0ef41Sopenharmony_ci      return {field.name_and_type, field.pos, 0, field.num_bits,
621cb0ef41Sopenharmony_ci              field.offset + bitfield_start_offset};
631cb0ef41Sopenharmony_ci    }
641cb0ef41Sopenharmony_ci    UNREACHABLE();
651cb0ef41Sopenharmony_ci  }
661cb0ef41Sopenharmony_ci  ValueTypeFieldIterator& operator++() {
671cb0ef41Sopenharmony_ci    ++index_;
681cb0ef41Sopenharmony_ci    return *this;
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci  bool operator==(const ValueTypeFieldIterator& other) const {
711cb0ef41Sopenharmony_ci    return type_ == other.type_ && index_ == other.index_;
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci  bool operator!=(const ValueTypeFieldIterator& other) const {
741cb0ef41Sopenharmony_ci    return !(*this == other);
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci private:
781cb0ef41Sopenharmony_ci  const Type* type_;
791cb0ef41Sopenharmony_ci  size_t index_;
801cb0ef41Sopenharmony_ci};
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci// A way to iterate over the fields of structs or bitfield structs. For other
831cb0ef41Sopenharmony_ci// types, the iterators returned from begin() and end() are immediately equal.
841cb0ef41Sopenharmony_ciclass ValueTypeFieldsRange {
851cb0ef41Sopenharmony_ci public:
861cb0ef41Sopenharmony_ci  explicit ValueTypeFieldsRange(const Type* type) : type_(type) {}
871cb0ef41Sopenharmony_ci  ValueTypeFieldIterator begin() { return {type_, 0}; }
881cb0ef41Sopenharmony_ci  ValueTypeFieldIterator end() {
891cb0ef41Sopenharmony_ci    size_t index = 0;
901cb0ef41Sopenharmony_ci    base::Optional<const StructType*> struct_type = type_->StructSupertype();
911cb0ef41Sopenharmony_ci    if (struct_type && *struct_type != TypeOracle::GetFloat64OrHoleType()) {
921cb0ef41Sopenharmony_ci      index = (*struct_type)->fields().size();
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci    const Type* type = type_;
951cb0ef41Sopenharmony_ci    if (const auto type_wrapped_in_smi =
961cb0ef41Sopenharmony_ci            Type::MatchUnaryGeneric(type_, TypeOracle::GetSmiTaggedGeneric())) {
971cb0ef41Sopenharmony_ci      type = *type_wrapped_in_smi;
981cb0ef41Sopenharmony_ci    }
991cb0ef41Sopenharmony_ci    if (const BitFieldStructType* bit_field_struct_type =
1001cb0ef41Sopenharmony_ci            BitFieldStructType::DynamicCast(type)) {
1011cb0ef41Sopenharmony_ci      index = bit_field_struct_type->fields().size();
1021cb0ef41Sopenharmony_ci    }
1031cb0ef41Sopenharmony_ci    return {type_, index};
1041cb0ef41Sopenharmony_ci  }
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci private:
1071cb0ef41Sopenharmony_ci  const Type* type_;
1081cb0ef41Sopenharmony_ci};
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci// A convenient way to keep track of several different ways that we might need
1111cb0ef41Sopenharmony_ci// to represent a field's type in the generated C++.
1121cb0ef41Sopenharmony_ciclass DebugFieldType {
1131cb0ef41Sopenharmony_ci public:
1141cb0ef41Sopenharmony_ci  explicit DebugFieldType(const Field& field)
1151cb0ef41Sopenharmony_ci      : name_and_type_(field.name_and_type), pos_(field.pos) {}
1161cb0ef41Sopenharmony_ci  DebugFieldType(const NameAndType& name_and_type, const SourcePosition& pos)
1171cb0ef41Sopenharmony_ci      : name_and_type_(name_and_type), pos_(pos) {}
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  bool IsTagged() const {
1201cb0ef41Sopenharmony_ci    return name_and_type_.type->IsSubtypeOf(TypeOracle::GetTaggedType());
1211cb0ef41Sopenharmony_ci  }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  // Returns the type that should be used for this field's value within code
1241cb0ef41Sopenharmony_ci  // that is compiled as part of the debug helper library. In particular, this
1251cb0ef41Sopenharmony_ci  // simplifies any tagged type to a plain uintptr_t because the debug helper
1261cb0ef41Sopenharmony_ci  // compiles without most of the V8 runtime code.
1271cb0ef41Sopenharmony_ci  std::string GetValueType(TypeStorage storage) const {
1281cb0ef41Sopenharmony_ci    if (IsTagged()) {
1291cb0ef41Sopenharmony_ci      return storage == kAsStoredInHeap ? "i::Tagged_t" : "uintptr_t";
1301cb0ef41Sopenharmony_ci    }
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci    // We can't emit a useful error at this point if the constexpr type name is
1331cb0ef41Sopenharmony_ci    // wrong, but we can include a comment that might be helpful.
1341cb0ef41Sopenharmony_ci    return GetOriginalType(storage) +
1351cb0ef41Sopenharmony_ci           " /*Failing? Ensure constexpr type name is correct, and the "
1361cb0ef41Sopenharmony_ci           "necessary #include is in any .tq file*/";
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  // Returns the type that should be used to represent a field's type to
1401cb0ef41Sopenharmony_ci  // debugging tools that have full V8 symbols. The types returned from this
1411cb0ef41Sopenharmony_ci  // method are resolveable in the v8::internal namespace and may refer to
1421cb0ef41Sopenharmony_ci  // object types that are not included in the compilation of the debug helper
1431cb0ef41Sopenharmony_ci  // library.
1441cb0ef41Sopenharmony_ci  std::string GetOriginalType(TypeStorage storage) const {
1451cb0ef41Sopenharmony_ci    if (name_and_type_.type->StructSupertype()) {
1461cb0ef41Sopenharmony_ci      // There's no meaningful type we could use here, because the V8 symbols
1471cb0ef41Sopenharmony_ci      // don't have any definition of a C++ struct matching this struct type.
1481cb0ef41Sopenharmony_ci      return "";
1491cb0ef41Sopenharmony_ci    }
1501cb0ef41Sopenharmony_ci    if (IsTagged()) {
1511cb0ef41Sopenharmony_ci      if (storage == kAsStoredInHeap &&
1521cb0ef41Sopenharmony_ci          TargetArchitecture::ArePointersCompressed()) {
1531cb0ef41Sopenharmony_ci        return "v8::internal::TaggedValue";
1541cb0ef41Sopenharmony_ci      }
1551cb0ef41Sopenharmony_ci      base::Optional<const ClassType*> field_class_type =
1561cb0ef41Sopenharmony_ci          name_and_type_.type->ClassSupertype();
1571cb0ef41Sopenharmony_ci      return "v8::internal::" +
1581cb0ef41Sopenharmony_ci             (field_class_type.has_value()
1591cb0ef41Sopenharmony_ci                  ? (*field_class_type)->GetGeneratedTNodeTypeName()
1601cb0ef41Sopenharmony_ci                  : "Object");
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci    return name_and_type_.type->GetConstexprGeneratedTypeName();
1631cb0ef41Sopenharmony_ci  }
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci  // Returns a C++ expression that evaluates to a string (type `const char*`)
1661cb0ef41Sopenharmony_ci  // containing the name of the field's type. The types returned from this
1671cb0ef41Sopenharmony_ci  // method are resolveable in the v8::internal namespace and may refer to
1681cb0ef41Sopenharmony_ci  // object types that are not included in the compilation of the debug helper
1691cb0ef41Sopenharmony_ci  // library.
1701cb0ef41Sopenharmony_ci  std::string GetTypeString(TypeStorage storage) const {
1711cb0ef41Sopenharmony_ci    if (IsTagged() || name_and_type_.type->IsStructType()) {
1721cb0ef41Sopenharmony_ci      // Wrap up the original type in a string literal.
1731cb0ef41Sopenharmony_ci      return "\"" + GetOriginalType(storage) + "\"";
1741cb0ef41Sopenharmony_ci    }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    // We require constexpr type names to be resolvable in the v8::internal
1771cb0ef41Sopenharmony_ci    // namespace, according to the contract in debug-helper.h. In order to
1781cb0ef41Sopenharmony_ci    // verify at compile time that constexpr type names are resolvable, we use
1791cb0ef41Sopenharmony_ci    // the type name as a dummy template parameter to a function that just
1801cb0ef41Sopenharmony_ci    // returns its parameter.
1811cb0ef41Sopenharmony_ci    return "CheckTypeName<" + GetValueType(storage) + ">(\"" +
1821cb0ef41Sopenharmony_ci           GetOriginalType(storage) + "\")";
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  // Returns the field's size in bytes.
1861cb0ef41Sopenharmony_ci  size_t GetSize() const {
1871cb0ef41Sopenharmony_ci    auto opt_size = SizeOf(name_and_type_.type);
1881cb0ef41Sopenharmony_ci    if (!opt_size.has_value()) {
1891cb0ef41Sopenharmony_ci      Error("Size required for type ", name_and_type_.type->ToString())
1901cb0ef41Sopenharmony_ci          .Position(pos_);
1911cb0ef41Sopenharmony_ci      return 0;
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci    return std::get<0>(*opt_size);
1941cb0ef41Sopenharmony_ci  }
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci  // Returns the name of the function for getting this field's address.
1971cb0ef41Sopenharmony_ci  std::string GetAddressGetter() {
1981cb0ef41Sopenharmony_ci    return "Get" + CamelifyString(name_and_type_.name) + "Address";
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci private:
2021cb0ef41Sopenharmony_ci  NameAndType name_and_type_;
2031cb0ef41Sopenharmony_ci  SourcePosition pos_;
2041cb0ef41Sopenharmony_ci};
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci// Emits a function to get the address of a field within a class, based on the
2071cb0ef41Sopenharmony_ci// member variable {address_}, which is a tagged pointer. Example
2081cb0ef41Sopenharmony_ci// implementation:
2091cb0ef41Sopenharmony_ci//
2101cb0ef41Sopenharmony_ci// uintptr_t TqFixedArray::GetObjectsAddress() const {
2111cb0ef41Sopenharmony_ci//   return address_ - i::kHeapObjectTag + 16;
2121cb0ef41Sopenharmony_ci// }
2131cb0ef41Sopenharmony_civoid GenerateFieldAddressAccessor(const Field& field,
2141cb0ef41Sopenharmony_ci                                  const std::string& class_name,
2151cb0ef41Sopenharmony_ci                                  std::ostream& h_contents,
2161cb0ef41Sopenharmony_ci                                  std::ostream& cc_contents) {
2171cb0ef41Sopenharmony_ci  DebugFieldType debug_field_type(field);
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  const std::string address_getter = debug_field_type.GetAddressGetter();
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  h_contents << "  uintptr_t " << address_getter << "() const;\n";
2221cb0ef41Sopenharmony_ci  cc_contents << "\nuintptr_t Tq" << class_name << "::" << address_getter
2231cb0ef41Sopenharmony_ci              << "() const {\n";
2241cb0ef41Sopenharmony_ci  cc_contents << "  return address_ - i::kHeapObjectTag + " << *field.offset
2251cb0ef41Sopenharmony_ci              << ";\n";
2261cb0ef41Sopenharmony_ci  cc_contents << "}\n";
2271cb0ef41Sopenharmony_ci}
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci// Emits a function to get the value of a field, or the value from an indexed
2301cb0ef41Sopenharmony_ci// position within an array field, based on the member variable {address_},
2311cb0ef41Sopenharmony_ci// which is a tagged pointer, and the parameter {accessor}, a function pointer
2321cb0ef41Sopenharmony_ci// that allows for fetching memory from the debuggee. The returned result
2331cb0ef41Sopenharmony_ci// includes both a "validity", indicating whether the memory could be fetched,
2341cb0ef41Sopenharmony_ci// and the fetched value. If the field contains tagged data, then these
2351cb0ef41Sopenharmony_ci// functions call EnsureDecompressed to expand compressed data. Example:
2361cb0ef41Sopenharmony_ci//
2371cb0ef41Sopenharmony_ci// Value<uintptr_t> TqMap::GetPrototypeValue(d::MemoryAccessor accessor) const {
2381cb0ef41Sopenharmony_ci//   i::Tagged_t value{};
2391cb0ef41Sopenharmony_ci//   d::MemoryAccessResult validity = accessor(
2401cb0ef41Sopenharmony_ci//       GetPrototypeAddress(),
2411cb0ef41Sopenharmony_ci//       reinterpret_cast<uint8_t*>(&value),
2421cb0ef41Sopenharmony_ci//       sizeof(value));
2431cb0ef41Sopenharmony_ci//   return {validity, EnsureDecompressed(value, address_)};
2441cb0ef41Sopenharmony_ci// }
2451cb0ef41Sopenharmony_ci//
2461cb0ef41Sopenharmony_ci// For array fields, an offset parameter is included. Example:
2471cb0ef41Sopenharmony_ci//
2481cb0ef41Sopenharmony_ci// Value<uintptr_t> TqFixedArray::GetObjectsValue(d::MemoryAccessor accessor,
2491cb0ef41Sopenharmony_ci//                                                size_t offset) const {
2501cb0ef41Sopenharmony_ci//   i::Tagged_t value{};
2511cb0ef41Sopenharmony_ci//   d::MemoryAccessResult validity = accessor(
2521cb0ef41Sopenharmony_ci//       GetObjectsAddress() + offset * sizeof(value),
2531cb0ef41Sopenharmony_ci//       reinterpret_cast<uint8_t*>(&value),
2541cb0ef41Sopenharmony_ci//       sizeof(value));
2551cb0ef41Sopenharmony_ci//   return {validity, EnsureDecompressed(value, address_)};
2561cb0ef41Sopenharmony_ci// }
2571cb0ef41Sopenharmony_civoid GenerateFieldValueAccessor(const Field& field,
2581cb0ef41Sopenharmony_ci                                const std::string& class_name,
2591cb0ef41Sopenharmony_ci                                std::ostream& h_contents,
2601cb0ef41Sopenharmony_ci                                std::ostream& cc_contents) {
2611cb0ef41Sopenharmony_ci  // Currently not implemented for struct fields.
2621cb0ef41Sopenharmony_ci  if (field.name_and_type.type->StructSupertype()) return;
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci  DebugFieldType debug_field_type(field);
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci  const std::string address_getter = debug_field_type.GetAddressGetter();
2671cb0ef41Sopenharmony_ci  const std::string field_getter =
2681cb0ef41Sopenharmony_ci      "Get" + CamelifyString(field.name_and_type.name) + "Value";
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  std::string index_param;
2711cb0ef41Sopenharmony_ci  std::string index_offset;
2721cb0ef41Sopenharmony_ci  if (field.index) {
2731cb0ef41Sopenharmony_ci    index_param = ", size_t offset";
2741cb0ef41Sopenharmony_ci    index_offset = " + offset * sizeof(value)";
2751cb0ef41Sopenharmony_ci  }
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  std::string field_value_type = debug_field_type.GetValueType(kUncompressed);
2781cb0ef41Sopenharmony_ci  h_contents << "  Value<" << field_value_type << "> " << field_getter
2791cb0ef41Sopenharmony_ci             << "(d::MemoryAccessor accessor " << index_param << ") const;\n";
2801cb0ef41Sopenharmony_ci  cc_contents << "\nValue<" << field_value_type << "> Tq" << class_name
2811cb0ef41Sopenharmony_ci              << "::" << field_getter << "(d::MemoryAccessor accessor"
2821cb0ef41Sopenharmony_ci              << index_param << ") const {\n";
2831cb0ef41Sopenharmony_ci  cc_contents << "  " << debug_field_type.GetValueType(kAsStoredInHeap)
2841cb0ef41Sopenharmony_ci              << " value{};\n";
2851cb0ef41Sopenharmony_ci  cc_contents << "  d::MemoryAccessResult validity = accessor("
2861cb0ef41Sopenharmony_ci              << address_getter << "()" << index_offset
2871cb0ef41Sopenharmony_ci              << ", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
2881cb0ef41Sopenharmony_ci#ifdef V8_MAP_PACKING
2891cb0ef41Sopenharmony_ci  if (field_getter == "GetMapValue") {
2901cb0ef41Sopenharmony_ci    cc_contents << "  value = i::MapWord::Unpack(value);\n";
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci#endif
2931cb0ef41Sopenharmony_ci  cc_contents << "  return {validity, "
2941cb0ef41Sopenharmony_ci              << (debug_field_type.IsTagged()
2951cb0ef41Sopenharmony_ci                      ? "EnsureDecompressed(value, address_)"
2961cb0ef41Sopenharmony_ci                      : "value")
2971cb0ef41Sopenharmony_ci              << "};\n";
2981cb0ef41Sopenharmony_ci  cc_contents << "}\n";
2991cb0ef41Sopenharmony_ci}
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci// Emits a portion of the member function GetProperties that is responsible for
3021cb0ef41Sopenharmony_ci// adding data about the current field to a result vector called "result".
3031cb0ef41Sopenharmony_ci// Example output:
3041cb0ef41Sopenharmony_ci//
3051cb0ef41Sopenharmony_ci// std::vector<std::unique_ptr<StructProperty>> prototype_struct_field_list;
3061cb0ef41Sopenharmony_ci// result.push_back(std::make_unique<ObjectProperty>(
3071cb0ef41Sopenharmony_ci//     "prototype",                                     // Field name
3081cb0ef41Sopenharmony_ci//     "v8::internal::HeapObject",                      // Field type
3091cb0ef41Sopenharmony_ci//     "v8::internal::HeapObject",                      // Decompressed type
3101cb0ef41Sopenharmony_ci//     GetPrototypeAddress(),                           // Field address
3111cb0ef41Sopenharmony_ci//     1,                                               // Number of values
3121cb0ef41Sopenharmony_ci//     8,                                               // Size of value
3131cb0ef41Sopenharmony_ci//     std::move(prototype_struct_field_list),          // Struct fields
3141cb0ef41Sopenharmony_ci//     d::PropertyKind::kSingle));                      // Field kind
3151cb0ef41Sopenharmony_ci//
3161cb0ef41Sopenharmony_ci// In builds with pointer compression enabled, the field type for tagged values
3171cb0ef41Sopenharmony_ci// is "v8::internal::TaggedValue" (a four-byte class) and the decompressed type
3181cb0ef41Sopenharmony_ci// is a normal Object subclass that describes the expanded eight-byte type.
3191cb0ef41Sopenharmony_ci//
3201cb0ef41Sopenharmony_ci// If the field is an array, then its length is fetched from the debuggee. This
3211cb0ef41Sopenharmony_ci// could fail if the debuggee has incomplete memory, so the "validity" from that
3221cb0ef41Sopenharmony_ci// fetch is used to determine the result PropertyKind, which will say whether
3231cb0ef41Sopenharmony_ci// the array's length is known.
3241cb0ef41Sopenharmony_ci//
3251cb0ef41Sopenharmony_ci// If the field's type is a struct, then a local variable is created and filled
3261cb0ef41Sopenharmony_ci// with descriptions of each of the struct's fields. The type and decompressed
3271cb0ef41Sopenharmony_ci// type in the ObjectProperty are set to the empty string, to indicate to the
3281cb0ef41Sopenharmony_ci// caller that the struct fields vector should be used instead.
3291cb0ef41Sopenharmony_ci//
3301cb0ef41Sopenharmony_ci// The following example is an array of structs, so it uses both of the optional
3311cb0ef41Sopenharmony_ci// components described above:
3321cb0ef41Sopenharmony_ci//
3331cb0ef41Sopenharmony_ci// std::vector<std::unique_ptr<StructProperty>> descriptors_struct_field_list;
3341cb0ef41Sopenharmony_ci// descriptors_struct_field_list.push_back(std::make_unique<StructProperty>(
3351cb0ef41Sopenharmony_ci//     "key",                                // Struct field name
3361cb0ef41Sopenharmony_ci//     "v8::internal::PrimitiveHeapObject",  // Struct field type
3371cb0ef41Sopenharmony_ci//     "v8::internal::PrimitiveHeapObject",  // Struct field decompressed type
3381cb0ef41Sopenharmony_ci//     0,                                    // Byte offset within struct data
3391cb0ef41Sopenharmony_ci//     0,                                    // Bitfield size (0=not a bitfield)
3401cb0ef41Sopenharmony_ci//     0));                                  // Bitfield shift
3411cb0ef41Sopenharmony_ci// // The line above is repeated for other struct fields. Omitted here.
3421cb0ef41Sopenharmony_ci// // Fetch the slice.
3431cb0ef41Sopenharmony_ci// auto indexed_field_slice_descriptors =
3441cb0ef41Sopenharmony_ci//     TqDebugFieldSliceDescriptorArrayDescriptors(accessor, address_);
3451cb0ef41Sopenharmony_ci// if (indexed_field_slice_descriptors.validity == d::MemoryAccessResult::kOk) {
3461cb0ef41Sopenharmony_ci//   result.push_back(std::make_unique<ObjectProperty>(
3471cb0ef41Sopenharmony_ci//     "descriptors",                                 // Field name
3481cb0ef41Sopenharmony_ci//     "",                                            // Field type
3491cb0ef41Sopenharmony_ci//     "",                                            // Decompressed type
3501cb0ef41Sopenharmony_ci//     address_ - i::kHeapObjectTag +
3511cb0ef41Sopenharmony_ci//     std::get<1>(indexed_field_slice_descriptors.value), // Field address
3521cb0ef41Sopenharmony_ci//     std::get<2>(indexed_field_slice_descriptors.value), // Number of values
3531cb0ef41Sopenharmony_ci//     12,                                            // Size of value
3541cb0ef41Sopenharmony_ci//     std::move(descriptors_struct_field_list),      // Struct fields
3551cb0ef41Sopenharmony_ci//     GetArrayKind(indexed_field_slice_descriptors.validity)));  // Field kind
3561cb0ef41Sopenharmony_ci// }
3571cb0ef41Sopenharmony_civoid GenerateGetPropsChunkForField(const Field& field,
3581cb0ef41Sopenharmony_ci                                   std::ostream& get_props_impl,
3591cb0ef41Sopenharmony_ci                                   std::string class_name) {
3601cb0ef41Sopenharmony_ci  DebugFieldType debug_field_type(field);
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci  // If the current field is a struct or bitfield struct, create a vector
3631cb0ef41Sopenharmony_ci  // describing its fields. Otherwise this vector will be empty.
3641cb0ef41Sopenharmony_ci  std::string struct_field_list =
3651cb0ef41Sopenharmony_ci      field.name_and_type.name + "_struct_field_list";
3661cb0ef41Sopenharmony_ci  get_props_impl << "  std::vector<std::unique_ptr<StructProperty>> "
3671cb0ef41Sopenharmony_ci                 << struct_field_list << ";\n";
3681cb0ef41Sopenharmony_ci  for (const auto& struct_field :
3691cb0ef41Sopenharmony_ci       ValueTypeFieldsRange(field.name_and_type.type)) {
3701cb0ef41Sopenharmony_ci    DebugFieldType struct_field_type(struct_field.name_and_type,
3711cb0ef41Sopenharmony_ci                                     struct_field.pos);
3721cb0ef41Sopenharmony_ci    get_props_impl << "  " << struct_field_list
3731cb0ef41Sopenharmony_ci                   << ".push_back(std::make_unique<StructProperty>(\""
3741cb0ef41Sopenharmony_ci                   << struct_field.name_and_type.name << "\", "
3751cb0ef41Sopenharmony_ci                   << struct_field_type.GetTypeString(kAsStoredInHeap) << ", "
3761cb0ef41Sopenharmony_ci                   << struct_field_type.GetTypeString(kUncompressed) << ", "
3771cb0ef41Sopenharmony_ci                   << struct_field.offset_bytes << ", " << struct_field.num_bits
3781cb0ef41Sopenharmony_ci                   << ", " << struct_field.shift_bits << "));\n";
3791cb0ef41Sopenharmony_ci  }
3801cb0ef41Sopenharmony_ci  struct_field_list = "std::move(" + struct_field_list + ")";
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci  // The number of values and property kind for non-indexed properties:
3831cb0ef41Sopenharmony_ci  std::string count_value = "1";
3841cb0ef41Sopenharmony_ci  std::string property_kind = "d::PropertyKind::kSingle";
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  // If the field is indexed, emit a fetch of the array length, and change
3871cb0ef41Sopenharmony_ci  // count_value and property_kind to be the correct values for an array.
3881cb0ef41Sopenharmony_ci  if (field.index) {
3891cb0ef41Sopenharmony_ci    std::string indexed_field_slice =
3901cb0ef41Sopenharmony_ci        "indexed_field_slice_" + field.name_and_type.name;
3911cb0ef41Sopenharmony_ci    get_props_impl << "  auto " << indexed_field_slice << " = "
3921cb0ef41Sopenharmony_ci                   << "TqDebugFieldSlice" << class_name
3931cb0ef41Sopenharmony_ci                   << CamelifyString(field.name_and_type.name)
3941cb0ef41Sopenharmony_ci                   << "(accessor, address_);\n";
3951cb0ef41Sopenharmony_ci    std::string validity = indexed_field_slice + ".validity";
3961cb0ef41Sopenharmony_ci    std::string value = indexed_field_slice + ".value";
3971cb0ef41Sopenharmony_ci    property_kind = "GetArrayKind(" + validity + ")";
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci    get_props_impl << "  if (" << validity
4001cb0ef41Sopenharmony_ci                   << " == d::MemoryAccessResult::kOk) {\n"
4011cb0ef41Sopenharmony_ci                   << "    result.push_back(std::make_unique<ObjectProperty>(\""
4021cb0ef41Sopenharmony_ci                   << field.name_and_type.name << "\", "
4031cb0ef41Sopenharmony_ci                   << debug_field_type.GetTypeString(kAsStoredInHeap) << ", "
4041cb0ef41Sopenharmony_ci                   << debug_field_type.GetTypeString(kUncompressed) << ", "
4051cb0ef41Sopenharmony_ci                   << "address_ - i::kHeapObjectTag + std::get<1>(" << value
4061cb0ef41Sopenharmony_ci                   << "), "
4071cb0ef41Sopenharmony_ci                   << "std::get<2>(" << value << ")"
4081cb0ef41Sopenharmony_ci                   << ", " << debug_field_type.GetSize() << ", "
4091cb0ef41Sopenharmony_ci                   << struct_field_list << ", " << property_kind << "));\n"
4101cb0ef41Sopenharmony_ci                   << "  }\n";
4111cb0ef41Sopenharmony_ci    return;
4121cb0ef41Sopenharmony_ci  }
4131cb0ef41Sopenharmony_ci  get_props_impl << "  result.push_back(std::make_unique<ObjectProperty>(\""
4141cb0ef41Sopenharmony_ci                 << field.name_and_type.name << "\", "
4151cb0ef41Sopenharmony_ci                 << debug_field_type.GetTypeString(kAsStoredInHeap) << ", "
4161cb0ef41Sopenharmony_ci                 << debug_field_type.GetTypeString(kUncompressed) << ", "
4171cb0ef41Sopenharmony_ci                 << debug_field_type.GetAddressGetter() << "(), " << count_value
4181cb0ef41Sopenharmony_ci                 << ", " << debug_field_type.GetSize() << ", "
4191cb0ef41Sopenharmony_ci                 << struct_field_list << ", " << property_kind << "));\n";
4201cb0ef41Sopenharmony_ci}
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci// For any Torque-defined class Foo, this function generates a class TqFoo which
4231cb0ef41Sopenharmony_ci// allows for convenient inspection of objects of type Foo in a crash dump or
4241cb0ef41Sopenharmony_ci// time travel session (where we can't just run the object printer). The
4251cb0ef41Sopenharmony_ci// generated class looks something like this:
4261cb0ef41Sopenharmony_ci//
4271cb0ef41Sopenharmony_ci// class TqFoo : public TqParentOfFoo {
4281cb0ef41Sopenharmony_ci//  public:
4291cb0ef41Sopenharmony_ci//   // {address} is an uncompressed tagged pointer.
4301cb0ef41Sopenharmony_ci//   inline TqFoo(uintptr_t address) : TqParentOfFoo(address) {}
4311cb0ef41Sopenharmony_ci//
4321cb0ef41Sopenharmony_ci//   // Creates and returns a list of this object's properties.
4331cb0ef41Sopenharmony_ci//   std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
4341cb0ef41Sopenharmony_ci//       d::MemoryAccessor accessor) const override;
4351cb0ef41Sopenharmony_ci//
4361cb0ef41Sopenharmony_ci//   // Returns the name of this class, "v8::internal::Foo".
4371cb0ef41Sopenharmony_ci//   const char* GetName() const override;
4381cb0ef41Sopenharmony_ci//
4391cb0ef41Sopenharmony_ci//   // Visitor pattern; implementation just calls visitor->VisitFoo(this).
4401cb0ef41Sopenharmony_ci//   void Visit(TqObjectVisitor* visitor) const override;
4411cb0ef41Sopenharmony_ci//
4421cb0ef41Sopenharmony_ci//   // Returns whether Foo is a superclass of the other object's type.
4431cb0ef41Sopenharmony_ci//   bool IsSuperclassOf(const TqObject* other) const override;
4441cb0ef41Sopenharmony_ci//
4451cb0ef41Sopenharmony_ci//   // Field accessors omitted here (see other comments above).
4461cb0ef41Sopenharmony_ci// };
4471cb0ef41Sopenharmony_ci//
4481cb0ef41Sopenharmony_ci// Four output streams are written:
4491cb0ef41Sopenharmony_ci//
4501cb0ef41Sopenharmony_ci// h_contents:  A header file which gets the class definition above.
4511cb0ef41Sopenharmony_ci// cc_contents: A cc file which gets implementations of that class's members.
4521cb0ef41Sopenharmony_ci// visitor:     A stream that is accumulating the definition of the class
4531cb0ef41Sopenharmony_ci//              TqObjectVisitor. Each class Foo gets its own virtual method
4541cb0ef41Sopenharmony_ci//              VisitFoo in TqObjectVisitor.
4551cb0ef41Sopenharmony_ci// class_names: A stream that is accumulating a list of strings including fully-
4561cb0ef41Sopenharmony_ci//              qualified names for every Torque-defined class type.
4571cb0ef41Sopenharmony_civoid GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents,
4581cb0ef41Sopenharmony_ci                              std::ostream& cc_contents, std::ostream& visitor,
4591cb0ef41Sopenharmony_ci                              std::ostream& class_names,
4601cb0ef41Sopenharmony_ci                              std::unordered_set<const ClassType*>* done) {
4611cb0ef41Sopenharmony_ci  // Make sure each class only gets generated once.
4621cb0ef41Sopenharmony_ci  if (!done->insert(&type).second) return;
4631cb0ef41Sopenharmony_ci  const ClassType* super_type = type.GetSuperClass();
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci  // We must emit the classes in dependency order. If the super class hasn't
4661cb0ef41Sopenharmony_ci  // been emitted yet, go handle it first.
4671cb0ef41Sopenharmony_ci  if (super_type != nullptr) {
4681cb0ef41Sopenharmony_ci    GenerateClassDebugReader(*super_type, h_contents, cc_contents, visitor,
4691cb0ef41Sopenharmony_ci                             class_names, done);
4701cb0ef41Sopenharmony_ci  }
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci  // Classes with undefined layout don't grant any particular value here and may
4731cb0ef41Sopenharmony_ci  // not correspond with actual C++ classes, so skip them.
4741cb0ef41Sopenharmony_ci  if (type.HasUndefinedLayout()) return;
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  const std::string name = type.name();
4771cb0ef41Sopenharmony_ci  const std::string super_name =
4781cb0ef41Sopenharmony_ci      super_type == nullptr ? "Object" : super_type->name();
4791cb0ef41Sopenharmony_ci  h_contents << "\nclass Tq" << name << " : public Tq" << super_name << " {\n";
4801cb0ef41Sopenharmony_ci  h_contents << " public:\n";
4811cb0ef41Sopenharmony_ci  h_contents << "  inline Tq" << name << "(uintptr_t address) : Tq"
4821cb0ef41Sopenharmony_ci             << super_name << "(address) {}\n";
4831cb0ef41Sopenharmony_ci  h_contents << kTqObjectOverrideDecls;
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci  cc_contents << "\nconst char* Tq" << name << "::GetName() const {\n";
4861cb0ef41Sopenharmony_ci  cc_contents << "  return \"v8::internal::" << name << "\";\n";
4871cb0ef41Sopenharmony_ci  cc_contents << "}\n";
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_ci  cc_contents << "\nvoid Tq" << name
4901cb0ef41Sopenharmony_ci              << "::Visit(TqObjectVisitor* visitor) const {\n";
4911cb0ef41Sopenharmony_ci  cc_contents << "  visitor->Visit" << name << "(this);\n";
4921cb0ef41Sopenharmony_ci  cc_contents << "}\n";
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci  cc_contents << "\nbool Tq" << name
4951cb0ef41Sopenharmony_ci              << "::IsSuperclassOf(const TqObject* other) const {\n";
4961cb0ef41Sopenharmony_ci  cc_contents
4971cb0ef41Sopenharmony_ci      << "  return GetName() != other->GetName() && dynamic_cast<const Tq"
4981cb0ef41Sopenharmony_ci      << name << "*>(other) != nullptr;\n";
4991cb0ef41Sopenharmony_ci  cc_contents << "}\n";
5001cb0ef41Sopenharmony_ci
5011cb0ef41Sopenharmony_ci  // By default, the visitor method for this class just calls the visitor method
5021cb0ef41Sopenharmony_ci  // for this class's parent. This allows custom visitors to only override a few
5031cb0ef41Sopenharmony_ci  // classes they care about without needing to know about the entire hierarchy.
5041cb0ef41Sopenharmony_ci  visitor << "  virtual void Visit" << name << "(const Tq" << name
5051cb0ef41Sopenharmony_ci          << "* object) {\n";
5061cb0ef41Sopenharmony_ci  visitor << "    Visit" << super_name << "(object);\n";
5071cb0ef41Sopenharmony_ci  visitor << "  }\n";
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci  class_names << "  \"v8::internal::" << name << "\",\n";
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci  std::stringstream get_props_impl;
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci  for (const Field& field : type.fields()) {
5141cb0ef41Sopenharmony_ci    if (field.name_and_type.type == TypeOracle::GetVoidType()) continue;
5151cb0ef41Sopenharmony_ci    if (field.offset.has_value()) {
5161cb0ef41Sopenharmony_ci      GenerateFieldAddressAccessor(field, name, h_contents, cc_contents);
5171cb0ef41Sopenharmony_ci      GenerateFieldValueAccessor(field, name, h_contents, cc_contents);
5181cb0ef41Sopenharmony_ci    }
5191cb0ef41Sopenharmony_ci    GenerateGetPropsChunkForField(field, get_props_impl, name);
5201cb0ef41Sopenharmony_ci  }
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_ci  h_contents << "};\n";
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci  cc_contents << "\nstd::vector<std::unique_ptr<ObjectProperty>> Tq" << name
5251cb0ef41Sopenharmony_ci              << "::GetProperties(d::MemoryAccessor accessor) const {\n";
5261cb0ef41Sopenharmony_ci  // Start by getting the fields from the parent class.
5271cb0ef41Sopenharmony_ci  cc_contents << "  std::vector<std::unique_ptr<ObjectProperty>> result = Tq"
5281cb0ef41Sopenharmony_ci              << super_name << "::GetProperties(accessor);\n";
5291cb0ef41Sopenharmony_ci  // Then add the fields from this class.
5301cb0ef41Sopenharmony_ci  cc_contents << get_props_impl.str();
5311cb0ef41Sopenharmony_ci  cc_contents << "  return result;\n";
5321cb0ef41Sopenharmony_ci  cc_contents << "}\n";
5331cb0ef41Sopenharmony_ci}
5341cb0ef41Sopenharmony_ci}  // namespace
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_civoid ImplementationVisitor::GenerateClassDebugReaders(
5371cb0ef41Sopenharmony_ci    const std::string& output_directory) {
5381cb0ef41Sopenharmony_ci  const std::string file_name = "class-debug-readers";
5391cb0ef41Sopenharmony_ci  std::stringstream h_contents;
5401cb0ef41Sopenharmony_ci  std::stringstream cc_contents;
5411cb0ef41Sopenharmony_ci  h_contents << "// Provides the ability to read object properties in\n";
5421cb0ef41Sopenharmony_ci  h_contents << "// postmortem or remote scenarios, where the debuggee's\n";
5431cb0ef41Sopenharmony_ci  h_contents << "// memory is not part of the current process's address\n";
5441cb0ef41Sopenharmony_ci  h_contents << "// space and must be read using a callback function.\n\n";
5451cb0ef41Sopenharmony_ci  {
5461cb0ef41Sopenharmony_ci    IncludeGuardScope include_guard(h_contents, file_name + ".h");
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci    h_contents << "#include <cstdint>\n";
5491cb0ef41Sopenharmony_ci    h_contents << "#include <vector>\n";
5501cb0ef41Sopenharmony_ci    h_contents
5511cb0ef41Sopenharmony_ci        << "\n#include \"tools/debug_helper/debug-helper-internal.h\"\n\n";
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci    const char* kWingdiWorkaround =
5541cb0ef41Sopenharmony_ci        "// Unset a wingdi.h macro that causes conflicts.\n"
5551cb0ef41Sopenharmony_ci        "#ifdef GetBValue\n"
5561cb0ef41Sopenharmony_ci        "#undef GetBValue\n"
5571cb0ef41Sopenharmony_ci        "#endif\n\n";
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci    h_contents << kWingdiWorkaround;
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci    cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n\n";
5621cb0ef41Sopenharmony_ci    cc_contents << "#include \"src/objects/all-objects-inl.h\"\n";
5631cb0ef41Sopenharmony_ci    cc_contents << "#include \"torque-generated/debug-macros.h\"\n\n";
5641cb0ef41Sopenharmony_ci    cc_contents << kWingdiWorkaround;
5651cb0ef41Sopenharmony_ci    cc_contents << "namespace i = v8::internal;\n\n";
5661cb0ef41Sopenharmony_ci
5671cb0ef41Sopenharmony_ci    NamespaceScope h_namespaces(h_contents,
5681cb0ef41Sopenharmony_ci                                {"v8", "internal", "debug_helper_internal"});
5691cb0ef41Sopenharmony_ci    NamespaceScope cc_namespaces(cc_contents,
5701cb0ef41Sopenharmony_ci                                 {"v8", "internal", "debug_helper_internal"});
5711cb0ef41Sopenharmony_ci
5721cb0ef41Sopenharmony_ci    std::stringstream visitor;
5731cb0ef41Sopenharmony_ci    visitor << "\nclass TqObjectVisitor {\n";
5741cb0ef41Sopenharmony_ci    visitor << " public:\n";
5751cb0ef41Sopenharmony_ci    visitor << "  virtual void VisitObject(const TqObject* object) {}\n";
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci    std::stringstream class_names;
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci    std::unordered_set<const ClassType*> done;
5801cb0ef41Sopenharmony_ci    for (const ClassType* type : TypeOracle::GetClasses()) {
5811cb0ef41Sopenharmony_ci      GenerateClassDebugReader(*type, h_contents, cc_contents, visitor,
5821cb0ef41Sopenharmony_ci                               class_names, &done);
5831cb0ef41Sopenharmony_ci    }
5841cb0ef41Sopenharmony_ci
5851cb0ef41Sopenharmony_ci    visitor << "};\n";
5861cb0ef41Sopenharmony_ci    h_contents << visitor.str();
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_ci    cc_contents << "\nconst char* kObjectClassNames[] {\n";
5891cb0ef41Sopenharmony_ci    cc_contents << class_names.str();
5901cb0ef41Sopenharmony_ci    cc_contents << "};\n";
5911cb0ef41Sopenharmony_ci    cc_contents << kObjectClassListDefinition;
5921cb0ef41Sopenharmony_ci  }
5931cb0ef41Sopenharmony_ci  WriteFile(output_directory + "/" + file_name + ".h", h_contents.str());
5941cb0ef41Sopenharmony_ci  WriteFile(output_directory + "/" + file_name + ".cc", cc_contents.str());
5951cb0ef41Sopenharmony_ci}
5961cb0ef41Sopenharmony_ci
5971cb0ef41Sopenharmony_ci}  // namespace torque
5981cb0ef41Sopenharmony_ci}  // namespace internal
5991cb0ef41Sopenharmony_ci}  // namespace v8
600