• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/flags/flags.h"
6 #include "src/torque/implementation-visitor.h"
7 #include "src/torque/type-oracle.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace torque {
12 
13 constexpr char kTqObjectOverrideDecls[] =
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;
19 )";
20 
21 constexpr char kObjectClassListDefinition[] = R"(
22 const d::ClassList kObjectClassList {
23   sizeof(kObjectClassNames) / sizeof(const char*),
24   kObjectClassNames,
25 };
26 )";
27 
28 namespace {
29 enum TypeStorage {
30   kAsStoredInHeap,
31   kUncompressed,
32 };
33 
34 // An iterator for use in ValueTypeFieldsRange.
35 class ValueTypeFieldIterator {
36  public:
ValueTypeFieldIterator(const Type * type,size_t index)37   ValueTypeFieldIterator(const Type* type, size_t index)
38       : type_(type), index_(index) {}
39   struct Result {
40     NameAndType name_and_type;
41     SourcePosition pos;
42     size_t offset_bytes;
43     int num_bits;
44     int shift_bits;
45   };
operator *() const46   const Result operator*() const {
47     if (auto struct_type = type_->StructSupertype()) {
48       const auto& field = (*struct_type)->fields()[index_];
49       return {field.name_and_type, field.pos, *field.offset, 0, 0};
50     }
51     const Type* type = type_;
52     int bitfield_start_offset = 0;
53     if (const auto type_wrapped_in_smi =
54             Type::MatchUnaryGeneric(type_, TypeOracle::GetSmiTaggedGeneric())) {
55       type = *type_wrapped_in_smi;
56       bitfield_start_offset = TargetArchitecture::SmiTagAndShiftSize();
57     }
58     if (const BitFieldStructType* bit_field_struct_type =
59             BitFieldStructType::DynamicCast(type)) {
60       const auto& field = bit_field_struct_type->fields()[index_];
61       return {field.name_and_type, field.pos, 0, field.num_bits,
62               field.offset + bitfield_start_offset};
63     }
64     UNREACHABLE();
65   }
operator ++()66   ValueTypeFieldIterator& operator++() {
67     ++index_;
68     return *this;
69   }
operator ==(const ValueTypeFieldIterator & other) const70   bool operator==(const ValueTypeFieldIterator& other) const {
71     return type_ == other.type_ && index_ == other.index_;
72   }
operator !=(const ValueTypeFieldIterator & other) const73   bool operator!=(const ValueTypeFieldIterator& other) const {
74     return !(*this == other);
75   }
76 
77  private:
78   const Type* type_;
79   size_t index_;
80 };
81 
82 // A way to iterate over the fields of structs or bitfield structs. For other
83 // types, the iterators returned from begin() and end() are immediately equal.
84 class ValueTypeFieldsRange {
85  public:
ValueTypeFieldsRange(const Type * type)86   explicit ValueTypeFieldsRange(const Type* type) : type_(type) {}
begin()87   ValueTypeFieldIterator begin() { return {type_, 0}; }
end()88   ValueTypeFieldIterator end() {
89     size_t index = 0;
90     base::Optional<const StructType*> struct_type = type_->StructSupertype();
91     if (struct_type && *struct_type != TypeOracle::GetFloat64OrHoleType()) {
92       index = (*struct_type)->fields().size();
93     }
94     const Type* type = type_;
95     if (const auto type_wrapped_in_smi =
96             Type::MatchUnaryGeneric(type_, TypeOracle::GetSmiTaggedGeneric())) {
97       type = *type_wrapped_in_smi;
98     }
99     if (const BitFieldStructType* bit_field_struct_type =
100             BitFieldStructType::DynamicCast(type)) {
101       index = bit_field_struct_type->fields().size();
102     }
103     return {type_, index};
104   }
105 
106  private:
107   const Type* type_;
108 };
109 
110 // A convenient way to keep track of several different ways that we might need
111 // to represent a field's type in the generated C++.
112 class DebugFieldType {
113  public:
DebugFieldType(const Field & field)114   explicit DebugFieldType(const Field& field)
115       : name_and_type_(field.name_and_type), pos_(field.pos) {}
DebugFieldType(const NameAndType & name_and_type,const SourcePosition & pos)116   DebugFieldType(const NameAndType& name_and_type, const SourcePosition& pos)
117       : name_and_type_(name_and_type), pos_(pos) {}
118 
IsTagged() const119   bool IsTagged() const {
120     return name_and_type_.type->IsSubtypeOf(TypeOracle::GetTaggedType());
121   }
122 
123   // Returns the type that should be used for this field's value within code
124   // that is compiled as part of the debug helper library. In particular, this
125   // simplifies any tagged type to a plain uintptr_t because the debug helper
126   // compiles without most of the V8 runtime code.
GetValueType(TypeStorage storage) const127   std::string GetValueType(TypeStorage storage) const {
128     if (IsTagged()) {
129       return storage == kAsStoredInHeap ? "i::Tagged_t" : "uintptr_t";
130     }
131 
132     // We can't emit a useful error at this point if the constexpr type name is
133     // wrong, but we can include a comment that might be helpful.
134     return GetOriginalType(storage) +
135            " /*Failing? Ensure constexpr type name is correct, and the "
136            "necessary #include is in any .tq file*/";
137   }
138 
139   // Returns the type that should be used to represent a field's type to
140   // debugging tools that have full V8 symbols. The types returned from this
141   // method are resolveable in the v8::internal namespace and may refer to
142   // object types that are not included in the compilation of the debug helper
143   // library.
GetOriginalType(TypeStorage storage) const144   std::string GetOriginalType(TypeStorage storage) const {
145     if (name_and_type_.type->StructSupertype()) {
146       // There's no meaningful type we could use here, because the V8 symbols
147       // don't have any definition of a C++ struct matching this struct type.
148       return "";
149     }
150     if (IsTagged()) {
151       if (storage == kAsStoredInHeap &&
152           TargetArchitecture::ArePointersCompressed()) {
153         return "v8::internal::TaggedValue";
154       }
155       base::Optional<const ClassType*> field_class_type =
156           name_and_type_.type->ClassSupertype();
157       return "v8::internal::" +
158              (field_class_type.has_value()
159                   ? (*field_class_type)->GetGeneratedTNodeTypeName()
160                   : "Object");
161     }
162     return name_and_type_.type->GetConstexprGeneratedTypeName();
163   }
164 
165   // Returns a C++ expression that evaluates to a string (type `const char*`)
166   // containing the name of the field's type. The types returned from this
167   // method are resolveable in the v8::internal namespace and may refer to
168   // object types that are not included in the compilation of the debug helper
169   // library.
GetTypeString(TypeStorage storage) const170   std::string GetTypeString(TypeStorage storage) const {
171     if (IsTagged() || name_and_type_.type->IsStructType()) {
172       // Wrap up the original type in a string literal.
173       return "\"" + GetOriginalType(storage) + "\"";
174     }
175 
176     // We require constexpr type names to be resolvable in the v8::internal
177     // namespace, according to the contract in debug-helper.h. In order to
178     // verify at compile time that constexpr type names are resolvable, we use
179     // the type name as a dummy template parameter to a function that just
180     // returns its parameter.
181     return "CheckTypeName<" + GetValueType(storage) + ">(\"" +
182            GetOriginalType(storage) + "\")";
183   }
184 
185   // Returns the field's size in bytes.
GetSize() const186   size_t GetSize() const {
187     auto opt_size = SizeOf(name_and_type_.type);
188     if (!opt_size.has_value()) {
189       Error("Size required for type ", name_and_type_.type->ToString())
190           .Position(pos_);
191       return 0;
192     }
193     return std::get<0>(*opt_size);
194   }
195 
196   // Returns the name of the function for getting this field's address.
GetAddressGetter()197   std::string GetAddressGetter() {
198     return "Get" + CamelifyString(name_and_type_.name) + "Address";
199   }
200 
201  private:
202   NameAndType name_and_type_;
203   SourcePosition pos_;
204 };
205 
206 // Emits a function to get the address of a field within a class, based on the
207 // member variable {address_}, which is a tagged pointer. Example
208 // implementation:
209 //
210 // uintptr_t TqFixedArray::GetObjectsAddress() const {
211 //   return address_ - i::kHeapObjectTag + 16;
212 // }
GenerateFieldAddressAccessor(const Field & field,const std::string & class_name,std::ostream & h_contents,std::ostream & cc_contents)213 void GenerateFieldAddressAccessor(const Field& field,
214                                   const std::string& class_name,
215                                   std::ostream& h_contents,
216                                   std::ostream& cc_contents) {
217   DebugFieldType debug_field_type(field);
218 
219   const std::string address_getter = debug_field_type.GetAddressGetter();
220 
221   h_contents << "  uintptr_t " << address_getter << "() const;\n";
222   cc_contents << "\nuintptr_t Tq" << class_name << "::" << address_getter
223               << "() const {\n";
224   cc_contents << "  return address_ - i::kHeapObjectTag + " << *field.offset
225               << ";\n";
226   cc_contents << "}\n";
227 }
228 
229 // Emits a function to get the value of a field, or the value from an indexed
230 // position within an array field, based on the member variable {address_},
231 // which is a tagged pointer, and the parameter {accessor}, a function pointer
232 // that allows for fetching memory from the debuggee. The returned result
233 // includes both a "validity", indicating whether the memory could be fetched,
234 // and the fetched value. If the field contains tagged data, then these
235 // functions call EnsureDecompressed to expand compressed data. Example:
236 //
237 // Value<uintptr_t> TqMap::GetPrototypeValue(d::MemoryAccessor accessor) const {
238 //   i::Tagged_t value{};
239 //   d::MemoryAccessResult validity = accessor(
240 //       GetPrototypeAddress(),
241 //       reinterpret_cast<uint8_t*>(&value),
242 //       sizeof(value));
243 //   return {validity, EnsureDecompressed(value, address_)};
244 // }
245 //
246 // For array fields, an offset parameter is included. Example:
247 //
248 // Value<uintptr_t> TqFixedArray::GetObjectsValue(d::MemoryAccessor accessor,
249 //                                                size_t offset) const {
250 //   i::Tagged_t value{};
251 //   d::MemoryAccessResult validity = accessor(
252 //       GetObjectsAddress() + offset * sizeof(value),
253 //       reinterpret_cast<uint8_t*>(&value),
254 //       sizeof(value));
255 //   return {validity, EnsureDecompressed(value, address_)};
256 // }
GenerateFieldValueAccessor(const Field & field,const std::string & class_name,std::ostream & h_contents,std::ostream & cc_contents)257 void GenerateFieldValueAccessor(const Field& field,
258                                 const std::string& class_name,
259                                 std::ostream& h_contents,
260                                 std::ostream& cc_contents) {
261   // Currently not implemented for struct fields.
262   if (field.name_and_type.type->StructSupertype()) return;
263 
264   DebugFieldType debug_field_type(field);
265 
266   const std::string address_getter = debug_field_type.GetAddressGetter();
267   const std::string field_getter =
268       "Get" + CamelifyString(field.name_and_type.name) + "Value";
269 
270   std::string index_param;
271   std::string index_offset;
272   if (field.index) {
273     index_param = ", size_t offset";
274     index_offset = " + offset * sizeof(value)";
275   }
276 
277   std::string field_value_type = debug_field_type.GetValueType(kUncompressed);
278   h_contents << "  Value<" << field_value_type << "> " << field_getter
279              << "(d::MemoryAccessor accessor " << index_param << ") const;\n";
280   cc_contents << "\nValue<" << field_value_type << "> Tq" << class_name
281               << "::" << field_getter << "(d::MemoryAccessor accessor"
282               << index_param << ") const {\n";
283   cc_contents << "  " << debug_field_type.GetValueType(kAsStoredInHeap)
284               << " value{};\n";
285   cc_contents << "  d::MemoryAccessResult validity = accessor("
286               << address_getter << "()" << index_offset
287               << ", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
288 #ifdef V8_MAP_PACKING
289   if (field_getter == "GetMapValue") {
290     cc_contents << "  value = i::MapWord::Unpack(value);\n";
291   }
292 #endif
293   cc_contents << "  return {validity, "
294               << (debug_field_type.IsTagged()
295                       ? "EnsureDecompressed(value, address_)"
296                       : "value")
297               << "};\n";
298   cc_contents << "}\n";
299 }
300 
301 // Emits a portion of the member function GetProperties that is responsible for
302 // adding data about the current field to a result vector called "result".
303 // Example output:
304 //
305 // std::vector<std::unique_ptr<StructProperty>> prototype_struct_field_list;
306 // result.push_back(std::make_unique<ObjectProperty>(
307 //     "prototype",                                     // Field name
308 //     "v8::internal::HeapObject",                      // Field type
309 //     "v8::internal::HeapObject",                      // Decompressed type
310 //     GetPrototypeAddress(),                           // Field address
311 //     1,                                               // Number of values
312 //     8,                                               // Size of value
313 //     std::move(prototype_struct_field_list),          // Struct fields
314 //     d::PropertyKind::kSingle));                      // Field kind
315 //
316 // In builds with pointer compression enabled, the field type for tagged values
317 // is "v8::internal::TaggedValue" (a four-byte class) and the decompressed type
318 // is a normal Object subclass that describes the expanded eight-byte type.
319 //
320 // If the field is an array, then its length is fetched from the debuggee. This
321 // could fail if the debuggee has incomplete memory, so the "validity" from that
322 // fetch is used to determine the result PropertyKind, which will say whether
323 // the array's length is known.
324 //
325 // If the field's type is a struct, then a local variable is created and filled
326 // with descriptions of each of the struct's fields. The type and decompressed
327 // type in the ObjectProperty are set to the empty string, to indicate to the
328 // caller that the struct fields vector should be used instead.
329 //
330 // The following example is an array of structs, so it uses both of the optional
331 // components described above:
332 //
333 // std::vector<std::unique_ptr<StructProperty>> descriptors_struct_field_list;
334 // descriptors_struct_field_list.push_back(std::make_unique<StructProperty>(
335 //     "key",                                // Struct field name
336 //     "v8::internal::PrimitiveHeapObject",  // Struct field type
337 //     "v8::internal::PrimitiveHeapObject",  // Struct field decompressed type
338 //     0,                                    // Byte offset within struct data
339 //     0,                                    // Bitfield size (0=not a bitfield)
340 //     0));                                  // Bitfield shift
341 // // The line above is repeated for other struct fields. Omitted here.
342 // // Fetch the slice.
343 // auto indexed_field_slice_descriptors =
344 //     TqDebugFieldSliceDescriptorArrayDescriptors(accessor, address_);
345 // if (indexed_field_slice_descriptors.validity == d::MemoryAccessResult::kOk) {
346 //   result.push_back(std::make_unique<ObjectProperty>(
347 //     "descriptors",                                 // Field name
348 //     "",                                            // Field type
349 //     "",                                            // Decompressed type
350 //     address_ - i::kHeapObjectTag +
351 //     std::get<1>(indexed_field_slice_descriptors.value), // Field address
352 //     std::get<2>(indexed_field_slice_descriptors.value), // Number of values
353 //     12,                                            // Size of value
354 //     std::move(descriptors_struct_field_list),      // Struct fields
355 //     GetArrayKind(indexed_field_slice_descriptors.validity)));  // Field kind
356 // }
GenerateGetPropsChunkForField(const Field & field,std::ostream & get_props_impl,std::string class_name)357 void GenerateGetPropsChunkForField(const Field& field,
358                                    std::ostream& get_props_impl,
359                                    std::string class_name) {
360   DebugFieldType debug_field_type(field);
361 
362   // If the current field is a struct or bitfield struct, create a vector
363   // describing its fields. Otherwise this vector will be empty.
364   std::string struct_field_list =
365       field.name_and_type.name + "_struct_field_list";
366   get_props_impl << "  std::vector<std::unique_ptr<StructProperty>> "
367                  << struct_field_list << ";\n";
368   for (const auto& struct_field :
369        ValueTypeFieldsRange(field.name_and_type.type)) {
370     DebugFieldType struct_field_type(struct_field.name_and_type,
371                                      struct_field.pos);
372     get_props_impl << "  " << struct_field_list
373                    << ".push_back(std::make_unique<StructProperty>(\""
374                    << struct_field.name_and_type.name << "\", "
375                    << struct_field_type.GetTypeString(kAsStoredInHeap) << ", "
376                    << struct_field_type.GetTypeString(kUncompressed) << ", "
377                    << struct_field.offset_bytes << ", " << struct_field.num_bits
378                    << ", " << struct_field.shift_bits << "));\n";
379   }
380   struct_field_list = "std::move(" + struct_field_list + ")";
381 
382   // The number of values and property kind for non-indexed properties:
383   std::string count_value = "1";
384   std::string property_kind = "d::PropertyKind::kSingle";
385 
386   // If the field is indexed, emit a fetch of the array length, and change
387   // count_value and property_kind to be the correct values for an array.
388   if (field.index) {
389     std::string indexed_field_slice =
390         "indexed_field_slice_" + field.name_and_type.name;
391     get_props_impl << "  auto " << indexed_field_slice << " = "
392                    << "TqDebugFieldSlice" << class_name
393                    << CamelifyString(field.name_and_type.name)
394                    << "(accessor, address_);\n";
395     std::string validity = indexed_field_slice + ".validity";
396     std::string value = indexed_field_slice + ".value";
397     property_kind = "GetArrayKind(" + validity + ")";
398 
399     get_props_impl << "  if (" << validity
400                    << " == d::MemoryAccessResult::kOk) {\n"
401                    << "    result.push_back(std::make_unique<ObjectProperty>(\""
402                    << field.name_and_type.name << "\", "
403                    << debug_field_type.GetTypeString(kAsStoredInHeap) << ", "
404                    << debug_field_type.GetTypeString(kUncompressed) << ", "
405                    << "address_ - i::kHeapObjectTag + std::get<1>(" << value
406                    << "), "
407                    << "std::get<2>(" << value << ")"
408                    << ", " << debug_field_type.GetSize() << ", "
409                    << struct_field_list << ", " << property_kind << "));\n"
410                    << "  }\n";
411     return;
412   }
413   get_props_impl << "  result.push_back(std::make_unique<ObjectProperty>(\""
414                  << field.name_and_type.name << "\", "
415                  << debug_field_type.GetTypeString(kAsStoredInHeap) << ", "
416                  << debug_field_type.GetTypeString(kUncompressed) << ", "
417                  << debug_field_type.GetAddressGetter() << "(), " << count_value
418                  << ", " << debug_field_type.GetSize() << ", "
419                  << struct_field_list << ", " << property_kind << "));\n";
420 }
421 
422 // For any Torque-defined class Foo, this function generates a class TqFoo which
423 // allows for convenient inspection of objects of type Foo in a crash dump or
424 // time travel session (where we can't just run the object printer). The
425 // generated class looks something like this:
426 //
427 // class TqFoo : public TqParentOfFoo {
428 //  public:
429 //   // {address} is an uncompressed tagged pointer.
430 //   inline TqFoo(uintptr_t address) : TqParentOfFoo(address) {}
431 //
432 //   // Creates and returns a list of this object's properties.
433 //   std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
434 //       d::MemoryAccessor accessor) const override;
435 //
436 //   // Returns the name of this class, "v8::internal::Foo".
437 //   const char* GetName() const override;
438 //
439 //   // Visitor pattern; implementation just calls visitor->VisitFoo(this).
440 //   void Visit(TqObjectVisitor* visitor) const override;
441 //
442 //   // Returns whether Foo is a superclass of the other object's type.
443 //   bool IsSuperclassOf(const TqObject* other) const override;
444 //
445 //   // Field accessors omitted here (see other comments above).
446 // };
447 //
448 // Four output streams are written:
449 //
450 // h_contents:  A header file which gets the class definition above.
451 // cc_contents: A cc file which gets implementations of that class's members.
452 // visitor:     A stream that is accumulating the definition of the class
453 //              TqObjectVisitor. Each class Foo gets its own virtual method
454 //              VisitFoo in TqObjectVisitor.
455 // class_names: A stream that is accumulating a list of strings including fully-
456 //              qualified names for every Torque-defined class type.
GenerateClassDebugReader(const ClassType & type,std::ostream & h_contents,std::ostream & cc_contents,std::ostream & visitor,std::ostream & class_names,std::unordered_set<const ClassType * > * done)457 void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents,
458                               std::ostream& cc_contents, std::ostream& visitor,
459                               std::ostream& class_names,
460                               std::unordered_set<const ClassType*>* done) {
461   // Make sure each class only gets generated once.
462   if (!done->insert(&type).second) return;
463   const ClassType* super_type = type.GetSuperClass();
464 
465   // We must emit the classes in dependency order. If the super class hasn't
466   // been emitted yet, go handle it first.
467   if (super_type != nullptr) {
468     GenerateClassDebugReader(*super_type, h_contents, cc_contents, visitor,
469                              class_names, done);
470   }
471 
472   // Classes with undefined layout don't grant any particular value here and may
473   // not correspond with actual C++ classes, so skip them.
474   if (type.HasUndefinedLayout()) return;
475 
476   const std::string name = type.name();
477   const std::string super_name =
478       super_type == nullptr ? "Object" : super_type->name();
479   h_contents << "\nclass Tq" << name << " : public Tq" << super_name << " {\n";
480   h_contents << " public:\n";
481   h_contents << "  inline Tq" << name << "(uintptr_t address) : Tq"
482              << super_name << "(address) {}\n";
483   h_contents << kTqObjectOverrideDecls;
484 
485   cc_contents << "\nconst char* Tq" << name << "::GetName() const {\n";
486   cc_contents << "  return \"v8::internal::" << name << "\";\n";
487   cc_contents << "}\n";
488 
489   cc_contents << "\nvoid Tq" << name
490               << "::Visit(TqObjectVisitor* visitor) const {\n";
491   cc_contents << "  visitor->Visit" << name << "(this);\n";
492   cc_contents << "}\n";
493 
494   cc_contents << "\nbool Tq" << name
495               << "::IsSuperclassOf(const TqObject* other) const {\n";
496   cc_contents
497       << "  return GetName() != other->GetName() && dynamic_cast<const Tq"
498       << name << "*>(other) != nullptr;\n";
499   cc_contents << "}\n";
500 
501   // By default, the visitor method for this class just calls the visitor method
502   // for this class's parent. This allows custom visitors to only override a few
503   // classes they care about without needing to know about the entire hierarchy.
504   visitor << "  virtual void Visit" << name << "(const Tq" << name
505           << "* object) {\n";
506   visitor << "    Visit" << super_name << "(object);\n";
507   visitor << "  }\n";
508 
509   class_names << "  \"v8::internal::" << name << "\",\n";
510 
511   std::stringstream get_props_impl;
512 
513   for (const Field& field : type.fields()) {
514     if (field.name_and_type.type == TypeOracle::GetVoidType()) continue;
515     if (field.offset.has_value()) {
516       GenerateFieldAddressAccessor(field, name, h_contents, cc_contents);
517       GenerateFieldValueAccessor(field, name, h_contents, cc_contents);
518     }
519     GenerateGetPropsChunkForField(field, get_props_impl, name);
520   }
521 
522   h_contents << "};\n";
523 
524   cc_contents << "\nstd::vector<std::unique_ptr<ObjectProperty>> Tq" << name
525               << "::GetProperties(d::MemoryAccessor accessor) const {\n";
526   // Start by getting the fields from the parent class.
527   cc_contents << "  std::vector<std::unique_ptr<ObjectProperty>> result = Tq"
528               << super_name << "::GetProperties(accessor);\n";
529   // Then add the fields from this class.
530   cc_contents << get_props_impl.str();
531   cc_contents << "  return result;\n";
532   cc_contents << "}\n";
533 }
534 }  // namespace
535 
GenerateClassDebugReaders(const std::string & output_directory)536 void ImplementationVisitor::GenerateClassDebugReaders(
537     const std::string& output_directory) {
538   const std::string file_name = "class-debug-readers";
539   std::stringstream h_contents;
540   std::stringstream cc_contents;
541   h_contents << "// Provides the ability to read object properties in\n";
542   h_contents << "// postmortem or remote scenarios, where the debuggee's\n";
543   h_contents << "// memory is not part of the current process's address\n";
544   h_contents << "// space and must be read using a callback function.\n\n";
545   {
546     IncludeGuardScope include_guard(h_contents, file_name + ".h");
547 
548     h_contents << "#include <cstdint>\n";
549     h_contents << "#include <vector>\n";
550     h_contents
551         << "\n#include \"tools/debug_helper/debug-helper-internal.h\"\n\n";
552 
553     const char* kWingdiWorkaround =
554         "// Unset a wingdi.h macro that causes conflicts.\n"
555         "#ifdef GetBValue\n"
556         "#undef GetBValue\n"
557         "#endif\n\n";
558 
559     h_contents << kWingdiWorkaround;
560 
561     cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n\n";
562     cc_contents << "#include \"src/objects/all-objects-inl.h\"\n";
563     cc_contents << "#include \"torque-generated/debug-macros.h\"\n\n";
564     cc_contents << kWingdiWorkaround;
565     cc_contents << "namespace i = v8::internal;\n\n";
566 
567     NamespaceScope h_namespaces(h_contents,
568                                 {"v8", "internal", "debug_helper_internal"});
569     NamespaceScope cc_namespaces(cc_contents,
570                                  {"v8", "internal", "debug_helper_internal"});
571 
572     std::stringstream visitor;
573     visitor << "\nclass TqObjectVisitor {\n";
574     visitor << " public:\n";
575     visitor << "  virtual void VisitObject(const TqObject* object) {}\n";
576 
577     std::stringstream class_names;
578 
579     std::unordered_set<const ClassType*> done;
580     for (const ClassType* type : TypeOracle::GetClasses()) {
581       GenerateClassDebugReader(*type, h_contents, cc_contents, visitor,
582                                class_names, &done);
583     }
584 
585     visitor << "};\n";
586     h_contents << visitor.str();
587 
588     cc_contents << "\nconst char* kObjectClassNames[] {\n";
589     cc_contents << class_names.str();
590     cc_contents << "};\n";
591     cc_contents << kObjectClassListDefinition;
592   }
593   WriteFile(output_directory + "/" + file_name + ".h", h_contents.str());
594   WriteFile(output_directory + "/" + file_name + ".cc", cc_contents.str());
595 }
596 
597 }  // namespace torque
598 }  // namespace internal
599 }  // namespace v8
600