14 R
"( std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
15 d::MemoryAccessor accessor) const override;
16 const char* GetName() const override;
17 void Visit(TqObjectVisitor* visitor) const override;
18 bool IsSuperclassOf(const TqObject* other) const override;
28class ValueTypeFieldIterator {
30 ValueTypeFieldIterator(
const Type* type,
size_t index)
39 const Result operator*()
const {
40 if (
auto struct_type =
type_->StructSupertype()) {
41 const auto& field = (*struct_type)->fields()[
index_];
42 return {field.name_and_type, field.pos, *field.offset, 0, 0};
44 const Type* type =
type_;
45 int bitfield_start_offset = 0;
46 if (
const auto type_wrapped_in_smi =
48 type = *type_wrapped_in_smi;
51 if (
const BitFieldStructType* bit_field_struct_type =
52 BitFieldStructType::DynamicCast(type)) {
53 const auto& field = bit_field_struct_type->fields()[
index_];
54 return {field.name_and_type, field.pos, 0, field.num_bits,
55 field.offset + bitfield_start_offset};
63 bool operator==(
const ValueTypeFieldIterator& other)
const {
64 return type_ == other.type_ &&
index_ == other.index_;
66 bool operator!=(
const ValueTypeFieldIterator& other)
const {
67 return !(*
this == other);
77class ValueTypeFieldsRange {
79 explicit ValueTypeFieldsRange(
const Type* type) :
type_(type) {}
80 ValueTypeFieldIterator
begin() {
return {
type_, 0}; }
81 ValueTypeFieldIterator
end() {
83 std::optional<const StructType*> struct_type =
type_->StructSupertype();
86 index = (*struct_type)->fields().size();
88 const Type* type =
type_;
89 if (
const auto type_wrapped_in_smi =
91 type = *type_wrapped_in_smi;
93 if (
const BitFieldStructType* bit_field_struct_type =
94 BitFieldStructType::DynamicCast(type)) {
95 index = bit_field_struct_type->fields().size();
97 return {
type_, index};
106class DebugFieldType {
108 explicit DebugFieldType(
const Field& field)
113 bool IsTagged()
const {
121 std::string GetValueType(TypeStorage storage)
const {
123 return storage == kAsStoredInHeap ?
"i::Tagged_t" :
"uintptr_t";
128 return GetOriginalType(storage) +
129 " /*Failing? Ensure constexpr type name is correct, and the "
130 "necessary #include is in any .tq file*/";
138 std::string GetOriginalType(TypeStorage storage)
const {
145 std::optional<const ClassType*> field_class_type =
149 (field_class_type.has_value()
150 ? (*field_class_type)->GetGeneratedTNodeTypeName()
152 if (storage == kAsStoredInHeap) {
165 std::string GetTypeString(TypeStorage storage)
const {
168 return "\"" + GetOriginalType(storage) +
"\"";
176 return "CheckTypeName<" + GetValueType(storage) +
">(\"" +
177 GetOriginalType(storage) +
"\")";
181 size_t GetSize()
const {
183 if (!opt_size.has_value()) {
188 return std::get<0>(*opt_size);
192 std::string GetAddressGetter() {
208void GenerateFieldAddressAccessor(
const Field& field,
209 const std::string& class_name,
210 std::ostream& h_contents,
211 std::ostream& cc_contents) {
212 DebugFieldType debug_field_type(field);
214 const std::string address_getter = debug_field_type.GetAddressGetter();
216 h_contents <<
" uintptr_t " << address_getter <<
"() const;\n";
217 cc_contents <<
"\nuintptr_t Tq" << class_name <<
"::" << address_getter
219 cc_contents <<
" return address_ - i::kHeapObjectTag + " << *field.offset
221 cc_contents <<
"}\n";
252void GenerateFieldValueAccessor(
const Field& field,
253 const std::string& class_name,
254 std::ostream& h_contents,
255 std::ostream& cc_contents) {
257 if (field.name_and_type.type->StructSupertype())
return;
259 DebugFieldType debug_field_type(field);
261 const std::string address_getter = debug_field_type.GetAddressGetter();
262 const std::string field_getter =
265 std::string index_param;
266 std::string index_offset;
268 index_param =
", size_t offset";
269 index_offset =
" + offset * sizeof(value)";
272 std::string field_value_type = debug_field_type.GetValueType(kUncompressed);
273 h_contents <<
" Value<" << field_value_type <<
"> " << field_getter
274 <<
"(d::MemoryAccessor accessor " << index_param <<
") const;\n";
275 cc_contents <<
"\nValue<" << field_value_type <<
"> Tq" << class_name
276 <<
"::" << field_getter <<
"(d::MemoryAccessor accessor"
277 << index_param <<
") const {\n";
278 cc_contents <<
" " << debug_field_type.GetValueType(kAsStoredInHeap)
280 cc_contents <<
" d::MemoryAccessResult validity = accessor("
281 << address_getter <<
"()" << index_offset
282 <<
", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
284 if (field_getter ==
"GetMapValue") {
285 cc_contents <<
" value = i::MapWord::Unpack(value);\n";
288 cc_contents <<
" return {validity, "
289 << (debug_field_type.IsTagged()
290 ?
"EnsureDecompressed(value, address_)"
293 cc_contents <<
"}\n";
352void GenerateGetPropsChunkForField(
const Field& field,
353 std::ostream& get_props_impl,
354 std::string class_name) {
355 DebugFieldType debug_field_type(field);
359 std::string struct_field_list =
360 field.name_and_type.name +
"_struct_field_list";
361 get_props_impl <<
" std::vector<std::unique_ptr<StructProperty>> "
362 << struct_field_list <<
";\n";
363 for (
const auto& struct_field :
364 ValueTypeFieldsRange(field.name_and_type.type)) {
365 DebugFieldType struct_field_type(struct_field.name_and_type,
367 get_props_impl <<
" " << struct_field_list
368 <<
".push_back(std::make_unique<StructProperty>(\""
369 << struct_field.name_and_type.name <<
"\", "
370 << struct_field_type.GetTypeString(kAsStoredInHeap) <<
", "
371 << struct_field.offset_bytes <<
", " << struct_field.num_bits
372 <<
", " << struct_field.shift_bits <<
"));\n";
374 struct_field_list =
"std::move(" + struct_field_list +
")";
377 std::string count_value =
"1";
378 std::string property_kind =
"d::PropertyKind::kSingle";
383 std::string indexed_field_slice =
384 "indexed_field_slice_" + field.name_and_type.name;
385 get_props_impl <<
" auto " << indexed_field_slice <<
" = "
386 <<
"TqDebugFieldSlice" << class_name
388 <<
"(accessor, address_);\n";
389 std::string validity = indexed_field_slice +
".validity";
390 std::string value = indexed_field_slice +
".value";
391 property_kind =
"GetArrayKind(" + validity +
")";
393 get_props_impl <<
" if (" << validity
394 <<
" == d::MemoryAccessResult::kOk) {\n"
395 <<
" result.push_back(std::make_unique<ObjectProperty>(\""
396 << field.name_and_type.name <<
"\", "
397 << debug_field_type.GetTypeString(kAsStoredInHeap) <<
", "
398 <<
"address_ - i::kHeapObjectTag + std::get<1>(" << value
400 <<
"std::get<2>(" << value <<
")"
401 <<
", " << debug_field_type.GetSize() <<
", "
402 << struct_field_list <<
", " << property_kind <<
"));\n"
406 get_props_impl <<
" result.push_back(std::make_unique<ObjectProperty>(\""
407 << field.name_and_type.name <<
"\", "
408 << debug_field_type.GetTypeString(kAsStoredInHeap) <<
", "
409 << debug_field_type.GetAddressGetter() <<
"(), " << count_value
410 <<
", " << debug_field_type.GetSize() <<
", "
411 << struct_field_list <<
", " << property_kind <<
"));\n";
447void GenerateClassDebugReader(
const ClassType& type, std::ostream& h_contents,
448 std::ostream& cc_contents, std::ostream& visitor,
449 std::unordered_set<const ClassType*>* done) {
451 if (!done->insert(&type).second)
return;
452 const ClassType* super_type = type.GetSuperClass();
456 if (super_type !=
nullptr) {
457 GenerateClassDebugReader(*super_type, h_contents, cc_contents, visitor,
463 if (type.HasUndefinedLayout())
return;
465 const std::string name = type.name();
466 const std::string super_name =
467 super_type ==
nullptr ?
"Object" : super_type->name();
468 h_contents <<
"\nclass Tq" << name <<
" : public Tq" << super_name <<
" {\n";
469 h_contents <<
" public:\n";
470 h_contents <<
" inline Tq" << name <<
"(uintptr_t address) : Tq"
471 << super_name <<
"(address) {}\n";
474 cc_contents <<
"\nconst char* Tq" << name <<
"::GetName() const {\n";
475 cc_contents <<
" return \"v8::internal::" << name <<
"\";\n";
476 cc_contents <<
"}\n";
478 cc_contents <<
"\nvoid Tq" << name
479 <<
"::Visit(TqObjectVisitor* visitor) const {\n";
480 cc_contents <<
" visitor->Visit" << name <<
"(this);\n";
481 cc_contents <<
"}\n";
483 cc_contents <<
"\nbool Tq" << name
484 <<
"::IsSuperclassOf(const TqObject* other) const {\n";
486 <<
" return GetName() != other->GetName() && dynamic_cast<const Tq"
487 << name <<
"*>(other) != nullptr;\n";
488 cc_contents <<
"}\n";
493 visitor <<
" virtual void Visit" << name <<
"(const Tq" << name
495 visitor <<
" Visit" << super_name <<
"(object);\n";
498 std::stringstream get_props_impl;
500 for (
const Field& field : type.fields()) {
502 if (field.offset.has_value()) {
503 GenerateFieldAddressAccessor(field, name, h_contents, cc_contents);
504 GenerateFieldValueAccessor(field, name, h_contents, cc_contents);
506 GenerateGetPropsChunkForField(field, get_props_impl, name);
509 h_contents <<
"};\n";
511 cc_contents <<
"\nstd::vector<std::unique_ptr<ObjectProperty>> Tq" << name
512 <<
"::GetProperties(d::MemoryAccessor accessor) const {\n";
514 cc_contents <<
" std::vector<std::unique_ptr<ObjectProperty>> result = Tq"
515 << super_name <<
"::GetProperties(accessor);\n";
517 cc_contents << get_props_impl.str();
518 cc_contents <<
" return result;\n";
519 cc_contents <<
"}\n";
524 const std::string& output_directory) {
525 const std::string file_name =
"class-debug-readers";
526 std::stringstream h_contents;
527 std::stringstream cc_contents;
528 h_contents <<
"// Provides the ability to read object properties in\n";
529 h_contents <<
"// postmortem or remote scenarios, where the debuggee's\n";
530 h_contents <<
"// memory is not part of the current process's address\n";
531 h_contents <<
"// space and must be read using a callback function.\n\n";
535 h_contents <<
"#include <cstdint>\n";
536 h_contents <<
"#include <vector>\n\n";
543 <<
"\n#include \"tools/debug_helper/debug-helper-internal.h\"\n\n";
545 const char* kWingdiWorkaround =
546 "// Unset a wingdi.h macro that causes conflicts.\n"
551 h_contents << kWingdiWorkaround;
553 cc_contents <<
"#include \"torque-generated/" << file_name <<
".h\"\n\n";
554 cc_contents <<
"#include \"src/objects/all-objects-inl.h\"\n";
555 cc_contents <<
"#include \"torque-generated/debug-macros.h\"\n\n";
556 cc_contents << kWingdiWorkaround;
557 cc_contents <<
"namespace i = v8::internal;\n\n";
560 {
"v8",
"internal",
"debug_helper_internal"});
562 {
"v8",
"internal",
"debug_helper_internal"});
564 std::stringstream visitor;
565 visitor <<
"\nclass TqObjectVisitor {\n";
566 visitor <<
" public:\n";
567 visitor <<
" virtual void VisitObject(const TqObject* object) {}\n";
569 std::unordered_set<const ClassType*> done;
571 GenerateClassDebugReader(*type, h_contents, cc_contents, visitor, &done);
575 h_contents << visitor.str();
577 WriteFile(output_directory +
"/" + file_name +
".h", h_contents.str());
578 WriteFile(output_directory +
"/" + file_name +
".cc", cc_contents.str());
NameAndType name_and_type
NameAndType name_and_type_
static const std::set< std::string > & CppIncludes()
void GenerateClassDebugReaders(const std::string &output_directory)
void WriteFile(const std::string &file, const std::string &content)
MessageBuilder & Position(SourcePosition position)
static int SmiTagAndShiftSize()
static GenericType * GetSmiTaggedGeneric()
static std::vector< const ClassType * > GetClasses()
static const Type * GetTaggedType()
static const Type * GetVoidType()
static const Type * GetFloat64OrUndefinedOrHoleType()
static std::optional< const Type * > MatchUnaryGeneric(const Type *type, GenericType *generic)
ZoneVector< RpoNumber > & result
Node::Uses::const_iterator begin(const Node::Uses &uses)
std::string StringLiteralQuote(const std::string &s)
std::string CamelifyString(const std::string &underscore_string)
std::optional< std::tuple< size_t, std::string > > SizeOf(const Type *type)
constexpr char kTqObjectOverrideDecls[]
MessageBuilder Error(Args &&... args)
bool operator!=(ExternalReference lhs, ExternalReference rhs)
bool operator==(ExternalReference lhs, ExternalReference rhs)
V8_INLINE Builtin operator++(Builtin &builtin)