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