summaryrefslogtreecommitdiff
path: root/deps/v8/tools/debug_helper
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools/debug_helper')
-rw-r--r--deps/v8/tools/debug_helper/BUILD.gn3
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.cc11
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.h42
-rw-r--r--deps/v8/tools/debug_helper/debug-helper.h28
-rw-r--r--deps/v8/tools/debug_helper/gen-heap-constants.py19
-rw-r--r--deps/v8/tools/debug_helper/get-object-properties.cc321
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.cc52
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.h47
8 files changed, 365 insertions, 158 deletions
diff --git a/deps/v8/tools/debug_helper/BUILD.gn b/deps/v8/tools/debug_helper/BUILD.gn
index c81fddc9e5..2fe5f0d8be 100644
--- a/deps/v8/tools/debug_helper/BUILD.gn
+++ b/deps/v8/tools/debug_helper/BUILD.gn
@@ -100,5 +100,8 @@ v8_component("v8_debug_helper") {
configs += [ "//third_party/icu:icu_config" ]
}
+ remove_configs = [ "//build/config/compiler:no_rtti" ]
+ configs += [ "//build/config/compiler:rtti" ]
+
public_configs = [ ":external_config" ]
}
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.cc b/deps/v8/tools/debug_helper/debug-helper-internal.cc
index ee5629b438..597ea7a639 100644
--- a/deps/v8/tools/debug_helper/debug-helper-internal.cc
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.cc
@@ -12,15 +12,14 @@ namespace v8_debug_helper_internal {
bool IsPointerCompressed(uintptr_t address) {
#if COMPRESS_POINTERS_BOOL
- STATIC_ASSERT(i::kPtrComprHeapReservationSize == uintptr_t{1} << 32);
- intptr_t signed_address = static_cast<intptr_t>(address);
- return signed_address >= INT32_MIN && signed_address <= INT32_MAX;
+ return address < i::kPtrComprHeapReservationSize;
#else
return false;
#endif
}
-uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_ptr) {
+uintptr_t EnsureDecompressed(uintptr_t address,
+ uintptr_t any_uncompressed_ptr) {
if (!COMPRESS_POINTERS_BOOL || !IsPointerCompressed(address)) return address;
return i::DecompressTaggedAny(any_uncompressed_ptr,
static_cast<i::Tagged_t>(address));
@@ -55,4 +54,8 @@ void TqObject::Visit(TqObjectVisitor* visitor) const {
visitor->VisitObject(this);
}
+bool TqObject::IsSuperclassOf(const TqObject* other) const {
+ return GetName() != other->GetName();
+}
+
} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.h b/deps/v8/tools/debug_helper/debug-helper-internal.h
index 82506c0941..e2161e25ba 100644
--- a/deps/v8/tools/debug_helper/debug-helper-internal.h
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.h
@@ -10,6 +10,7 @@
#ifndef V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
#define V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
+#include <memory>
#include <string>
#include <vector>
@@ -27,6 +28,7 @@ struct Value {
TValue value;
};
+// Internal version of API class v8::debug_helper::ObjectProperty.
class ObjectProperty {
public:
inline ObjectProperty(std::string name, std::string type,
@@ -68,15 +70,20 @@ struct ObjectPropertiesResultExtended : public d::ObjectPropertiesResult {
ObjectPropertiesResultInternal* base; // Back reference for cleanup
};
+// Internal version of API class v8::debug_helper::ObjectPropertiesResult.
class ObjectPropertiesResult {
public:
- inline ObjectPropertiesResult(
+ ObjectPropertiesResult(d::TypeCheckResult type_check_result,
+ std::string brief, std::string type)
+ : type_check_result_(type_check_result), brief_(brief), type_(type) {}
+ ObjectPropertiesResult(
d::TypeCheckResult type_check_result, std::string brief, std::string type,
- std::vector<std::unique_ptr<ObjectProperty>> properties)
- : type_check_result_(type_check_result),
- brief_(brief),
- type_(type),
- properties_(std::move(properties)) {}
+ std::vector<std::unique_ptr<ObjectProperty>> properties,
+ std::vector<std::string> guessed_types)
+ : ObjectPropertiesResult(type_check_result, brief, type) {
+ properties_ = std::move(properties);
+ guessed_types_ = std::move(guessed_types);
+ }
inline void Prepend(const char* prefix) { brief_ = prefix + brief_; }
@@ -85,11 +92,17 @@ class ObjectPropertiesResult {
public_view_.brief = brief_.c_str();
public_view_.type = type_.c_str();
public_view_.num_properties = properties_.size();
- properties_raw_.resize(0);
+ properties_raw_.clear();
for (const auto& property : properties_) {
properties_raw_.push_back(property->GetPublicView());
}
public_view_.properties = properties_raw_.data();
+ public_view_.num_guessed_types = guessed_types_.size();
+ guessed_types_raw_.clear();
+ for (const auto& guess : guessed_types_) {
+ guessed_types_raw_.push_back(guess.c_str());
+ }
+ public_view_.guessed_types = guessed_types_raw_.data();
public_view_.base = this;
return &public_view_;
}
@@ -99,9 +112,11 @@ class ObjectPropertiesResult {
std::string brief_;
std::string type_;
std::vector<std::unique_ptr<ObjectProperty>> properties_;
+ std::vector<std::string> guessed_types_;
ObjectPropertiesResultExtended public_view_;
std::vector<d::ObjectProperty*> properties_raw_;
+ std::vector<const char*> guessed_types_raw_;
};
class TqObjectVisitor;
@@ -116,13 +131,24 @@ class TqObject {
d::MemoryAccessor accessor) const;
virtual const char* GetName() const;
virtual void Visit(TqObjectVisitor* visitor) const;
+ virtual bool IsSuperclassOf(const TqObject* other) const;
protected:
uintptr_t address_;
};
+// In ptr-compr builds, returns whether the address looks like a compressed
+// pointer (sign-extended from 32 bits). Otherwise returns false because no
+// pointers can be compressed.
bool IsPointerCompressed(uintptr_t address);
-uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_address);
+
+// If the given address looks like a compressed pointer, returns a decompressed
+// representation of it. Otherwise returns the address unmodified.
+uintptr_t EnsureDecompressed(uintptr_t address,
+ uintptr_t any_uncompressed_address);
+
+// Converts the MemoryAccessResult from attempting to read an array's length
+// into the corresponding PropertyKind for the array.
d::PropertyKind GetArrayKind(d::MemoryAccessResult mem_result);
} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/debug-helper.h b/deps/v8/tools/debug_helper/debug-helper.h
index 9bbec76c7c..7d75843bf6 100644
--- a/deps/v8/tools/debug_helper/debug-helper.h
+++ b/deps/v8/tools/debug_helper/debug-helper.h
@@ -46,6 +46,7 @@ enum class TypeCheckResult {
kSmi,
kWeakRef,
kUsedMap,
+ kKnownMapPointer,
kUsedTypeHint,
// Failure cases:
@@ -98,6 +99,16 @@ struct ObjectPropertiesResult {
const char* type; // Runtime type of the object.
size_t num_properties;
ObjectProperty** properties;
+
+ // If not all relevant memory is available, GetObjectProperties may respond
+ // with a technically correct but uninteresting type such as HeapObject, and
+ // use other heuristics to make reasonable guesses about what specific type
+ // the object actually is. You may request data about the same object again
+ // using any of these guesses as the type hint, but the results should be
+ // formatted to the user in a way that clearly indicates that they're only
+ // guesses.
+ size_t num_guessed_types;
+ const char** guessed_types;
};
// Copies byte_count bytes of memory from the given address in the debuggee to
@@ -109,7 +120,7 @@ typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address,
// Additional data that can help GetObjectProperties to be more accurate. Any
// fields you don't know can be set to zero and this library will do the best it
// can with the information available.
-struct Roots {
+struct HeapAddresses {
// Beginning of allocated space for various kinds of data. These can help us
// to detect certain common objects that are placed in memory during startup.
// These values might be provided via name-value pairs in CrashPad dumps.
@@ -119,9 +130,9 @@ struct Roots {
// key stored in v8::internal::Isolate::isolate_key_.
// 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for
// old_space_ and read_only_space_.
- uintptr_t map_space;
- uintptr_t old_space;
- uintptr_t read_only_space;
+ uintptr_t map_space_first_page;
+ uintptr_t old_space_first_page;
+ uintptr_t read_only_space_first_page;
// Any valid heap pointer address. On platforms where pointer compression is
// enabled, this can allow us to get data from compressed pointers even if the
@@ -139,7 +150,8 @@ extern "C" {
V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult*
_v8_debug_helper_GetObjectProperties(
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
- const v8::debug_helper::Roots& heap_roots, const char* type_hint);
+ const v8::debug_helper::HeapAddresses& heap_addresses,
+ const char* type_hint);
V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
v8::debug_helper::ObjectPropertiesResult* result);
}
@@ -159,16 +171,16 @@ using ObjectPropertiesResultPtr =
// Get information about the given object pointer, which could be:
// - A tagged pointer, strong or weak
// - A cleared weak pointer
-// - A compressed tagged pointer, sign-extended to 64 bits
+// - A compressed tagged pointer, zero-extended to 64 bits
// - A tagged small integer
// The type hint is only used if the object's Map is missing or corrupt. It
// should be the fully-qualified name of a class that inherits from
// v8::internal::Object.
inline ObjectPropertiesResultPtr GetObjectProperties(
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
- const Roots& heap_roots, const char* type_hint = nullptr) {
+ const HeapAddresses& heap_addresses, const char* type_hint = nullptr) {
return ObjectPropertiesResultPtr(_v8_debug_helper_GetObjectProperties(
- object, memory_accessor, heap_roots, type_hint));
+ object, memory_accessor, heap_addresses, type_hint));
}
} // namespace debug_helper
diff --git a/deps/v8/tools/debug_helper/gen-heap-constants.py b/deps/v8/tools/debug_helper/gen-heap-constants.py
index 0fd575a994..1d81f2e510 100644
--- a/deps/v8/tools/debug_helper/gen-heap-constants.py
+++ b/deps/v8/tools/debug_helper/gen-heap-constants.py
@@ -16,6 +16,9 @@ out = """
#include <cstdint>
#include <string>
+#include "src/common/ptr-compr-inl.h"
+#include "tools/debug_helper/debug-helper-internal.h"
+
namespace v8_debug_helper_internal {
"""
@@ -51,6 +54,22 @@ def iterate_maps(target_space, camel_space_name):
iterate_maps('map_space', 'MapSpace')
iterate_maps('read_only_space', 'ReadOnlySpace')
+out = out + '\nvoid FillInUnknownHeapAddresses(' + \
+ 'd::HeapAddresses* heap_addresses, uintptr_t any_uncompressed_ptr) {\n'
+if (hasattr(v8heapconst, 'HEAP_FIRST_PAGES')): # Only exists in ptr-compr builds.
+ out = out + ' if (heap_addresses->any_heap_pointer == 0) {\n'
+ out = out + ' heap_addresses->any_heap_pointer = any_uncompressed_ptr;\n'
+ out = out + ' }\n'
+ expected_spaces = set(['map_space', 'read_only_space', 'old_space'])
+ for offset, space_name in v8heapconst.HEAP_FIRST_PAGES.items():
+ if (space_name in expected_spaces):
+ out = out + ' if (heap_addresses->' + space_name + '_first_page == 0) {\n'
+ out = out + ' heap_addresses->' + space_name + \
+ '_first_page = i::DecompressTaggedPointer(any_uncompressed_ptr, ' + \
+ str(offset) + ');\n'
+ out = out + ' }\n'
+out = out + '}\n'
+
out = out + '\n}\n'
try:
diff --git a/deps/v8/tools/debug_helper/get-object-properties.cc b/deps/v8/tools/debug_helper/get-object-properties.cc
index fbe992c40e..8eeeb84093 100644
--- a/deps/v8/tools/debug_helper/get-object-properties.cc
+++ b/deps/v8/tools/debug_helper/get-object-properties.cc
@@ -34,7 +34,7 @@ namespace v8_debug_helper_internal {
V(Foreign, FOREIGN_TYPE) \
V(FreeSpace, FREE_SPACE_TYPE) \
V(HeapNumber, HEAP_NUMBER_TYPE) \
- V(JSArgumentsObject, JS_ARGUMENTS_TYPE) \
+ V(JSArgumentsObject, JS_ARGUMENTS_OBJECT_TYPE) \
V(JSArray, JS_ARRAY_TYPE) \
V(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) \
V(JSArrayIterator, JS_ARRAY_ITERATOR_TYPE) \
@@ -52,8 +52,8 @@ namespace v8_debug_helper_internal {
V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \
V(JSPromise, JS_PROMISE_TYPE) \
V(JSProxy, JS_PROXY_TYPE) \
- V(JSRegExp, JS_REGEXP_TYPE) \
- V(JSRegExpStringIterator, JS_REGEXP_STRING_ITERATOR_TYPE) \
+ V(JSRegExp, JS_REG_EXP_TYPE) \
+ V(JSRegExpStringIterator, JS_REG_EXP_STRING_ITERATOR_TYPE) \
V(JSSet, JS_SET_TYPE) \
V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \
V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \
@@ -71,27 +71,27 @@ namespace v8_debug_helper_internal {
V(PropertyCell, PROPERTY_CELL_TYPE) \
V(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) \
V(Symbol, SYMBOL_TYPE) \
- V(WasmExceptionObject, WASM_EXCEPTION_TYPE) \
- V(WasmGlobalObject, WASM_GLOBAL_TYPE) \
- V(WasmMemoryObject, WASM_MEMORY_TYPE) \
- V(WasmModuleObject, WASM_MODULE_TYPE) \
- V(WasmTableObject, WASM_TABLE_TYPE) \
+ V(WasmExceptionObject, WASM_EXCEPTION_OBJECT_TYPE) \
+ V(WasmGlobalObject, WASM_GLOBAL_OBJECT_TYPE) \
+ V(WasmMemoryObject, WASM_MEMORY_OBJECT_TYPE) \
+ V(WasmModuleObject, WASM_MODULE_OBJECT_TYPE) \
+ V(WasmTableObject, WASM_TABLE_OBJECT_TYPE) \
V(WeakArrayList, WEAK_ARRAY_LIST_TYPE) \
V(WeakCell, WEAK_CELL_TYPE)
#ifdef V8_INTL_SUPPORT
-#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
- TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
- V(JSV8BreakIterator, JS_INTL_V8_BREAK_ITERATOR_TYPE) \
- V(JSCollator, JS_INTL_COLLATOR_TYPE) \
- V(JSDateTimeFormat, JS_INTL_DATE_TIME_FORMAT_TYPE) \
- V(JSListFormat, JS_INTL_LIST_FORMAT_TYPE) \
- V(JSLocale, JS_INTL_LOCALE_TYPE) \
- V(JSNumberFormat, JS_INTL_NUMBER_FORMAT_TYPE) \
- V(JSPluralRules, JS_INTL_PLURAL_RULES_TYPE) \
- V(JSRelativeTimeFormat, JS_INTL_RELATIVE_TIME_FORMAT_TYPE) \
- V(JSSegmentIterator, JS_INTL_SEGMENT_ITERATOR_TYPE) \
- V(JSSegmenter, JS_INTL_SEGMENTER_TYPE)
+#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
+ TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
+ V(JSV8BreakIterator, JS_V8_BREAK_ITERATOR_TYPE) \
+ V(JSCollator, JS_COLLATOR_TYPE) \
+ V(JSDateTimeFormat, JS_DATE_TIME_FORMAT_TYPE) \
+ V(JSListFormat, JS_LIST_FORMAT_TYPE) \
+ V(JSLocale, JS_LOCALE_TYPE) \
+ V(JSNumberFormat, JS_NUMBER_FORMAT_TYPE) \
+ V(JSPluralRules, JS_PLURAL_RULES_TYPE) \
+ V(JSRelativeTimeFormat, JS_RELATIVE_TIME_FORMAT_TYPE) \
+ V(JSSegmentIterator, JS_SEGMENT_ITERATOR_TYPE) \
+ V(JSSegmenter, JS_SEGMENTER_TYPE)
#else
@@ -99,12 +99,14 @@ namespace v8_debug_helper_internal {
#endif // V8_INTL_SUPPORT
+// Used in the static assertion below.
enum class InstanceTypeCheckersSingle {
#define ENUM_VALUE(ClassName, INSTANCE_TYPE) k##ClassName = i::INSTANCE_TYPE,
INSTANCE_TYPE_CHECKERS_SINGLE(ENUM_VALUE)
#undef ENUM_VALUE
};
+// Verify that the instance type list above stays in sync with the truth.
#define CHECK_VALUE(ClassName, INSTANCE_TYPE) \
static_assert( \
static_cast<i::InstanceType>( \
@@ -117,6 +119,9 @@ TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(CHECK_VALUE)
// Adapts one STRUCT_LIST_GENERATOR entry to (Name, NAME) format.
#define STRUCT_INSTANCE_TYPE_ADAPTER(V, NAME, Name, name) V(Name, NAME)
+// Pairs of (ClassName, CLASS_NAME_TYPE) for every instance type that
+// corresponds to a single Torque-defined class. Note that all Struct-derived
+// classes are defined in Torque.
#define TQ_INSTANCE_TYPES_SINGLE(V) \
TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
STRUCT_LIST_GENERATOR(STRUCT_INSTANCE_TYPE_ADAPTER, V)
@@ -147,109 +152,154 @@ struct TypedObject {
TypedObject(d::TypeCheckResult type_check_result,
std::unique_ptr<TqObject> object)
: type_check_result(type_check_result), object(std::move(object)) {}
+
+ // How we discovered the object's type, or why we failed to do so.
d::TypeCheckResult type_check_result;
+
+ // Pointer to some TqObject subclass, representing the most specific known
+ // type for the object.
std::unique_ptr<TqObject> object;
+
+ // Collection of other guesses at more specific types than the one represented
+ // by |object|.
+ std::vector<TypedObject> possible_types;
};
TypedObject GetTypedObjectByHint(uintptr_t address,
std::string type_hint_string) {
-#define TYPE_NAME_CASE(ClassName, ...) \
- if (type_hint_string == "v8::internal::" #ClassName) { \
- return {d::TypeCheckResult::kUsedTypeHint, \
- v8::base::make_unique<Tq##ClassName>(address)}; \
+#define TYPE_NAME_CASE(ClassName, ...) \
+ if (type_hint_string == "v8::internal::" #ClassName) { \
+ return {d::TypeCheckResult::kUsedTypeHint, \
+ std::make_unique<Tq##ClassName>(address)}; \
}
TQ_INSTANCE_TYPES_SINGLE(TYPE_NAME_CASE)
TQ_INSTANCE_TYPES_RANGE(TYPE_NAME_CASE)
+ STRING_CLASS_TYPES(TYPE_NAME_CASE)
#undef TYPE_NAME_CASE
return {d::TypeCheckResult::kUnknownTypeHint,
- v8::base::make_unique<TqHeapObject>(address)};
+ std::make_unique<TqHeapObject>(address)};
}
-TypedObject GetTypedObjectForString(uintptr_t address, i::InstanceType type) {
+TypedObject GetTypedObjectForString(uintptr_t address, i::InstanceType type,
+ d::TypeCheckResult type_source) {
class StringGetDispatcher : public i::AllStatic {
public:
-#define DEFINE_METHOD(ClassName) \
- static inline TypedObject Handle##ClassName(uintptr_t address) { \
- return {d::TypeCheckResult::kUsedMap, \
- v8::base::make_unique<Tq##ClassName>(address)}; \
+#define DEFINE_METHOD(ClassName) \
+ static inline TypedObject Handle##ClassName( \
+ uintptr_t address, d::TypeCheckResult type_source) { \
+ return {type_source, std::make_unique<Tq##ClassName>(address)}; \
}
STRING_CLASS_TYPES(DEFINE_METHOD)
#undef DEFINE_METHOD
- static inline TypedObject HandleInvalidString(uintptr_t address) {
+ static inline TypedObject HandleInvalidString(
+ uintptr_t address, d::TypeCheckResult type_source) {
return {d::TypeCheckResult::kUnknownInstanceType,
- v8::base::make_unique<TqString>(address)};
+ std::make_unique<TqString>(address)};
}
};
return i::StringShape(type)
.DispatchToSpecificTypeWithoutCast<StringGetDispatcher, TypedObject>(
- address);
+ address, type_source);
+}
+
+TypedObject GetTypedObjectByInstanceType(uintptr_t address,
+ i::InstanceType type,
+ d::TypeCheckResult type_source) {
+ switch (type) {
+#define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \
+ case i::INSTANCE_TYPE: \
+ return {type_source, std::make_unique<Tq##ClassName>(address)};
+ TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE)
+#undef INSTANCE_TYPE_CASE
+
+ default:
+
+ // Special case: concrete subtypes of String are not included in the
+ // main instance type list because they use the low bits of the instance
+ // type enum as flags.
+ if (type <= i::LAST_STRING_TYPE) {
+ return GetTypedObjectForString(address, type, type_source);
+ }
+
+#define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \
+ if (type >= i::FIRST_TYPE && type <= i::LAST_TYPE) { \
+ return {type_source, std::make_unique<Tq##ClassName>(address)}; \
+ }
+ TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE)
+#undef INSTANCE_RANGE_CASE
+
+ return {d::TypeCheckResult::kUnknownInstanceType,
+ std::make_unique<TqHeapObject>(address)};
+ }
}
TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
- const char* type_hint) {
- auto heap_object = v8::base::make_unique<TqHeapObject>(address);
+ const char* type_hint,
+ const d::HeapAddresses& heap_addresses) {
+ auto heap_object = std::make_unique<TqHeapObject>(address);
Value<uintptr_t> map_ptr = heap_object->GetMapValue(accessor);
if (map_ptr.validity != d::MemoryAccessResult::kOk) {
+ // If we can't read the Map pointer from the object, then we likely can't
+ // read anything else, so there's not any point in attempting to use the
+ // type hint. Just return a failure.
return {map_ptr.validity == d::MemoryAccessResult::kAddressNotValid
? d::TypeCheckResult::kObjectPointerInvalid
: d::TypeCheckResult::kObjectPointerValidButInaccessible,
std::move(heap_object)};
}
+
Value<i::InstanceType> type =
TqMap(map_ptr.value).GetInstanceTypeValue(accessor);
-
if (type.validity == d::MemoryAccessResult::kOk) {
- // Dispatch to the appropriate method for each instance type. After calling
- // the generated method to fetch properties, we can add custom properties.
- switch (type.value) {
-#define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \
- case i::INSTANCE_TYPE: \
- return {d::TypeCheckResult::kUsedMap, \
- v8::base::make_unique<Tq##ClassName>(address)};
- TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE)
-#undef INSTANCE_TYPE_CASE
-
- default:
+ return GetTypedObjectByInstanceType(address, type.value,
+ d::TypeCheckResult::kUsedMap);
+ }
- // Special case: concrete subtypes of String are not included in the
- // main instance type list because they use the low bits of the instance
- // type enum as flags.
- if (type.value <= i::LAST_STRING_TYPE) {
- return GetTypedObjectForString(address, type.value);
- }
+ // We can't read the Map, so check whether it is in the list of known Maps,
+ // as another way to get its instance type.
+ KnownInstanceType known_map_type =
+ FindKnownMapInstanceType(map_ptr.value, heap_addresses);
+ if (known_map_type.confidence == KnownInstanceType::Confidence::kHigh) {
+ DCHECK_EQ(known_map_type.types.size(), 1);
+ return GetTypedObjectByInstanceType(address, known_map_type.types[0],
+ d::TypeCheckResult::kKnownMapPointer);
+ }
-#define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \
- if (type.value >= i::FIRST_TYPE && type.value <= i::LAST_TYPE) { \
- return {d::TypeCheckResult::kUsedMap, \
- v8::base::make_unique<Tq##ClassName>(address)}; \
+ // Create a basic result that says that the object is a HeapObject and we
+ // couldn't read its Map.
+ TypedObject result = {
+ type.validity == d::MemoryAccessResult::kAddressNotValid
+ ? d::TypeCheckResult::kMapPointerInvalid
+ : d::TypeCheckResult::kMapPointerValidButInaccessible,
+ std::move(heap_object)};
+
+ // If a type hint is available, it may give us something more specific than
+ // HeapObject. However, a type hint of Object would be even less specific, so
+ // we'll only use the type hint if it's a subclass of HeapObject.
+ if (type_hint != nullptr) {
+ TypedObject hint_result = GetTypedObjectByHint(address, type_hint);
+ if (result.object->IsSuperclassOf(hint_result.object.get())) {
+ result = std::move(hint_result);
+ }
}
- TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE)
-#undef INSTANCE_RANGE_CASE
- return {d::TypeCheckResult::kUnknownInstanceType,
- std::move(heap_object)};
- break;
+ // If low-confidence results are available from known Maps, include them only
+ // if they don't contradict the primary type and would provide some additional
+ // specificity.
+ for (const i::InstanceType type_guess : known_map_type.types) {
+ TypedObject guess_result = GetTypedObjectByInstanceType(
+ address, type_guess, d::TypeCheckResult::kKnownMapPointer);
+ if (result.object->IsSuperclassOf(guess_result.object.get())) {
+ result.possible_types.push_back(std::move(guess_result));
}
- } else if (type_hint != nullptr) {
- // Try to use the provided type hint, since the real instance type is
- // unavailable.
- return GetTypedObjectByHint(address, type_hint);
- } else {
- // TODO(v8:9376): Use known maps here. If known map is just a guess (because
- // root pointers weren't provided), then create a synthetic property with
- // the more specific type. Then the caller could presumably ask us again
- // with the type hint we provided. Otherwise, just go ahead and use it to
- // generate properties.
- return {type.validity == d::MemoryAccessResult::kAddressNotValid
- ? d::TypeCheckResult::kMapPointerInvalid
- : d::TypeCheckResult::kMapPointerValidButInaccessible,
- std::move(heap_object)};
}
+
+ return result;
}
#undef STRUCT_INSTANCE_TYPE_ADAPTER
@@ -261,8 +311,13 @@ TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
// An object visitor that accumulates the first few characters of a string.
class ReadStringVisitor : public TqObjectVisitor {
public:
- ReadStringVisitor(d::MemoryAccessor accessor)
- : accessor_(accessor), index_(0), limit_(INT32_MAX), done_(false) {}
+ ReadStringVisitor(d::MemoryAccessor accessor,
+ const d::HeapAddresses& heap_addresses)
+ : accessor_(accessor),
+ heap_addresses_(heap_addresses),
+ index_(0),
+ limit_(INT32_MAX),
+ done_(false) {}
// Returns the result as UTF-8 once visiting is complete.
std::string GetString() {
@@ -301,7 +356,9 @@ class ReadStringVisitor : public TqObjectVisitor {
void VisitConsString(const TqConsString* object) override {
uintptr_t first_address = GetOrFinish(object->GetFirstValue(accessor_));
if (done_) return;
- auto first = GetTypedHeapObject(first_address, accessor_, nullptr).object;
+ auto first =
+ GetTypedHeapObject(first_address, accessor_, nullptr, heap_addresses_)
+ .object;
first->Visit(this);
if (done_) return;
int32_t first_length = GetOrFinish(
@@ -309,7 +366,8 @@ class ReadStringVisitor : public TqObjectVisitor {
uintptr_t second = GetOrFinish(object->GetSecondValue(accessor_));
if (done_) return;
IndexModifier modifier(this, -first_length, -first_length);
- GetTypedHeapObject(second, accessor_, nullptr).object->Visit(this);
+ GetTypedHeapObject(second, accessor_, nullptr, heap_addresses_)
+ .object->Visit(this);
}
void VisitSlicedString(const TqSlicedString* object) override {
@@ -320,13 +378,15 @@ class ReadStringVisitor : public TqObjectVisitor {
if (done_) return;
int32_t limit_adjust = offset + length - limit_;
IndexModifier modifier(this, offset, limit_adjust < 0 ? limit_adjust : 0);
- GetTypedHeapObject(parent, accessor_, nullptr).object->Visit(this);
+ GetTypedHeapObject(parent, accessor_, nullptr, heap_addresses_)
+ .object->Visit(this);
}
void VisitThinString(const TqThinString* object) override {
uintptr_t actual = GetOrFinish(object->GetActualValue(accessor_));
if (done_) return;
- GetTypedHeapObject(actual, accessor_, nullptr).object->Visit(this);
+ GetTypedHeapObject(actual, accessor_, nullptr, heap_addresses_)
+ .object->Visit(this);
}
void VisitExternalString(const TqExternalString* object) override {
@@ -398,6 +458,7 @@ class ReadStringVisitor : public TqObjectVisitor {
std::u16string string_; // Result string.
d::MemoryAccessor accessor_;
+ const d::HeapAddresses& heap_addresses_;
int32_t index_; // Index of next char to read.
int32_t limit_; // Don't read past this index (set by SlicedString).
bool done_; // Whether to stop further work.
@@ -406,14 +467,15 @@ class ReadStringVisitor : public TqObjectVisitor {
// An object visitor that adds extra debugging information for some types.
class AddInfoVisitor : public TqObjectVisitor {
public:
- AddInfoVisitor(const std::string& brief, d::MemoryAccessor accessor)
- : accessor_(accessor), brief_(brief) {}
+ AddInfoVisitor(const std::string& brief, d::MemoryAccessor accessor,
+ const d::HeapAddresses& heap_addresses)
+ : accessor_(accessor), brief_(brief), heap_addresses_(heap_addresses) {}
// Returns the brief object description, once visiting is complete.
const std::string& GetBrief() { return brief_; }
void VisitString(const TqString* object) override {
- ReadStringVisitor visitor(accessor_);
+ ReadStringVisitor visitor(accessor_, heap_addresses_);
object->Visit(&visitor);
if (!brief_.empty()) brief_ += " ";
brief_ += "\"" + visitor.GetString() + "\"";
@@ -422,12 +484,18 @@ class AddInfoVisitor : public TqObjectVisitor {
private:
d::MemoryAccessor accessor_;
std::string brief_;
+ const d::HeapAddresses& heap_addresses_;
};
-std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectPropertiesNotCompressed(
uintptr_t address, d::MemoryAccessor accessor, const char* type_hint,
- std::string brief) {
- TypedObject typed = GetTypedHeapObject(address, accessor, type_hint);
+ const d::HeapAddresses& heap_addresses) {
+ // Regardless of whether we can read the object itself, maybe we can find its
+ // pointer in the list of known objects.
+ std::string brief = FindKnownObject(address, heap_addresses);
+
+ TypedObject typed =
+ GetTypedHeapObject(address, accessor, type_hint, heap_addresses);
// TODO(v8:9376): Many object types need additional data that is not included
// in their Torque layout definitions. For example, JSObject has an array of
@@ -435,59 +503,62 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
// should be represented as an array in this response. If the relevant memory
// is available, we should instead represent those properties (and any out-of-
// object properties) using their JavaScript property names.
- AddInfoVisitor visitor(brief, accessor);
+ AddInfoVisitor visitor(brief, accessor, heap_addresses);
typed.object->Visit(&visitor);
brief = visitor.GetBrief();
brief = AppendAddressAndType(brief, address, typed.object->GetName());
- return v8::base::make_unique<ObjectPropertiesResult>(
+ // Convert the low-confidence guessed types to a list of strings as expected
+ // for the response.
+ std::vector<std::string> guessed_types;
+ for (const auto& guess : typed.possible_types) {
+ guessed_types.push_back(guess.object->GetName());
+ }
+
+ return std::make_unique<ObjectPropertiesResult>(
typed.type_check_result, brief, typed.object->GetName(),
- typed.object->GetProperties(accessor));
+ typed.object->GetProperties(accessor), std::move(guessed_types));
}
-std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
- uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
- const char* type_hint) {
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectPropertiesMaybeCompressed(
+ uintptr_t address, d::MemoryAccessor memory_accessor,
+ d::HeapAddresses heap_addresses, const char* type_hint) {
// Try to figure out the heap range, for pointer compression (this is unused
// if pointer compression is disabled).
uintptr_t any_uncompressed_ptr = 0;
if (!IsPointerCompressed(address)) any_uncompressed_ptr = address;
- if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.any_heap_pointer;
- if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.map_space;
- if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.old_space;
- if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.read_only_space;
+ if (any_uncompressed_ptr == 0)
+ any_uncompressed_ptr = heap_addresses.any_heap_pointer;
+ if (any_uncompressed_ptr == 0)
+ any_uncompressed_ptr = heap_addresses.map_space_first_page;
+ if (any_uncompressed_ptr == 0)
+ any_uncompressed_ptr = heap_addresses.old_space_first_page;
+ if (any_uncompressed_ptr == 0)
+ any_uncompressed_ptr = heap_addresses.read_only_space_first_page;
+ FillInUnknownHeapAddresses(&heap_addresses, any_uncompressed_ptr);
if (any_uncompressed_ptr == 0) {
// We can't figure out the heap range. Just check for known objects.
- std::string brief = FindKnownObject(address, roots);
+ std::string brief = FindKnownObject(address, heap_addresses);
brief = AppendAddressAndType(brief, address, "v8::internal::TaggedValue");
- return v8::base::make_unique<ObjectPropertiesResult>(
+ return std::make_unique<ObjectPropertiesResult>(
d::TypeCheckResult::kUnableToDecompress, brief,
- "v8::internal::TaggedValue",
- std::vector<std::unique_ptr<ObjectProperty>>());
+ "v8::internal::TaggedValue");
}
- // TODO(v8:9376): It seems that the space roots are at predictable offsets
- // within the heap reservation block when pointer compression is enabled, so
- // we should be able to set those here.
-
- address = Decompress(address, any_uncompressed_ptr);
- // From here on all addresses should be decompressed.
+ address = EnsureDecompressed(address, any_uncompressed_ptr);
- // Regardless of whether we can read the object itself, maybe we can find its
- // pointer in the list of known objects.
- std::string brief = FindKnownObject(address, roots);
- return GetHeapObjectProperties(address, memory_accessor, type_hint, brief);
+ return GetHeapObjectPropertiesNotCompressed(address, memory_accessor,
+ type_hint, heap_addresses);
}
-std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
- uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
- const char* type_hint) {
- std::vector<std::unique_ptr<ObjectProperty>> props;
+std::unique_ptr<ObjectPropertiesResult> GetObjectProperties(
+ uintptr_t address, d::MemoryAccessor memory_accessor,
+ const d::HeapAddresses& heap_addresses, const char* type_hint) {
if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) {
- return v8::base::make_unique<ObjectPropertiesResult>(
+ return std::make_unique<ObjectPropertiesResult>(
d::TypeCheckResult::kWeakRef, "cleared weak ref",
- "v8::internal::HeapObject", std::move(props));
+ "v8::internal::HeapObject");
}
bool is_weak = (address & i::kHeapObjectTagMask) == i::kWeakHeapObjectTag;
if (is_weak) {
@@ -495,7 +566,8 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
}
if (i::Internals::HasHeapObjectTag(address)) {
std::unique_ptr<ObjectPropertiesResult> result =
- GetHeapObjectProperties(address, memory_accessor, roots, type_hint);
+ GetHeapObjectPropertiesMaybeCompressed(address, memory_accessor,
+ heap_addresses, type_hint);
if (is_weak) {
result->Prepend("weak ref to ");
}
@@ -507,9 +579,8 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
int32_t value = i::PlatformSmiTagging::SmiToInt(address);
std::stringstream stream;
stream << value << " (0x" << std::hex << value << ")";
- return v8::base::make_unique<ObjectPropertiesResult>(
- d::TypeCheckResult::kSmi, stream.str(), "v8::internal::Smi",
- std::move(props));
+ return std::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kSmi, stream.str(), "v8::internal::Smi");
}
} // namespace v8_debug_helper_internal
@@ -520,10 +591,10 @@ extern "C" {
V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult*
_v8_debug_helper_GetObjectProperties(uintptr_t object,
d::MemoryAccessor memory_accessor,
- const d::Roots& heap_roots,
+ const d::HeapAddresses& heap_addresses,
const char* type_hint) {
- return di::GetObjectPropertiesImpl(object, memory_accessor, heap_roots,
- type_hint)
+ return di::GetObjectProperties(object, memory_accessor, heap_addresses,
+ type_hint)
.release()
->GetPublicView();
}
diff --git a/deps/v8/tools/debug_helper/heap-constants.cc b/deps/v8/tools/debug_helper/heap-constants.cc
index 2bd0420690..9b9ed04cc1 100644
--- a/deps/v8/tools/debug_helper/heap-constants.cc
+++ b/deps/v8/tools/debug_helper/heap-constants.cc
@@ -9,36 +9,37 @@ namespace d = v8::debug_helper;
namespace v8_debug_helper_internal {
-std::string FindKnownObject(uintptr_t address, const d::Roots& roots) {
+std::string FindKnownObject(uintptr_t address,
+ const d::HeapAddresses& heap_addresses) {
uintptr_t containing_page = address & ~i::kPageAlignmentMask;
uintptr_t offset_in_page = address & i::kPageAlignmentMask;
- // If there's a match with a known root, then search only that page.
- if (containing_page == roots.map_space) {
+ // If there's a match with a known page, then search only that page.
+ if (containing_page == heap_addresses.map_space_first_page) {
return FindKnownObjectInMapSpace(offset_in_page);
}
- if (containing_page == roots.old_space) {
+ if (containing_page == heap_addresses.old_space_first_page) {
return FindKnownObjectInOldSpace(offset_in_page);
}
- if (containing_page == roots.read_only_space) {
+ if (containing_page == heap_addresses.read_only_space_first_page) {
return FindKnownObjectInReadOnlySpace(offset_in_page);
}
- // For any unknown roots, compile a list of things this object might be.
+ // For any unknown pages, compile a list of things this object might be.
std::string result;
- if (roots.map_space == 0) {
+ if (heap_addresses.map_space_first_page == 0) {
std::string sub_result = FindKnownObjectInMapSpace(offset_in_page);
if (!sub_result.empty()) {
result += "maybe " + sub_result;
}
}
- if (roots.old_space == 0) {
+ if (heap_addresses.old_space_first_page == 0) {
std::string sub_result = FindKnownObjectInOldSpace(offset_in_page);
if (!sub_result.empty()) {
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
}
}
- if (roots.read_only_space == 0) {
+ if (heap_addresses.read_only_space_first_page == 0) {
std::string sub_result = FindKnownObjectInReadOnlySpace(offset_in_page);
if (!sub_result.empty()) {
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
@@ -48,4 +49,37 @@ std::string FindKnownObject(uintptr_t address, const d::Roots& roots) {
return result;
}
+KnownInstanceType FindKnownMapInstanceType(
+ uintptr_t address, const d::HeapAddresses& heap_addresses) {
+ uintptr_t containing_page = address & ~i::kPageAlignmentMask;
+ uintptr_t offset_in_page = address & i::kPageAlignmentMask;
+
+ // If there's a match with a known page, then search only that page.
+ if (containing_page == heap_addresses.map_space_first_page) {
+ return KnownInstanceType(
+ FindKnownMapInstanceTypeInMapSpace(offset_in_page));
+ }
+ if (containing_page == heap_addresses.read_only_space_first_page) {
+ return KnownInstanceType(
+ FindKnownMapInstanceTypeInReadOnlySpace(offset_in_page));
+ }
+
+ // For any unknown pages, compile a list of things this object might be.
+ KnownInstanceType result;
+ if (heap_addresses.map_space_first_page == 0) {
+ int sub_result = FindKnownMapInstanceTypeInMapSpace(offset_in_page);
+ if (sub_result >= 0) {
+ result.types.push_back(static_cast<i::InstanceType>(sub_result));
+ }
+ }
+ if (heap_addresses.read_only_space_first_page == 0) {
+ int sub_result = FindKnownMapInstanceTypeInReadOnlySpace(offset_in_page);
+ if (sub_result >= 0) {
+ result.types.push_back(static_cast<i::InstanceType>(sub_result));
+ }
+ }
+
+ return result;
+}
+
} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/heap-constants.h b/deps/v8/tools/debug_helper/heap-constants.h
index f3149bbb47..6c1f17dc82 100644
--- a/deps/v8/tools/debug_helper/heap-constants.h
+++ b/deps/v8/tools/debug_helper/heap-constants.h
@@ -7,21 +7,60 @@
#include <cstdint>
#include <string>
+#include <vector>
#include "debug-helper.h"
+#include "src/objects/instance-type.h"
namespace d = v8::debug_helper;
namespace v8_debug_helper_internal {
-// Functions generated by mkgrokdump:
+// ===== Functions generated by gen-heap-constants.py: =========================
+
+// Returns the name of a known object, given its offset within the first page of
+// the space, or empty string on failure.
std::string FindKnownObjectInOldSpace(uintptr_t offset);
std::string FindKnownObjectInReadOnlySpace(uintptr_t offset);
std::string FindKnownObjectInMapSpace(uintptr_t offset);
-std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
-std::string FindKnownMapInstanceTypeInReadOnlySpace(uintptr_t offset);
-std::string FindKnownObject(uintptr_t address, const d::Roots& roots);
+// In builds with pointer compression enabled, sets the *_first_page members in
+// the HeapAddresses object. In other builds, does nothing.
+void FillInUnknownHeapAddresses(d::HeapAddresses* heap_addresses,
+ uintptr_t any_uncompressed_ptr);
+
+// Returns the instance type for the known Map, given its offset within the
+// first page of the space, or empty string on failure.
+int FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
+int FindKnownMapInstanceTypeInReadOnlySpace(uintptr_t offset);
+
+// ===== End of generated functions. ===========================================
+
+// Returns a descriptive string if the given address matches a known object, or
+// an empty string otherwise.
+std::string FindKnownObject(uintptr_t address,
+ const d::HeapAddresses& heap_addresses);
+
+struct KnownInstanceType {
+ enum class Confidence {
+ kLow,
+ kHigh,
+ };
+ KnownInstanceType() : confidence(Confidence::kLow) {}
+ KnownInstanceType(int type) : KnownInstanceType() {
+ if (type >= 0) {
+ confidence = Confidence::kHigh;
+ types.push_back(static_cast<v8::internal::InstanceType>(type));
+ }
+ }
+ Confidence confidence;
+ std::vector<v8::internal::InstanceType> types;
+};
+
+// Returns information about the instance type of the Map at the given address,
+// based on the list of known Maps.
+KnownInstanceType FindKnownMapInstanceType(
+ uintptr_t address, const d::HeapAddresses& heap_addresses);
} // namespace v8_debug_helper_internal